Source: dist/es/mapray.js

var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

function createCommonjsModule(fn, module) {
	return module = { exports: {} }, fn(module, module.exports), module.exports;
}

var check = function (it) {
  return it && it.Math == Math && it;
}; // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028


var global_1 = // eslint-disable-next-line no-undef
check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || check(typeof self == 'object' && self) || check(typeof commonjsGlobal == 'object' && commonjsGlobal) || // eslint-disable-next-line no-new-func
Function('return this')();

var fails = function (exec) {
  try {
    return !!exec();
  } catch (error) {
    return true;
  }
};

var descriptors = !fails(function () {
  return Object.defineProperty({}, 1, {
    get: function () {
      return 7;
    }
  })[1] != 7;
});

var isObject = function (it) {
  return typeof it === 'object' ? it !== null : typeof it === 'function';
};

var document$1 = global_1.document; // typeof document.createElement is 'object' in old IE

var EXISTS = isObject(document$1) && isObject(document$1.createElement);

var documentCreateElement = function (it) {
  return EXISTS ? document$1.createElement(it) : {};
};

var ie8DomDefine = !descriptors && !fails(function () {
  return Object.defineProperty(documentCreateElement('div'), 'a', {
    get: function () {
      return 7;
    }
  }).a != 7;
});

var anObject = function (it) {
  if (!isObject(it)) {
    throw TypeError(String(it) + ' is not an object');
  }

  return it;
};

// https://tc39.github.io/ecma262/#sec-toprimitive
// instead of the ES6 spec version, we didn't implement @@toPrimitive case
// and the second argument - flag - preferred type is a string

var toPrimitive = function (input, PREFERRED_STRING) {
  if (!isObject(input)) return input;
  var fn, val;
  if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
  if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
  if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
  throw TypeError("Can't convert object to primitive value");
};

var nativeDefineProperty = Object.defineProperty; // `Object.defineProperty` method
// https://tc39.github.io/ecma262/#sec-object.defineproperty

var f = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
  anObject(O);
  P = toPrimitive(P, true);
  anObject(Attributes);
  if (ie8DomDefine) try {
    return nativeDefineProperty(O, P, Attributes);
  } catch (error) {
    /* empty */
  }
  if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
  if ('value' in Attributes) O[P] = Attributes.value;
  return O;
};
var objectDefineProperty = {
  f: f
};

var createPropertyDescriptor = function (bitmap, value) {
  return {
    enumerable: !(bitmap & 1),
    configurable: !(bitmap & 2),
    writable: !(bitmap & 4),
    value: value
  };
};

var createNonEnumerableProperty = descriptors ? function (object, key, value) {
  return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
} : function (object, key, value) {
  object[key] = value;
  return object;
};

var hasOwnProperty = {}.hasOwnProperty;

var has = function (it, key) {
  return hasOwnProperty.call(it, key);
};

var setGlobal = function (key, value) {
  try {
    createNonEnumerableProperty(global_1, key, value);
  } catch (error) {
    global_1[key] = value;
  }

  return value;
};

var SHARED = '__core-js_shared__';
var store = global_1[SHARED] || setGlobal(SHARED, {});
var sharedStore = store;

var functionToString = Function.toString; // this helper broken in `3.4.1-3.4.4`, so we can't use `shared` helper

if (typeof sharedStore.inspectSource != 'function') {
  sharedStore.inspectSource = function (it) {
    return functionToString.call(it);
  };
}

var inspectSource = sharedStore.inspectSource;

var WeakMap = global_1.WeakMap;
var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(inspectSource(WeakMap));

var isPure = false;

var shared = createCommonjsModule(function (module) {
  (module.exports = function (key, value) {
    return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
  })('versions', []).push({
    version: '3.6.4',
    mode:  'global',
    copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
  });
});

var id = 0;
var postfix = Math.random();

var uid = function (key) {
  return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
};

var keys = shared('keys');

var sharedKey = function (key) {
  return keys[key] || (keys[key] = uid(key));
};

var hiddenKeys = {};

var WeakMap$1 = global_1.WeakMap;
var set, get, has$1;

var enforce = function (it) {
  return has$1(it) ? get(it) : set(it, {});
};

var getterFor = function (TYPE) {
  return function (it) {
    var state;

    if (!isObject(it) || (state = get(it)).type !== TYPE) {
      throw TypeError('Incompatible receiver, ' + TYPE + ' required');
    }

    return state;
  };
};

if (nativeWeakMap) {
  var store$1 = new WeakMap$1();
  var wmget = store$1.get;
  var wmhas = store$1.has;
  var wmset = store$1.set;

  set = function (it, metadata) {
    wmset.call(store$1, it, metadata);
    return metadata;
  };

  get = function (it) {
    return wmget.call(store$1, it) || {};
  };

  has$1 = function (it) {
    return wmhas.call(store$1, it);
  };
} else {
  var STATE = sharedKey('state');
  hiddenKeys[STATE] = true;

  set = function (it, metadata) {
    createNonEnumerableProperty(it, STATE, metadata);
    return metadata;
  };

  get = function (it) {
    return has(it, STATE) ? it[STATE] : {};
  };

  has$1 = function (it) {
    return has(it, STATE);
  };
}

var internalState = {
  set: set,
  get: get,
  has: has$1,
  enforce: enforce,
  getterFor: getterFor
};

var redefine = createCommonjsModule(function (module) {
  var getInternalState = internalState.get;
  var enforceInternalState = internalState.enforce;
  var TEMPLATE = String(String).split('String');
  (module.exports = function (O, key, value, options) {
    var unsafe = options ? !!options.unsafe : false;
    var simple = options ? !!options.enumerable : false;
    var noTargetGet = options ? !!options.noTargetGet : false;

    if (typeof value == 'function') {
      if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key);
      enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
    }

    if (O === global_1) {
      if (simple) O[key] = value;else setGlobal(key, value);
      return;
    } else if (!unsafe) {
      delete O[key];
    } else if (!noTargetGet && O[key]) {
      simple = true;
    }

    if (simple) O[key] = value;else createNonEnumerableProperty(O, key, value); // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
  })(Function.prototype, 'toString', function toString() {
    return typeof this == 'function' && getInternalState(this).source || inspectSource(this);
  });
});

var DatePrototype = Date.prototype;
var INVALID_DATE = 'Invalid Date';
var TO_STRING = 'toString';
var nativeDateToString = DatePrototype[TO_STRING];
var getTime = DatePrototype.getTime; // `Date.prototype.toString` method
// https://tc39.github.io/ecma262/#sec-date.prototype.tostring

if (new Date(NaN) + '' != INVALID_DATE) {
  redefine(DatePrototype, TO_STRING, function toString() {
    var value = getTime.call(this); // eslint-disable-next-line no-self-compare

    return value === value ? nativeDateToString.call(this) : INVALID_DATE;
  });
}

var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; // Nashorn ~ JDK8 bug

var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({
  1: 2
}, 1); // `Object.prototype.propertyIsEnumerable` method implementation
// https://tc39.github.io/ecma262/#sec-object.prototype.propertyisenumerable

var f$1 = NASHORN_BUG ? function propertyIsEnumerable(V) {
  var descriptor = getOwnPropertyDescriptor(this, V);
  return !!descriptor && descriptor.enumerable;
} : nativePropertyIsEnumerable;
var objectPropertyIsEnumerable = {
  f: f$1
};

var toString = {}.toString;

var classofRaw = function (it) {
  return toString.call(it).slice(8, -1);
};

var split = ''.split; // fallback for non-array-like ES3 and non-enumerable old V8 strings

var indexedObject = fails(function () {
  // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
  // eslint-disable-next-line no-prototype-builtins
  return !Object('z').propertyIsEnumerable(0);
}) ? function (it) {
  return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
} : Object;

// `RequireObjectCoercible` abstract operation
// https://tc39.github.io/ecma262/#sec-requireobjectcoercible
var requireObjectCoercible = function (it) {
  if (it == undefined) throw TypeError("Can't call method on " + it);
  return it;
};

var toIndexedObject = function (it) {
  return indexedObject(requireObjectCoercible(it));
};

var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; // `Object.getOwnPropertyDescriptor` method
// https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor

var f$2 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
  O = toIndexedObject(O);
  P = toPrimitive(P, true);
  if (ie8DomDefine) try {
    return nativeGetOwnPropertyDescriptor(O, P);
  } catch (error) {
    /* empty */
  }
  if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
};
var objectGetOwnPropertyDescriptor = {
  f: f$2
};

var path = global_1;

var aFunction = function (variable) {
  return typeof variable == 'function' ? variable : undefined;
};

var getBuiltIn = function (namespace, method) {
  return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace]) : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
};

var ceil = Math.ceil;
var floor = Math.floor; // `ToInteger` abstract operation
// https://tc39.github.io/ecma262/#sec-tointeger

var toInteger = function (argument) {
  return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
};

var min = Math.min; // `ToLength` abstract operation
// https://tc39.github.io/ecma262/#sec-tolength

var toLength = function (argument) {
  return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
};

var max = Math.max;
var min$1 = Math.min; // Helper for a popular repeating case of the spec:
// Let integer be ? ToInteger(index).
// If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).

var toAbsoluteIndex = function (index, length) {
  var integer = toInteger(index);
  return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
};

var createMethod = function (IS_INCLUDES) {
  return function ($this, el, fromIndex) {
    var O = toIndexedObject($this);
    var length = toLength(O.length);
    var index = toAbsoluteIndex(fromIndex, length);
    var value; // Array#includes uses SameValueZero equality algorithm
    // eslint-disable-next-line no-self-compare

    if (IS_INCLUDES && el != el) while (length > index) {
      value = O[index++]; // eslint-disable-next-line no-self-compare

      if (value != value) return true; // Array#indexOf ignores holes, Array#includes - not
    } else for (; length > index; index++) {
      if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
    }
    return !IS_INCLUDES && -1;
  };
};

var arrayIncludes = {
  // `Array.prototype.includes` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.includes
  includes: createMethod(true),
  // `Array.prototype.indexOf` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.indexof
  indexOf: createMethod(false)
};

var indexOf = arrayIncludes.indexOf;

var objectKeysInternal = function (object, names) {
  var O = toIndexedObject(object);
  var i = 0;
  var result = [];
  var key;

  for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key); // Don't enum bug & hidden keys


  while (names.length > i) if (has(O, key = names[i++])) {
    ~indexOf(result, key) || result.push(key);
  }

  return result;
};

// IE8- don't enum bug keys
var enumBugKeys = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];

var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype'); // `Object.getOwnPropertyNames` method
// https://tc39.github.io/ecma262/#sec-object.getownpropertynames

var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
  return objectKeysInternal(O, hiddenKeys$1);
};

var objectGetOwnPropertyNames = {
  f: f$3
};

var f$4 = Object.getOwnPropertySymbols;
var objectGetOwnPropertySymbols = {
  f: f$4
};

var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
  var keys = objectGetOwnPropertyNames.f(anObject(it));
  var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
  return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
};

var copyConstructorProperties = function (target, source) {
  var keys = ownKeys(source);
  var defineProperty = objectDefineProperty.f;
  var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;

  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
  }
};

var replacement = /#|\.prototype\./;

var isForced = function (feature, detection) {
  var value = data[normalize(feature)];
  return value == POLYFILL ? true : value == NATIVE ? false : typeof detection == 'function' ? fails(detection) : !!detection;
};

var normalize = isForced.normalize = function (string) {
  return String(string).replace(replacement, '.').toLowerCase();
};

var data = isForced.data = {};
var NATIVE = isForced.NATIVE = 'N';
var POLYFILL = isForced.POLYFILL = 'P';
var isForced_1 = isForced;

var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
/*
  options.target      - name of the target object
  options.global      - target is the global object
  options.stat        - export as static methods of target
  options.proto       - export as prototype methods of target
  options.real        - real prototype method for the `pure` version
  options.forced      - export even if the native feature is available
  options.bind        - bind methods to the target, required for the `pure` version
  options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
  options.unsafe      - use the simple assignment of property instead of delete + defineProperty
  options.sham        - add a flag to not completely full polyfills
  options.enumerable  - export as enumerable property
  options.noTargetGet - prevent calling a getter on target
*/

var _export = function (options, source) {
  var TARGET = options.target;
  var GLOBAL = options.global;
  var STATIC = options.stat;
  var FORCED, target, key, targetProperty, sourceProperty, descriptor;

  if (GLOBAL) {
    target = global_1;
  } else if (STATIC) {
    target = global_1[TARGET] || setGlobal(TARGET, {});
  } else {
    target = (global_1[TARGET] || {}).prototype;
  }

  if (target) for (key in source) {
    sourceProperty = source[key];

    if (options.noTargetGet) {
      descriptor = getOwnPropertyDescriptor$1(target, key);
      targetProperty = descriptor && descriptor.value;
    } else targetProperty = target[key];

    FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); // contained in target

    if (!FORCED && targetProperty !== undefined) {
      if (typeof sourceProperty === typeof targetProperty) continue;
      copyConstructorProperties(sourceProperty, targetProperty);
    } // add a flag to not completely full polyfills


    if (options.sham || targetProperty && targetProperty.sham) {
      createNonEnumerableProperty(sourceProperty, 'sham', true);
    } // extend global


    redefine(target, key, sourceProperty, options);
  }
};

var log = Math.log;
var LN2 = Math.LN2; // `Math.log2` method
// https://tc39.github.io/ecma262/#sec-math.log2

_export({
  target: 'Math',
  stat: true
}, {
  log2: function log2(x) {
    return log(x) / LN2;
  }
});

var defineProperty = objectDefineProperty.f;
var FunctionPrototype = Function.prototype;
var FunctionPrototypeToString = FunctionPrototype.toString;
var nameRE = /^\s*function ([^ (]*)/;
var NAME = 'name'; // Function instances `.name` property
// https://tc39.github.io/ecma262/#sec-function-instances-name

if (descriptors && !(NAME in FunctionPrototype)) {
  defineProperty(FunctionPrototype, NAME, {
    configurable: true,
    get: function () {
      try {
        return FunctionPrototypeToString.call(this).match(nameRE)[1];
      } catch (error) {
        return '';
      }
    }
  });
}

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

function _defineProperties(target, props) {
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ("value" in descriptor) descriptor.writable = true;
    Object.defineProperty(target, descriptor.key, descriptor);
  }
}

function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  return Constructor;
}

function _inherits(subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function");
  }

  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      writable: true,
      configurable: true
    }
  });
  if (superClass) _setPrototypeOf(subClass, superClass);
}

function _getPrototypeOf(o) {
  _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
    return o.__proto__ || Object.getPrototypeOf(o);
  };
  return _getPrototypeOf(o);
}

function _setPrototypeOf(o, p) {
  _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
    o.__proto__ = p;
    return o;
  };

  return _setPrototypeOf(o, p);
}

function isNativeReflectConstruct() {
  if (typeof Reflect === "undefined" || !Reflect.construct) return false;
  if (Reflect.construct.sham) return false;
  if (typeof Proxy === "function") return true;

  try {
    Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
    return true;
  } catch (e) {
    return false;
  }
}

function _construct(Parent, args, Class) {
  if (isNativeReflectConstruct()) {
    _construct = Reflect.construct;
  } else {
    _construct = function _construct(Parent, args, Class) {
      var a = [null];
      a.push.apply(a, args);
      var Constructor = Function.bind.apply(Parent, a);
      var instance = new Constructor();
      if (Class) _setPrototypeOf(instance, Class.prototype);
      return instance;
    };
  }

  return _construct.apply(null, arguments);
}

function _isNativeFunction(fn) {
  return Function.toString.call(fn).indexOf("[native code]") !== -1;
}

function _wrapNativeSuper(Class) {
  var _cache = typeof Map === "function" ? new Map() : undefined;

  _wrapNativeSuper = function _wrapNativeSuper(Class) {
    if (Class === null || !_isNativeFunction(Class)) return Class;

    if (typeof Class !== "function") {
      throw new TypeError("Super expression must either be null or a function");
    }

    if (typeof _cache !== "undefined") {
      if (_cache.has(Class)) return _cache.get(Class);

      _cache.set(Class, Wrapper);
    }

    function Wrapper() {
      return _construct(Class, arguments, _getPrototypeOf(this).constructor);
    }

    Wrapper.prototype = Object.create(Class.prototype, {
      constructor: {
        value: Wrapper,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
    return _setPrototypeOf(Wrapper, Class);
  };

  return _wrapNativeSuper(Class);
}

function _assertThisInitialized(self) {
  if (self === void 0) {
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  }

  return self;
}

function _possibleConstructorReturn(self, call) {
  if (call && (typeof call === "object" || typeof call === "function")) {
    return call;
  }

  return _assertThisInitialized(self);
}

function _slicedToArray(arr, i) {
  return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
}

function _toConsumableArray(arr) {
  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}

function _arrayWithoutHoles(arr) {
  if (Array.isArray(arr)) {
    for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];

    return arr2;
  }
}

function _arrayWithHoles(arr) {
  if (Array.isArray(arr)) return arr;
}

function _iterableToArray(iter) {
  if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}

function _iterableToArrayLimit(arr, i) {
  if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
    return;
  }

  var _arr = [];
  var _n = true;
  var _d = false;
  var _e = undefined;

  try {
    for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
      _arr.push(_s.value);

      if (i && _arr.length === i) break;
    }
  } catch (err) {
    _d = true;
    _e = err;
  } finally {
    try {
      if (!_n && _i["return"] != null) _i["return"]();
    } finally {
      if (_d) throw _e;
    }
  }

  return _arr;
}

function _nonIterableSpread() {
  throw new TypeError("Invalid attempt to spread non-iterable instance");
}

function _nonIterableRest() {
  throw new TypeError("Invalid attempt to destructure non-iterable instance");
}

/**
 * @summary アニメーション共通のエラー
 *
 * @memberof mapray.animation
 * @extends Error
 *
 * @see {@link mapray.animation.Binder}
 */
var AnimationError =
/*#__PURE__*/
function (_Error) {
  _inherits(AnimationError, _Error);

  /**
   * @param {string} message  エラーの説明
   */
  function AnimationError(message) {
    var _this;

    _classCallCheck(this, AnimationError);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(AnimationError).call(this, message));
    _this.name = "mapray.animation.AnimationError";
    return _this;
  }

  return AnimationError;
}(_wrapNativeSuper(Error));

var aPossiblePrototype = function (it) {
  if (!isObject(it) && it !== null) {
    throw TypeError("Can't set " + String(it) + ' as a prototype');
  }

  return it;
};

// https://tc39.github.io/ecma262/#sec-object.setprototypeof
// Works with __proto__ only. Old v8 can't work with null proto objects.

/* eslint-disable no-proto */

var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
  var CORRECT_SETTER = false;
  var test = {};
  var setter;

  try {
    setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
    setter.call(test, []);
    CORRECT_SETTER = test instanceof Array;
  } catch (error) {
    /* empty */
  }

  return function setPrototypeOf(O, proto) {
    anObject(O);
    aPossiblePrototype(proto);
    if (CORRECT_SETTER) setter.call(O, proto);else O.__proto__ = proto;
    return O;
  };
}() : undefined);

var inheritIfRequired = function ($this, dummy, Wrapper) {
  var NewTarget, NewTargetPrototype;
  if ( // it can work only with native `setPrototypeOf`
  objectSetPrototypeOf && // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
  typeof (NewTarget = dummy.constructor) == 'function' && NewTarget !== Wrapper && isObject(NewTargetPrototype = NewTarget.prototype) && NewTargetPrototype !== Wrapper.prototype) objectSetPrototypeOf($this, NewTargetPrototype);
  return $this;
};

// https://tc39.github.io/ecma262/#sec-object.keys

var objectKeys = Object.keys || function keys(O) {
  return objectKeysInternal(O, enumBugKeys);
};

// https://tc39.github.io/ecma262/#sec-object.defineproperties

var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
  anObject(O);
  var keys = objectKeys(Properties);
  var length = keys.length;
  var index = 0;
  var key;

  while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);

  return O;
};

var html = getBuiltIn('document', 'documentElement');

var GT = '>';
var LT = '<';
var PROTOTYPE = 'prototype';
var SCRIPT = 'script';
var IE_PROTO = sharedKey('IE_PROTO');

var EmptyConstructor = function () {
  /* empty */
};

var scriptTag = function (content) {
  return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
}; // Create object with fake `null` prototype: use ActiveX Object with cleared prototype


var NullProtoObjectViaActiveX = function (activeXDocument) {
  activeXDocument.write(scriptTag(''));
  activeXDocument.close();
  var temp = activeXDocument.parentWindow.Object;
  activeXDocument = null; // avoid memory leak

  return temp;
}; // Create object with fake `null` prototype: use iframe Object with cleared prototype


var NullProtoObjectViaIFrame = function () {
  // Thrash, waste and sodomy: IE GC bug
  var iframe = documentCreateElement('iframe');
  var JS = 'java' + SCRIPT + ':';
  var iframeDocument;
  iframe.style.display = 'none';
  html.appendChild(iframe); // https://github.com/zloirock/core-js/issues/475

  iframe.src = String(JS);
  iframeDocument = iframe.contentWindow.document;
  iframeDocument.open();
  iframeDocument.write(scriptTag('document.F=Object'));
  iframeDocument.close();
  return iframeDocument.F;
}; // Check for document.domain and active x support
// No need to use active x approach when document.domain is not set
// see https://github.com/es-shims/es5-shim/issues/150
// variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
// avoid IE GC bug


var activeXDocument;

var NullProtoObject = function () {
  try {
    /* global ActiveXObject */
    activeXDocument = document.domain && new ActiveXObject('htmlfile');
  } catch (error) {
    /* ignore */
  }

  NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame();
  var length = enumBugKeys.length;

  while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]];

  return NullProtoObject();
};

hiddenKeys[IE_PROTO] = true; // `Object.create` method
// https://tc39.github.io/ecma262/#sec-object.create

var objectCreate = Object.create || function create(O, Properties) {
  var result;

  if (O !== null) {
    EmptyConstructor[PROTOTYPE] = anObject(O);
    result = new EmptyConstructor();
    EmptyConstructor[PROTOTYPE] = null; // add "__proto__" for Object.getPrototypeOf polyfill

    result[IE_PROTO] = O;
  } else result = NullProtoObject();

  return Properties === undefined ? result : objectDefineProperties(result, Properties);
};

// a string of all valid unicode whitespaces
// eslint-disable-next-line max-len
var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';

var whitespace = '[' + whitespaces + ']';
var ltrim = RegExp('^' + whitespace + whitespace + '*');
var rtrim = RegExp(whitespace + whitespace + '*$'); // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation

var createMethod$1 = function (TYPE) {
  return function ($this) {
    var string = String(requireObjectCoercible($this));
    if (TYPE & 1) string = string.replace(ltrim, '');
    if (TYPE & 2) string = string.replace(rtrim, '');
    return string;
  };
};

var stringTrim = {
  // `String.prototype.{ trimLeft, trimStart }` methods
  // https://tc39.github.io/ecma262/#sec-string.prototype.trimstart
  start: createMethod$1(1),
  // `String.prototype.{ trimRight, trimEnd }` methods
  // https://tc39.github.io/ecma262/#sec-string.prototype.trimend
  end: createMethod$1(2),
  // `String.prototype.trim` method
  // https://tc39.github.io/ecma262/#sec-string.prototype.trim
  trim: createMethod$1(3)
};

var getOwnPropertyNames = objectGetOwnPropertyNames.f;
var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
var defineProperty$1 = objectDefineProperty.f;
var trim = stringTrim.trim;
var NUMBER = 'Number';
var NativeNumber = global_1[NUMBER];
var NumberPrototype = NativeNumber.prototype; // Opera ~12 has broken Object#toString

var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER; // `ToNumber` abstract operation
// https://tc39.github.io/ecma262/#sec-tonumber

var toNumber = function (argument) {
  var it = toPrimitive(argument, false);
  var first, third, radix, maxCode, digits, length, index, code;

  if (typeof it == 'string' && it.length > 2) {
    it = trim(it);
    first = it.charCodeAt(0);

    if (first === 43 || first === 45) {
      third = it.charCodeAt(2);
      if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
    } else if (first === 48) {
      switch (it.charCodeAt(1)) {
        case 66:
        case 98:
          radix = 2;
          maxCode = 49;
          break;
        // fast equal of /^0b[01]+$/i

        case 79:
        case 111:
          radix = 8;
          maxCode = 55;
          break;
        // fast equal of /^0o[0-7]+$/i

        default:
          return +it;
      }

      digits = it.slice(2);
      length = digits.length;

      for (index = 0; index < length; index++) {
        code = digits.charCodeAt(index); // parseInt parses a string to a first unavailable symbol
        // but ToNumber should return NaN if a string contains unavailable symbols

        if (code < 48 || code > maxCode) return NaN;
      }

      return parseInt(digits, radix);
    }
  }

  return +it;
}; // `Number` constructor
// https://tc39.github.io/ecma262/#sec-number-constructor


if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
  var NumberWrapper = function Number(value) {
    var it = arguments.length < 1 ? 0 : value;
    var dummy = this;
    return dummy instanceof NumberWrapper // check on 1..constructor(foo) case
    && (BROKEN_CLASSOF ? fails(function () {
      NumberPrototype.valueOf.call(dummy);
    }) : classofRaw(dummy) != NUMBER) ? inheritIfRequired(new NativeNumber(toNumber(it)), dummy, NumberWrapper) : toNumber(it);
  };

  for (var keys$1 = descriptors ? getOwnPropertyNames(NativeNumber) : ( // ES3:
  'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' + // ES2015 (in case, if modules with ES2015 Number statics required before):
  'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' + 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger').split(','), j = 0, key; keys$1.length > j; j++) {
    if (has(NativeNumber, key = keys$1[j]) && !has(NumberWrapper, key)) {
      defineProperty$1(NumberWrapper, key, getOwnPropertyDescriptor$2(NativeNumber, key));
    }
  }

  NumberWrapper.prototype = NumberPrototype;
  NumberPrototype.constructor = NumberWrapper;
  redefine(global_1, NUMBER, NumberWrapper);
}

/**
 * @summary アニメーション時刻
 *
 * @classdesc
 * <p>アニメーションの時刻を表現するクラスである。</p>
 * <p>このクラスのインスタンスはイミュータブルである。</p>
 *
 * @memberof mapray.animation
 * @hideconstructor
 */
var Time =
/*#__PURE__*/
function () {
  /**
   * 非公開の構築子
   *
   * @param {number} ntime  数値時刻
   */
  function Time(ntime) {
    _classCallCheck(this, Time);

    this._ntime = ntime;
  }
  /**
   * @summary 表現可能な最初の時刻
   *
   * @type {mapray.animation.Time}
   * @readonly
   */


  _createClass(Time, [{
    key: "toNumber",

    /**
     * @summary 時刻を数値に変換
     *
     * @desc
     * <p>this の時刻に対応する数値を取得する。</p>
     *
     * @return {number}  時刻に対応する数値
     */
    value: function toNumber() {
      return this._ntime;
    }
    /** @summary 時刻の比較 (==)
     *
     * @desc
     * <p>this の時刻と rhs の時刻が同じとき true, それ以外のとき false を返す。</p>
     *
     * @param {mapray.animation.Time} rhs  時刻
     *
     * @return {boolean}  比較結果
     */

  }, {
    key: "equals",
    value: function equals(rhs) {
      return this._ntime == rhs._ntime;
    }
    /** @summary 時刻の比較 (<)
     *
     * @desc
     * <p>this の時刻が rhs の時刻より前のとき true, それ以外のとき false を返す。</p>
     *
     * @param {mapray.animation.Time} rhs  時刻
     *
     * @return {boolean}  比較結果
     */

  }, {
    key: "lessThan",
    value: function lessThan(rhs) {
      return this._ntime < rhs._ntime;
    }
    /** @summary 時刻の比較 (<=)
     *
     * @desc
     * <p>this の時刻が rhs の時刻より前または同じとき true, それ以外のとき false を返す。</p>
     *
     * @param {mapray.animation.Time} rhs  時刻
     *
     * @return {boolean}  比較結果
     */

  }, {
    key: "lessEqual",
    value: function lessEqual(rhs) {
      return this._ntime <= rhs._ntime;
    }
  }], [{
    key: "fromNumber",

    /**
     * @summary 数値を時刻に変換
     *
     * @desc
     * <p>時刻に対応する数値から Time インスタンスを生成する。</p>
     * <p>条件: Time.MIN_NTIME <= ntime <= Time.MAX_NTIME</p>
     *
     * @param {number} ntime  時刻に対応する数値
     *
     * @return {mapray.animation.Time}  Time インスタンス
     */
    value: function fromNumber(ntime) {
      return new Time(ntime);
    }
  }, {
    key: "MIN_TIME",
    get: function get() {
      return TIME_MIN_TIME;
    }
    /**
     * @summary 表現可能な最後の時刻
     *
     * @type {mapray.animation.Time}
     * @readonly
     */

  }, {
    key: "MAX_TIME",
    get: function get() {
      return TIME_MAX_TIME;
    }
    /**
     * @summary 時刻に対応する数値の最小値
     *
     * @type {number}
     * @readonly
     */

  }, {
    key: "MIN_NTIME",
    get: function get() {
      return TIME_MIN_NTIME;
    }
    /**
     * @summary 時刻に対応する数値の最大値
     *
     * @type {number}
     * @readonly
     */

  }, {
    key: "MAX_NTIME",
    get: function get() {
      return TIME_MAX_NTIME;
    }
  }]);

  return Time;
}();

var TIME_MIN_NTIME = -Number.MAX_VALUE;
var TIME_MAX_NTIME = +Number.MAX_VALUE;
var TIME_MIN_TIME = Time.fromNumber(TIME_MIN_NTIME);
var TIME_MAX_TIME = Time.fromNumber(TIME_MAX_NTIME);

/**
 * @summary アニメーション時刻の区間
 *
 * @classdesc
 * <p>アニメーション時刻の区間を表現するクラスである。</p>
 * <p>このクラスのインスタンスはイミュータブルである。</p>
 *
 * @memberof mapray.animation
 */

var Interval =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>下限 lower と上限 upper の時刻区間を生成する。</p>
   * <p>端点である lower と upper が区間に含まれるかどうかは l_open と u_open により指定する。</p>
   *
   * <pre>
   *  interval       | l_open  u_open
   * ----------------+----------------
   *  [lower, upper] | false   false
   *  [lower, upper) | false   true
   *  (lower, upper] | true    false
   *  (lower, upper) | true    true
   * </pre>
   *
   * @param {mapray.animation.Time} lower  区間の下限時刻
   * @param {mapray.animation.Time} upper  区間の上限時刻
   * @param {boolean}      [l_open=false]  lower が区間にが含まれるとき false, 含まれないとき true
   * @param {boolean}      [u_open=false]  upper が区間にが含まれるとき false, 含まれないとき true
   */
  function Interval(lower, upper, l_open, u_open) {
    _classCallCheck(this, Interval);

    this._lower = lower;
    this._upper = upper;
    this._l_open = l_open === undefined ? false : l_open;
    this._u_open = u_open === undefined ? false : u_open;
  }
  /**
   * @summary 全時刻区間
   *
   * @type {mapray.animation.Interval}
   * @readonly
   */


  _createClass(Interval, [{
    key: "isEmpty",

    /**
     * @summary 空時刻区間か?
     *
     * @desc
     * <p>this が空の時刻区間かどうかを返す。</p>
     * <p>空時刻区間の場合、区間内に 1 つも時刻が存在しない。</p>
     *
     * @return {boolean}  空時刻区間のとき true, それ以外のとき false
     */
    value: function isEmpty() {
      var lower = this._lower;
      var upper = this._upper;
      return upper.lessThan(lower) || upper.equals(lower) && (this._l_open || this._u_open);
    }
    /**
     * @summary 単一時刻区間か?
     *
     * @desc
     * <p>this が単一時刻の時刻区間かどうかを返す。</p>
     * <p>単一時刻区間の場合、区間内にただ 1 つの時刻が存在する。</p>
     * <p>単一時刻区間であるなら lower == upper であり、逆は必ずしも成り立たない。</p>
     *
     * @return {boolean}  単一時刻区間のとき true, それ以外のとき false
     */

  }, {
    key: "isSingle",
    value: function isSingle() {
      return this._lower.equals(this._upper) && !(this._l_open || this._u_open);
    }
    /**
     * @summary 通常時刻区間か?
     *
     * @desc
     * <p>this が通常の時刻区間かどうかを返す。</p>
     * <p>通常時刻区間の場合、区間内に無限個の時刻が存在する。</p>
     * <p>通常時刻区間であるなら lower < upper であり、逆も成り立つ。</p>
     *
     * @return {boolean}  通常時刻区間のとき true, それ以外のとき false
     */

  }, {
    key: "isProper",
    value: function isProper() {
      return this._lower.lessThan(this._upper);
    }
    /**
     * @summary 先行しているか?
     *
     * @desc
     * <p>this のすべての時刻が rhs のすべての時刻より先行しているときに true, それ以外のときは false を返す。</p>
     * <p>this または rhs のどちらか、または両方が空時刻区間のときは true を返す。</p>
     *
     * @param {mapray.animation.Interval} rhs  時刻区間
     *
     * @return {boolean}  this が rhs に先行しているとき true, それ以外のとき false
     */

  }, {
    key: "precedes",
    value: function precedes(rhs) {
      if (this.isEmpty() || rhs.isEmpty()) {
        // this または rhs のどちらか、または両方が空時刻区間のときの仕様
        return true;
      } else {
        var ut1 = this._upper;
        var uo1 = this._u_open;
        var lt2 = rhs._lower;
        var lo2 = rhs._l_open;
        return ut1.lessThan(lt2) || ut1.equals(lt2) && (uo1 || lo2);
      }
    }
    /**
     * @summary 包含しているか?
     *
     * @desc
     * <p>rhs のすべての時刻が this に含まれるとき true, それ以外のときは false を返す。</p>
     * <p>rhs が空時刻区間のときは true を返す。</p>
     * <p>これは rhs ⊆ this と等価である。</p>
     *
     * @param {mapray.animation.Interval} rhs  時刻区間
     *
     * @return {boolean}  this が rhs を包含しているとき true, それ以外のとき false
     */

  }, {
    key: "includes",
    value: function includes(rhs) {
      if (rhs.isEmpty()) {
        // rhs が空時刻区間のときの仕様
        return true;
      } else {
        var lt1 = this._lower;
        var lt2 = rhs._lower;
        var lo1 = this._l_open;
        var lo2 = rhs._l_open;
        var inc_l = lt1.lessThan(lt2) || lt1.equals(lt2) && (!lo1 || lo2);
        var ut1 = this._upper;
        var ut2 = rhs._upper;
        var uo1 = this._u_open;
        var uo2 = rhs._u_open;
        var inc_u = ut2.lessThan(ut1) || ut2.equals(ut1) && (uo2 || !uo1);
        return inc_l && inc_u;
      }
    }
    /**
     * @summary 時刻を包含しているか?
     *
     * @desc
     * <p>rhs の時刻が this に含まれるとき true, それ以外のときは false を返す。</p>
     * <p>このメソッドは this.includes( new Interval( rhs, rhs ) ) と同等である。</p>
     *
     * @param {mapray.animation.Time} rhs  時刻
     *
     * @return {boolean}  this が rhs を包含しているとき true, それ以外のとき false
     */

  }, {
    key: "includesTime",
    value: function includesTime(rhs) {
      var lower = this._lower;
      var inc_l = lower.lessThan(rhs) || lower.equals(rhs) && !this._l_open;
      var upper = this._upper;
      var inc_u = rhs.lessThan(upper) || rhs.equals(upper) && !this._u_open;
      return inc_l && inc_u;
    }
    /**
     * @summary 共通時刻区間は存在するか?
     *
     * @desc
     * <p>!this.getIntersection( rhs ).isEmpty() と同じである。</p>
     *
     * @param {mapray.animation.Interval} rhs  時刻区間
     *
     * @return {boolean}  共通時刻区間
     *
     * @see {@link mapray.animation.Interval#getIntersection}
     */

  }, {
    key: "hasIntersection",
    value: function hasIntersection(rhs) {
      // todo: オブジェクトを生成しないように最適化
      return !this.getIntersection(rhs).isEmpty();
    }
    /**
     * @summary 先行時刻区間を取得
     *
     * @desc
     * <p>this のすべての時刻に対して、先の時刻となるすべての時刻を含む先行時刻区間を返す。</p>
     * <p>this が空時刻区間のときは全時刻区間を返し、this
     *    に表現可能な最初の時刻が含まれるときは空時刻区間を返す。</p>
     * <p>this.getPrecedings().precedes( this ) は常に true を返す。</p>
     *
     * @return {mapray.animation.Interval}  先行時刻区間
     */

  }, {
    key: "getPrecedings",
    value: function getPrecedings() {
      if (this.isEmpty()) {
        // 空時刻区間のときは全時刻区間を返す仕様
        return INTERVAL_UNIVERSAL;
      } else {
        return new Interval(Time.MIN_TIME, this._lower, false, !this._l_open);
      }
    }
    /**
     * @summary 後続時刻区間を取得
     *
     * @desc
     * <p>this のすべての時刻に対して、後の時刻となるすべての時刻を含む後続時刻区間を返す。</p>
     * <p>this が空時刻区間のときは全時刻区間を返し、this
     *    に表現可能な最後の時刻が含まれるときは空時刻区間を返す。</p>
     * <p>this.precedes( this.getFollowings() ) は常に true を返す。</p>
     *
     * @return {mapray.animation.Interval}  後続時刻区間
     */

  }, {
    key: "getFollowings",
    value: function getFollowings() {
      if (this.isEmpty()) {
        // 空時刻区間のときは全時刻区間を返す仕様
        return INTERVAL_UNIVERSAL;
      } else {
        return new Interval(this._upper, Time.MAX_TIME, !this._u_open, false);
      }
    }
    /**
     * @summary 共通時刻区間を取得
     *
     * @desc
     * <p>this と rhs の共通時刻区間 (this ∩ rhs) を返す。</p>
     * <p>this と rhs に共通の時刻が存在しなければ空時刻区間を返す。</p>
     *
     * @param {mapray.animation.Interval} rhs  時刻区間
     *
     * @return {mapray.animation.Interval}  共通時刻区間
     *
     * @see {@link mapray.animation.Interval#hasIntersection}
     */

  }, {
    key: "getIntersection",
    value: function getIntersection(rhs) {
      // B = Lb ∩ Ub とするとき
      // A ∩ B = A ∩ Lb ∩ Ub
      // A ∩ Lb
      var cross = this._getIntersectionByLower(rhs._lower, rhs._l_open); // (A ∩ Lb) ∩ Ub


      return cross._getIntersectionByUpper(rhs._upper, rhs._u_open);
    }
    /**
     * @summary 合併時刻区間を取得
     *
     * @desc
     * <p>this と rhs を合併した時刻集合 (this ∪ rhs) を時刻区間の配列として返す。</p>
     * <p>0 から 2 個の時刻区間を含む配列を返す。配列の要素に空時刻区間は含まれない。</p>
     * <p>2 要素の配列 v が返されたとき、v[0] と v[1] の間に時刻が存在し、さらに
     *    v[0].precedes( v[1] ) は true となる。</p>
     *
     * @param {mapray.animation.Interval} rhs  時刻区間
     *
     * @return {mapray.animation.Interval[]}  合併時刻区間
     */

  }, {
    key: "getUnion",
    value: function getUnion(rhs) {
      if (this.isEmpty()) {
        return rhs.isEmpty() ? [] : [rhs];
      } else if (rhs.isEmpty()) {
        // Assert: !this.isEmpty() && rhs.isEmpty()
        return [this];
      } // Assert: !this.isEmpty() && !rhs.isEmpty()


      var lt1 = this._lower;
      var ut1 = this._upper;
      var lo1 = this._l_open;
      var uo1 = this._u_open;
      var lt2 = rhs._lower;
      var ut2 = rhs._upper;
      var lo2 = rhs._l_open;
      var uo2 = rhs._u_open;

      if (ut1.lessThan(lt2) || ut1.equals(lt2) && uo1 && lo2) {
        // Assert: this と rhs は離れている、かつ this が先行
        return [this, rhs];
      } else if (ut2.lessThan(lt1) || lt1.equals(ut2) && lo1 && uo2) {
        // Assert: this と rhs は離れている、かつ rhs が先行
        return [rhs, this];
      } // Assert: this と rhs は交差または隣接している (単一の時刻区間に合併できる)


      var _ref = lt1.lessThan(lt2) || lt1.equals(lt2) && lo2 ? [lt1, lo1] : [lt2, lo2],
          _ref2 = _slicedToArray(_ref, 2),
          lower = _ref2[0],
          l_open = _ref2[1];

      var _ref3 = ut2.lessThan(ut1) || ut2.equals(ut1) && uo2 ? [ut1, uo1] : [ut2, uo2],
          _ref4 = _slicedToArray(_ref3, 2),
          upper = _ref4[0],
          u_open = _ref4[1];

      return [new Interval(lower, upper, l_open, u_open)];
    }
    /**
     * @summary 時刻区間の差を取得
     *
     * @desc
     * <p>this から rhs を差し引いた時刻集合 (this - rhs) を時刻区間の配列として返す。</p>
     * <p>0 から 2 個の時刻区間を含む配列を返す。配列の要素に空時刻区間は含まれない。</p>
     * <p>2 要素の配列 v が返されたとき、v[0] と v[1] の間に時刻が存在し、さらに
     *    v[0].precedes( v[1] ) は true となる。</p>
     *
     * @param {mapray.animation.Interval} rhs  時刻区間
     *
     * @return {mapray.animation.Interval[]}  時刻区間の差
     */

  }, {
    key: "getDifference",
    value: function getDifference(rhs) {
      // B = Lb ∩ Ub とするとき
      // A - B = A ∩ ~B
      //       = (A ∩ ~Lb) ∪ (A ∩ ~Ub)
      // A ∩ ~Lb
      var i1 = this._getIntersectionByUpper(rhs._lower, !rhs._l_open); // A ∩ ~Ub


      var i2 = this._getIntersectionByLower(rhs._upper, !rhs._u_open); // (A ∩ ~Lb) ∪ (A ∩ ~Ub)


      return i1.getUnion(i2);
    }
    /**
     * @summary 補時刻区間を取得
     *
     * @desc
     * <p>全時刻区間 から this を差し引いた時刻集合を時刻区間の配列として返す。</p>
     * <p>0 から 2 個の時刻区間を含む配列を返す。配列の要素に空時刻区間は含まれない。</p>
     * <p>2 要素の配列 v が返されたとき、v[0] と v[1] の間に時刻が存在し、さらに
     *    v[0].precedes( v[1] ) は true となる。</p>
     *
     * @return {mapray.animation.Interval[]}  補時刻区間
     */

  }, {
    key: "getComplement",
    value: function getComplement() {
      return INTERVAL_UNIVERSAL.getDifference(this);
    }
    /**
     * @summary 下限時刻区間との共通時刻区間を取得
     *
     * @desc
     * <p>this ∩ Lower(bound, open) → Interval<p>
     *
     * @param {mapray.animation.Time} bound
     * @param {boolean}               open
     *
     * @return {mapray.animation.Interval}  共通時刻区間
     *
     * @private
     */

  }, {
    key: "_getIntersectionByLower",
    value: function _getIntersectionByLower(bound, open) {
      if (bound.lessThan(this._lower) || bound.equals(this._lower) && this._l_open) {
        return this;
      } else {
        return new Interval(bound, this._upper, open, this._u_open);
      }
    }
    /**
     * @summary 上限時刻区間との共通時刻区間を取得
     *
     * @desc
     * <p>this ∩ Upper(bound, open) → Interval<p>
     *
     * @param {mapray.animation.Time} bound
     * @param {boolean}               open
     *
     * @return {mapray.animation.Interval}  共通時刻区間
     *
     * @private
     */

  }, {
    key: "_getIntersectionByUpper",
    value: function _getIntersectionByUpper(bound, open) {
      if (this._upper.lessThan(bound) || this._upper.equals(bound) && this._u_open) {
        return this;
      } else {
        return new Interval(this._lower, bound, this._l_open, open);
      }
    }
  }, {
    key: "lower",

    /**
     * @summary 下限時刻
     *
     * @type {mapray.animation.Time}
     * @readonly
     */
    get: function get() {
      return this._lower;
    }
    /**
     * @summary 上限時刻
     *
     * @type {mapray.animation.Time}
     * @readonly
     */

  }, {
    key: "upper",
    get: function get() {
      return this._upper;
    }
    /**
     * @summary 下限時刻は除外されるか?
     *
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "l_open",
    get: function get() {
      return this._l_open;
    }
    /**
     * @summary 上限時刻は除外されるか?
     *
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "u_open",
    get: function get() {
      return this._u_open;
    }
  }], [{
    key: "UNIVERSAL",
    get: function get() {
      return INTERVAL_UNIVERSAL;
    }
  }]);

  return Interval;
}();

var INTERVAL_UNIVERSAL = new Interval(Time.MIN_TIME, Time.MAX_TIME);

var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
  // Chrome 38 Symbol has incorrect toString conversion
  // eslint-disable-next-line no-undef
  return !String(Symbol());
});

var useSymbolAsUid = nativeSymbol // eslint-disable-next-line no-undef
&& !Symbol.sham // eslint-disable-next-line no-undef
&& typeof Symbol.iterator == 'symbol';

// https://tc39.github.io/ecma262/#sec-isarray

var isArray = Array.isArray || function isArray(arg) {
  return classofRaw(arg) == 'Array';
};

// https://tc39.github.io/ecma262/#sec-toobject

var toObject = function (argument) {
  return Object(requireObjectCoercible(argument));
};

var nativeGetOwnPropertyNames = objectGetOwnPropertyNames.f;
var toString$1 = {}.toString;
var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : [];

var getWindowNames = function (it) {
  try {
    return nativeGetOwnPropertyNames(it);
  } catch (error) {
    return windowNames.slice();
  }
}; // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window


var f$5 = function getOwnPropertyNames(it) {
  return windowNames && toString$1.call(it) == '[object Window]' ? getWindowNames(it) : nativeGetOwnPropertyNames(toIndexedObject(it));
};

var objectGetOwnPropertyNamesExternal = {
  f: f$5
};

var WellKnownSymbolsStore = shared('wks');
var Symbol$1 = global_1.Symbol;
var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;

var wellKnownSymbol = function (name) {
  if (!has(WellKnownSymbolsStore, name)) {
    if (nativeSymbol && has(Symbol$1, name)) WellKnownSymbolsStore[name] = Symbol$1[name];else WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name);
  }

  return WellKnownSymbolsStore[name];
};

var f$6 = wellKnownSymbol;
var wellKnownSymbolWrapped = {
  f: f$6
};

var defineProperty$2 = objectDefineProperty.f;

var defineWellKnownSymbol = function (NAME) {
  var Symbol = path.Symbol || (path.Symbol = {});
  if (!has(Symbol, NAME)) defineProperty$2(Symbol, NAME, {
    value: wellKnownSymbolWrapped.f(NAME)
  });
};

var defineProperty$3 = objectDefineProperty.f;
var TO_STRING_TAG = wellKnownSymbol('toStringTag');

var setToStringTag = function (it, TAG, STATIC) {
  if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG)) {
    defineProperty$3(it, TO_STRING_TAG, {
      configurable: true,
      value: TAG
    });
  }
};

var aFunction$1 = function (it) {
  if (typeof it != 'function') {
    throw TypeError(String(it) + ' is not a function');
  }

  return it;
};

var functionBindContext = function (fn, that, length) {
  aFunction$1(fn);
  if (that === undefined) return fn;

  switch (length) {
    case 0:
      return function () {
        return fn.call(that);
      };

    case 1:
      return function (a) {
        return fn.call(that, a);
      };

    case 2:
      return function (a, b) {
        return fn.call(that, a, b);
      };

    case 3:
      return function (a, b, c) {
        return fn.call(that, a, b, c);
      };
  }

  return function ()
  /* ...args */
  {
    return fn.apply(that, arguments);
  };
};

var SPECIES = wellKnownSymbol('species'); // `ArraySpeciesCreate` abstract operation
// https://tc39.github.io/ecma262/#sec-arrayspeciescreate

var arraySpeciesCreate = function (originalArray, length) {
  var C;

  if (isArray(originalArray)) {
    C = originalArray.constructor; // cross-realm fallback

    if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;else if (isObject(C)) {
      C = C[SPECIES];
      if (C === null) C = undefined;
    }
  }

  return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
};

var push = [].push; // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex }` methods implementation

var createMethod$2 = function (TYPE) {
  var IS_MAP = TYPE == 1;
  var IS_FILTER = TYPE == 2;
  var IS_SOME = TYPE == 3;
  var IS_EVERY = TYPE == 4;
  var IS_FIND_INDEX = TYPE == 6;
  var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
  return function ($this, callbackfn, that, specificCreate) {
    var O = toObject($this);
    var self = indexedObject(O);
    var boundFunction = functionBindContext(callbackfn, that, 3);
    var length = toLength(self.length);
    var index = 0;
    var create = specificCreate || arraySpeciesCreate;
    var target = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined;
    var value, result;

    for (; length > index; index++) if (NO_HOLES || index in self) {
      value = self[index];
      result = boundFunction(value, index, O);

      if (TYPE) {
        if (IS_MAP) target[index] = result; // map
        else if (result) switch (TYPE) {
            case 3:
              return true;
            // some

            case 5:
              return value;
            // find

            case 6:
              return index;
            // findIndex

            case 2:
              push.call(target, value);
            // filter
          } else if (IS_EVERY) return false; // every
      }
    }

    return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
  };
};

var arrayIteration = {
  // `Array.prototype.forEach` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
  forEach: createMethod$2(0),
  // `Array.prototype.map` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.map
  map: createMethod$2(1),
  // `Array.prototype.filter` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.filter
  filter: createMethod$2(2),
  // `Array.prototype.some` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.some
  some: createMethod$2(3),
  // `Array.prototype.every` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.every
  every: createMethod$2(4),
  // `Array.prototype.find` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.find
  find: createMethod$2(5),
  // `Array.prototype.findIndex` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
  findIndex: createMethod$2(6)
};

var $forEach = arrayIteration.forEach;
var HIDDEN = sharedKey('hidden');
var SYMBOL = 'Symbol';
var PROTOTYPE$1 = 'prototype';
var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
var setInternalState = internalState.set;
var getInternalState = internalState.getterFor(SYMBOL);
var ObjectPrototype = Object[PROTOTYPE$1];
var $Symbol = global_1.Symbol;
var $stringify = getBuiltIn('JSON', 'stringify');
var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
var nativeDefineProperty$1 = objectDefineProperty.f;
var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f;
var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f;
var AllSymbols = shared('symbols');
var ObjectPrototypeSymbols = shared('op-symbols');
var StringToSymbolRegistry = shared('string-to-symbol-registry');
var SymbolToStringRegistry = shared('symbol-to-string-registry');
var WellKnownSymbolsStore$1 = shared('wks');
var QObject = global_1.QObject; // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173

var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild; // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687

var setSymbolDescriptor = descriptors && fails(function () {
  return objectCreate(nativeDefineProperty$1({}, 'a', {
    get: function () {
      return nativeDefineProperty$1(this, 'a', {
        value: 7
      }).a;
    }
  })).a != 7;
}) ? function (O, P, Attributes) {
  var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype, P);
  if (ObjectPrototypeDescriptor) delete ObjectPrototype[P];
  nativeDefineProperty$1(O, P, Attributes);

  if (ObjectPrototypeDescriptor && O !== ObjectPrototype) {
    nativeDefineProperty$1(ObjectPrototype, P, ObjectPrototypeDescriptor);
  }
} : nativeDefineProperty$1;

var wrap = function (tag, description) {
  var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE$1]);
  setInternalState(symbol, {
    type: SYMBOL,
    tag: tag,
    description: description
  });
  if (!descriptors) symbol.description = description;
  return symbol;
};

var isSymbol = useSymbolAsUid ? function (it) {
  return typeof it == 'symbol';
} : function (it) {
  return Object(it) instanceof $Symbol;
};

var $defineProperty = function defineProperty(O, P, Attributes) {
  if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
  anObject(O);
  var key = toPrimitive(P, true);
  anObject(Attributes);

  if (has(AllSymbols, key)) {
    if (!Attributes.enumerable) {
      if (!has(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor(1, {}));
      O[HIDDEN][key] = true;
    } else {
      if (has(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
      Attributes = objectCreate(Attributes, {
        enumerable: createPropertyDescriptor(0, false)
      });
    }

    return setSymbolDescriptor(O, key, Attributes);
  }

  return nativeDefineProperty$1(O, key, Attributes);
};

var $defineProperties = function defineProperties(O, Properties) {
  anObject(O);
  var properties = toIndexedObject(Properties);
  var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties));
  $forEach(keys, function (key) {
    if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
  });
  return O;
};

var $create = function create(O, Properties) {
  return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties);
};

var $propertyIsEnumerable = function propertyIsEnumerable(V) {
  var P = toPrimitive(V, true);
  var enumerable = nativePropertyIsEnumerable$1.call(this, P);
  if (this === ObjectPrototype && has(AllSymbols, P) && !has(ObjectPrototypeSymbols, P)) return false;
  return enumerable || !has(this, P) || !has(AllSymbols, P) || has(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
};

var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
  var it = toIndexedObject(O);
  var key = toPrimitive(P, true);
  if (it === ObjectPrototype && has(AllSymbols, key) && !has(ObjectPrototypeSymbols, key)) return;
  var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);

  if (descriptor && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) {
    descriptor.enumerable = true;
  }

  return descriptor;
};

var $getOwnPropertyNames = function getOwnPropertyNames(O) {
  var names = nativeGetOwnPropertyNames$1(toIndexedObject(O));
  var result = [];
  $forEach(names, function (key) {
    if (!has(AllSymbols, key) && !has(hiddenKeys, key)) result.push(key);
  });
  return result;
};

var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
  var IS_OBJECT_PROTOTYPE = O === ObjectPrototype;
  var names = nativeGetOwnPropertyNames$1(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
  var result = [];
  $forEach(names, function (key) {
    if (has(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype, key))) {
      result.push(AllSymbols[key]);
    }
  });
  return result;
}; // `Symbol` constructor
// https://tc39.github.io/ecma262/#sec-symbol-constructor


if (!nativeSymbol) {
  $Symbol = function Symbol() {
    if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
    var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
    var tag = uid(description);

    var setter = function (value) {
      if (this === ObjectPrototype) setter.call(ObjectPrototypeSymbols, value);
      if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
      setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
    };

    if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, {
      configurable: true,
      set: setter
    });
    return wrap(tag, description);
  };

  redefine($Symbol[PROTOTYPE$1], 'toString', function toString() {
    return getInternalState(this).tag;
  });
  redefine($Symbol, 'withoutSetter', function (description) {
    return wrap(uid(description), description);
  });
  objectPropertyIsEnumerable.f = $propertyIsEnumerable;
  objectDefineProperty.f = $defineProperty;
  objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor;
  objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames;
  objectGetOwnPropertySymbols.f = $getOwnPropertySymbols;

  wellKnownSymbolWrapped.f = function (name) {
    return wrap(wellKnownSymbol(name), name);
  };

  if (descriptors) {
    // https://github.com/tc39/proposal-Symbol-description
    nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', {
      configurable: true,
      get: function description() {
        return getInternalState(this).description;
      }
    });

    {
      redefine(ObjectPrototype, 'propertyIsEnumerable', $propertyIsEnumerable, {
        unsafe: true
      });
    }
  }
}

_export({
  global: true,
  wrap: true,
  forced: !nativeSymbol,
  sham: !nativeSymbol
}, {
  Symbol: $Symbol
});
$forEach(objectKeys(WellKnownSymbolsStore$1), function (name) {
  defineWellKnownSymbol(name);
});
_export({
  target: SYMBOL,
  stat: true,
  forced: !nativeSymbol
}, {
  // `Symbol.for` method
  // https://tc39.github.io/ecma262/#sec-symbol.for
  'for': function (key) {
    var string = String(key);
    if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
    var symbol = $Symbol(string);
    StringToSymbolRegistry[string] = symbol;
    SymbolToStringRegistry[symbol] = string;
    return symbol;
  },
  // `Symbol.keyFor` method
  // https://tc39.github.io/ecma262/#sec-symbol.keyfor
  keyFor: function keyFor(sym) {
    if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol');
    if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
  },
  useSetter: function () {
    USE_SETTER = true;
  },
  useSimple: function () {
    USE_SETTER = false;
  }
});
_export({
  target: 'Object',
  stat: true,
  forced: !nativeSymbol,
  sham: !descriptors
}, {
  // `Object.create` method
  // https://tc39.github.io/ecma262/#sec-object.create
  create: $create,
  // `Object.defineProperty` method
  // https://tc39.github.io/ecma262/#sec-object.defineproperty
  defineProperty: $defineProperty,
  // `Object.defineProperties` method
  // https://tc39.github.io/ecma262/#sec-object.defineproperties
  defineProperties: $defineProperties,
  // `Object.getOwnPropertyDescriptor` method
  // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors
  getOwnPropertyDescriptor: $getOwnPropertyDescriptor
});
_export({
  target: 'Object',
  stat: true,
  forced: !nativeSymbol
}, {
  // `Object.getOwnPropertyNames` method
  // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
  getOwnPropertyNames: $getOwnPropertyNames,
  // `Object.getOwnPropertySymbols` method
  // https://tc39.github.io/ecma262/#sec-object.getownpropertysymbols
  getOwnPropertySymbols: $getOwnPropertySymbols
}); // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
// https://bugs.chromium.org/p/v8/issues/detail?id=3443

_export({
  target: 'Object',
  stat: true,
  forced: fails(function () {
    objectGetOwnPropertySymbols.f(1);
  })
}, {
  getOwnPropertySymbols: function getOwnPropertySymbols(it) {
    return objectGetOwnPropertySymbols.f(toObject(it));
  }
}); // `JSON.stringify` method behavior with symbols
// https://tc39.github.io/ecma262/#sec-json.stringify

if ($stringify) {
  var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () {
    var symbol = $Symbol(); // MS Edge converts symbol values to JSON as {}

    return $stringify([symbol]) != '[null]' // WebKit converts symbol values to JSON as null
    || $stringify({
      a: symbol
    }) != '{}' // V8 throws on boxed symbols
    || $stringify(Object(symbol)) != '{}';
  });
  _export({
    target: 'JSON',
    stat: true,
    forced: FORCED_JSON_STRINGIFY
  }, {
    // eslint-disable-next-line no-unused-vars
    stringify: function stringify(it, replacer, space) {
      var args = [it];
      var index = 1;
      var $replacer;

      while (arguments.length > index) args.push(arguments[index++]);

      $replacer = replacer;
      if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined

      if (!isArray(replacer)) replacer = function (key, value) {
        if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
        if (!isSymbol(value)) return value;
      };
      args[1] = replacer;
      return $stringify.apply(null, args);
    }
  });
} // `Symbol.prototype[@@toPrimitive]` method
// https://tc39.github.io/ecma262/#sec-symbol.prototype-@@toprimitive


if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) {
  createNonEnumerableProperty($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf);
} // `Symbol.prototype[@@toStringTag]` property
// https://tc39.github.io/ecma262/#sec-symbol.prototype-@@tostringtag


setToStringTag($Symbol, SYMBOL);
hiddenKeys[HIDDEN] = true;

var defineProperty$4 = objectDefineProperty.f;
var NativeSymbol = global_1.Symbol;

if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) || // Safari 12 bug
NativeSymbol().description !== undefined)) {
  var EmptyStringDescriptionStore = {}; // wrap Symbol constructor for correct work with undefined description

  var SymbolWrapper = function Symbol() {
    var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
    var result = this instanceof SymbolWrapper ? new NativeSymbol(description) // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
    : description === undefined ? NativeSymbol() : NativeSymbol(description);
    if (description === '') EmptyStringDescriptionStore[result] = true;
    return result;
  };

  copyConstructorProperties(SymbolWrapper, NativeSymbol);
  var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
  symbolPrototype.constructor = SymbolWrapper;
  var symbolToString = symbolPrototype.toString;
  var native = String(NativeSymbol('test')) == 'Symbol(test)';
  var regexp = /^Symbol\((.*)\)[^)]+$/;
  defineProperty$4(symbolPrototype, 'description', {
    configurable: true,
    get: function description() {
      var symbol = isObject(this) ? this.valueOf() : this;
      var string = symbolToString.call(symbol);
      if (has(EmptyStringDescriptionStore, symbol)) return '';
      var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
      return desc === '' ? undefined : desc;
    }
  });
  _export({
    global: true,
    forced: true
  }, {
    Symbol: SymbolWrapper
  });
}

// https://tc39.github.io/ecma262/#sec-symbol.iterator

defineWellKnownSymbol('iterator');

var UNSCOPABLES = wellKnownSymbol('unscopables');
var ArrayPrototype = Array.prototype; // Array.prototype[@@unscopables]
// https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables

if (ArrayPrototype[UNSCOPABLES] == undefined) {
  objectDefineProperty.f(ArrayPrototype, UNSCOPABLES, {
    configurable: true,
    value: objectCreate(null)
  });
} // add a key to Array.prototype[@@unscopables]


var addToUnscopables = function (key) {
  ArrayPrototype[UNSCOPABLES][key] = true;
};

var defineProperty$5 = Object.defineProperty;
var cache = {};

var thrower = function (it) {
  throw it;
};

var arrayMethodUsesToLength = function (METHOD_NAME, options) {
  if (has(cache, METHOD_NAME)) return cache[METHOD_NAME];
  if (!options) options = {};
  var method = [][METHOD_NAME];
  var ACCESSORS = has(options, 'ACCESSORS') ? options.ACCESSORS : false;
  var argument0 = has(options, 0) ? options[0] : thrower;
  var argument1 = has(options, 1) ? options[1] : undefined;
  return cache[METHOD_NAME] = !!method && !fails(function () {
    if (ACCESSORS && !descriptors) return true;
    var O = {
      length: -1
    };
    if (ACCESSORS) defineProperty$5(O, 1, {
      enumerable: true,
      get: thrower
    });else O[1] = 1;
    method.call(O, argument0, argument1);
  });
};

var $includes = arrayIncludes.includes;
var USES_TO_LENGTH = arrayMethodUsesToLength('indexOf', {
  ACCESSORS: true,
  1: 0
}); // `Array.prototype.includes` method
// https://tc39.github.io/ecma262/#sec-array.prototype.includes

_export({
  target: 'Array',
  proto: true,
  forced: !USES_TO_LENGTH
}, {
  includes: function includes(el
  /* , fromIndex = 0 */
  ) {
    return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
  }
}); // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables

addToUnscopables('includes');

var iterators = {};

var correctPrototypeGetter = !fails(function () {
  function F() {
    /* empty */
  }

  F.prototype.constructor = null;
  return Object.getPrototypeOf(new F()) !== F.prototype;
});

var IE_PROTO$1 = sharedKey('IE_PROTO');
var ObjectPrototype$1 = Object.prototype; // `Object.getPrototypeOf` method
// https://tc39.github.io/ecma262/#sec-object.getprototypeof

var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
  O = toObject(O);
  if (has(O, IE_PROTO$1)) return O[IE_PROTO$1];

  if (typeof O.constructor == 'function' && O instanceof O.constructor) {
    return O.constructor.prototype;
  }

  return O instanceof Object ? ObjectPrototype$1 : null;
};

var ITERATOR = wellKnownSymbol('iterator');
var BUGGY_SAFARI_ITERATORS = false;

var returnThis = function () {
  return this;
}; // `%IteratorPrototype%` object
// https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object


var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;

if ([].keys) {
  arrayIterator = [].keys(); // Safari 8 has buggy iterators w/o `next`

  if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;else {
    PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
    if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;
  }
}

if (IteratorPrototype == undefined) IteratorPrototype = {}; // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()

if ( !has(IteratorPrototype, ITERATOR)) {
  createNonEnumerableProperty(IteratorPrototype, ITERATOR, returnThis);
}

var iteratorsCore = {
  IteratorPrototype: IteratorPrototype,
  BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
};

var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;

var returnThis$1 = function () {
  return this;
};

var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
  var TO_STRING_TAG = NAME + ' Iterator';
  IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, {
    next: createPropertyDescriptor(1, next)
  });
  setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
  iterators[TO_STRING_TAG] = returnThis$1;
  return IteratorConstructor;
};

var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
var ITERATOR$1 = wellKnownSymbol('iterator');
var KEYS = 'keys';
var VALUES = 'values';
var ENTRIES = 'entries';

var returnThis$2 = function () {
  return this;
};

var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
  createIteratorConstructor(IteratorConstructor, NAME, next);

  var getIterationMethod = function (KIND) {
    if (KIND === DEFAULT && defaultIterator) return defaultIterator;
    if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];

    switch (KIND) {
      case KEYS:
        return function keys() {
          return new IteratorConstructor(this, KIND);
        };

      case VALUES:
        return function values() {
          return new IteratorConstructor(this, KIND);
        };

      case ENTRIES:
        return function entries() {
          return new IteratorConstructor(this, KIND);
        };
    }

    return function () {
      return new IteratorConstructor(this);
    };
  };

  var TO_STRING_TAG = NAME + ' Iterator';
  var INCORRECT_VALUES_NAME = false;
  var IterablePrototype = Iterable.prototype;
  var nativeIterator = IterablePrototype[ITERATOR$1] || IterablePrototype['@@iterator'] || DEFAULT && IterablePrototype[DEFAULT];
  var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
  var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
  var CurrentIteratorPrototype, methods, KEY; // fix native

  if (anyNativeIterator) {
    CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));

    if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) {
      if ( objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) {
        if (objectSetPrototypeOf) {
          objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2);
        } else if (typeof CurrentIteratorPrototype[ITERATOR$1] != 'function') {
          createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$1, returnThis$2);
        }
      } // Set @@toStringTag to native iterators


      setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
    }
  } // fix Array#{values, @@iterator}.name in V8 / FF


  if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
    INCORRECT_VALUES_NAME = true;

    defaultIterator = function values() {
      return nativeIterator.call(this);
    };
  } // define iterator


  if ( IterablePrototype[ITERATOR$1] !== defaultIterator) {
    createNonEnumerableProperty(IterablePrototype, ITERATOR$1, defaultIterator);
  }

  iterators[NAME] = defaultIterator; // export additional methods

  if (DEFAULT) {
    methods = {
      values: getIterationMethod(VALUES),
      keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
      entries: getIterationMethod(ENTRIES)
    };
    if (FORCED) for (KEY in methods) {
      if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
        redefine(IterablePrototype, KEY, methods[KEY]);
      }
    } else _export({
      target: NAME,
      proto: true,
      forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME
    }, methods);
  }

  return methods;
};

var ARRAY_ITERATOR = 'Array Iterator';
var setInternalState$1 = internalState.set;
var getInternalState$1 = internalState.getterFor(ARRAY_ITERATOR); // `Array.prototype.entries` method
// https://tc39.github.io/ecma262/#sec-array.prototype.entries
// `Array.prototype.keys` method
// https://tc39.github.io/ecma262/#sec-array.prototype.keys
// `Array.prototype.values` method
// https://tc39.github.io/ecma262/#sec-array.prototype.values
// `Array.prototype[@@iterator]` method
// https://tc39.github.io/ecma262/#sec-array.prototype-@@iterator
// `CreateArrayIterator` internal method
// https://tc39.github.io/ecma262/#sec-createarrayiterator

var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
  setInternalState$1(this, {
    type: ARRAY_ITERATOR,
    target: toIndexedObject(iterated),
    // target
    index: 0,
    // next index
    kind: kind // kind

  }); // `%ArrayIteratorPrototype%.next` method
  // https://tc39.github.io/ecma262/#sec-%arrayiteratorprototype%.next
}, function () {
  var state = getInternalState$1(this);
  var target = state.target;
  var kind = state.kind;
  var index = state.index++;

  if (!target || index >= target.length) {
    state.target = undefined;
    return {
      value: undefined,
      done: true
    };
  }

  if (kind == 'keys') return {
    value: index,
    done: false
  };
  if (kind == 'values') return {
    value: target[index],
    done: false
  };
  return {
    value: [index, target[index]],
    done: false
  };
}, 'values'); // argumentsList[@@iterator] is %ArrayProto_values%
// https://tc39.github.io/ecma262/#sec-createunmappedargumentsobject
// https://tc39.github.io/ecma262/#sec-createmappedargumentsobject

iterators.Arguments = iterators.Array; // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables

addToUnscopables('keys');
addToUnscopables('values');
addToUnscopables('entries');

var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
var test = {};
test[TO_STRING_TAG$1] = 'z';
var toStringTagSupport = String(test) === '[object z]';

var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag'); // ES3 wrong here

var CORRECT_ARGUMENTS = classofRaw(function () {
  return arguments;
}()) == 'Arguments'; // fallback for IE11 Script Access Denied error

var tryGet = function (it, key) {
  try {
    return it[key];
  } catch (error) {
    /* empty */
  }
}; // getting tag from ES6+ `Object.prototype.toString`


var classof = toStringTagSupport ? classofRaw : function (it) {
  var O, tag, result;
  return it === undefined ? 'Undefined' : it === null ? 'Null' // @@toStringTag case
  : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag // builtinTag case
  : CORRECT_ARGUMENTS ? classofRaw(O) // ES3 arguments fallback
  : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
};

// https://tc39.github.io/ecma262/#sec-object.prototype.tostring


var objectToString = toStringTagSupport ? {}.toString : function toString() {
  return '[object ' + classof(this) + ']';
};

// https://tc39.github.io/ecma262/#sec-object.prototype.tostring

if (!toStringTagSupport) {
  redefine(Object.prototype, 'toString', objectToString, {
    unsafe: true
  });
}

var MATCH = wellKnownSymbol('match'); // `IsRegExp` abstract operation
// https://tc39.github.io/ecma262/#sec-isregexp

var isRegexp = function (it) {
  var isRegExp;
  return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
};

var notARegexp = function (it) {
  if (isRegexp(it)) {
    throw TypeError("The method doesn't accept regular expressions");
  }

  return it;
};

var MATCH$1 = wellKnownSymbol('match');

var correctIsRegexpLogic = function (METHOD_NAME) {
  var regexp = /./;

  try {
    '/./'[METHOD_NAME](regexp);
  } catch (e) {
    try {
      regexp[MATCH$1] = false;
      return '/./'[METHOD_NAME](regexp);
    } catch (f) {
      /* empty */
    }
  }

  return false;
};

// https://tc39.github.io/ecma262/#sec-string.prototype.includes


_export({
  target: 'String',
  proto: true,
  forced: !correctIsRegexpLogic('includes')
}, {
  includes: function includes(searchString
  /* , position = 0 */
  ) {
    return !!~String(requireObjectCoercible(this)).indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined);
  }
});

var createMethod$3 = function (CONVERT_TO_STRING) {
  return function ($this, pos) {
    var S = String(requireObjectCoercible($this));
    var position = toInteger(pos);
    var size = S.length;
    var first, second;
    if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
    first = S.charCodeAt(position);
    return first < 0xD800 || first > 0xDBFF || position + 1 === size || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF ? CONVERT_TO_STRING ? S.charAt(position) : first : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
  };
};

var stringMultibyte = {
  // `String.prototype.codePointAt` method
  // https://tc39.github.io/ecma262/#sec-string.prototype.codepointat
  codeAt: createMethod$3(false),
  // `String.prototype.at` method
  // https://github.com/mathiasbynens/String.prototype.at
  charAt: createMethod$3(true)
};

var charAt = stringMultibyte.charAt;
var STRING_ITERATOR = 'String Iterator';
var setInternalState$2 = internalState.set;
var getInternalState$2 = internalState.getterFor(STRING_ITERATOR); // `String.prototype[@@iterator]` method
// https://tc39.github.io/ecma262/#sec-string.prototype-@@iterator

defineIterator(String, 'String', function (iterated) {
  setInternalState$2(this, {
    type: STRING_ITERATOR,
    string: String(iterated),
    index: 0
  }); // `%StringIteratorPrototype%.next` method
  // https://tc39.github.io/ecma262/#sec-%stringiteratorprototype%.next
}, function next() {
  var state = getInternalState$2(this);
  var string = state.string;
  var index = state.index;
  var point;
  if (index >= string.length) return {
    value: undefined,
    done: true
  };
  point = charAt(string, index);
  state.index += point.length;
  return {
    value: point,
    done: false
  };
});

// iterable DOM collections
// flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
var domIterables = {
  CSSRuleList: 0,
  CSSStyleDeclaration: 0,
  CSSValueList: 0,
  ClientRectList: 0,
  DOMRectList: 0,
  DOMStringList: 0,
  DOMTokenList: 1,
  DataTransferItemList: 0,
  FileList: 0,
  HTMLAllCollection: 0,
  HTMLCollection: 0,
  HTMLFormElement: 0,
  HTMLSelectElement: 0,
  MediaList: 0,
  MimeTypeArray: 0,
  NamedNodeMap: 0,
  NodeList: 1,
  PaintRequestList: 0,
  Plugin: 0,
  PluginArray: 0,
  SVGLengthList: 0,
  SVGNumberList: 0,
  SVGPathSegList: 0,
  SVGPointList: 0,
  SVGStringList: 0,
  SVGTransformList: 0,
  SourceBufferList: 0,
  StyleSheetList: 0,
  TextTrackCueList: 0,
  TextTrackList: 0,
  TouchList: 0
};

var ITERATOR$2 = wellKnownSymbol('iterator');
var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
var ArrayValues = es_array_iterator.values;

for (var COLLECTION_NAME in domIterables) {
  var Collection = global_1[COLLECTION_NAME];
  var CollectionPrototype = Collection && Collection.prototype;

  if (CollectionPrototype) {
    // some Chrome versions have non-configurable methods on DOMTokenList
    if (CollectionPrototype[ITERATOR$2] !== ArrayValues) try {
      createNonEnumerableProperty(CollectionPrototype, ITERATOR$2, ArrayValues);
    } catch (error) {
      CollectionPrototype[ITERATOR$2] = ArrayValues;
    }

    if (!CollectionPrototype[TO_STRING_TAG$3]) {
      createNonEnumerableProperty(CollectionPrototype, TO_STRING_TAG$3, COLLECTION_NAME);
    }

    if (domIterables[COLLECTION_NAME]) for (var METHOD_NAME in es_array_iterator) {
      // some Chrome versions have non-configurable methods on DOMTokenList
      if (CollectionPrototype[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
        createNonEnumerableProperty(CollectionPrototype, METHOD_NAME, es_array_iterator[METHOD_NAME]);
      } catch (error) {
        CollectionPrototype[METHOD_NAME] = es_array_iterator[METHOD_NAME];
      }
    }
  }
}

// 辞書は二分探索木により実現している
// 二分探索木の挿入・削除操作は2色木で実装している
// 2色木のアルゴリズムは近代科学社の「アルゴリズムイントロダクション第3版」(以降 IA3) を参考にした

/**
 * @summary 2色木の番兵 (T.nil)
 *
 * @desc
 * <p>根の親、葉の子、または空辞書の root を表現する。</p>
 *
 * @see IA3/13.1 2色木の性質
 *
 * @private
 */
var T_nil;
/**
 * @summary 順序あり辞書
 *
 * @classdesc
 * <p>キーの値により順序付けされる辞書である。</p>
 * <p>等価 (equivalent) キーを持つ複数のアイテムは存在できない。</p>
 * <p>this はキーと値の参照を保有している。保有しているキーのインスタンスを変更すると動作は保証されない。</p>
 *
 * @memberof mapray
 * @private
 */

var OrderedMap =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.OrderedMap.Compare} compare  キー比較関数
   */
  function OrderedMap(compare) {
    _classCallCheck(this, OrderedMap);

    this._compare = compare;
    this._root = T_nil;
    this._size = 0;
  }
  /**
   * @summary 要素数
   *
   * @type {number}
   * @readonly
   */


  _createClass(OrderedMap, [{
    key: "clone",

    /**
     * @summary インスタンスを複製
     *
     * @desc
     * <p>キー比較関数、キー、値はシャローコピーされる。<p>
     *
     * <p>計算量: 要素数 n に対して O(n)</p>
     *
     * @return {mapray.OrderedMap}  this の複製
     */
    value: function clone() {
      var cloned = new OrderedMap(this._compare);

      if (this._root !== T_nil) {
        cloned._root = this._root._clone(T_nil);
      }

      cloned._size = this._size;
      return cloned;
    }
    /**
     * @summary 要素は存在しないか?
     *
     * <p>計算量: 要素数 n に対して O(1)</p>
     *
     * @return {boolean}  要素が存在しないとき true, そうでないとき false
     */

  }, {
    key: "isEmpty",
    value: function isEmpty() {
      return this._root === T_nil;
    }
    /**
     * @summary 先頭要素を検索
     *
     * @desc
     * <p>順序が最初の要素を検索する。</p>
     *
     * <p>計算量: 要素数 n に対して O(log n)</p>
     *
     * @return {!mapray.OrderedMap.Item}  検索されたアイテム (this が空なら null)
     */

  }, {
    key: "findFirst",
    value: function findFirst() {
      if (this._root !== T_nil) {
        return this._root._findMinimum();
      } else {
        return null;
      }
    }
    /**
     * @summary 末尾要素を検索
     *
     * @desc
     * <p>順序が最後の要素を検索する。</p>
     *
     * <p>計算量: 要素数 n に対して O(log n)</p>
     *
     * @return {!mapray.OrderedMap.Item}  検索されたアイテム (this が空なら null)
     */

  }, {
    key: "findLast",
    value: function findLast() {
      if (this._root !== T_nil) {
        return this._root._findMaximum();
      } else {
        return null;
      }
    }
    /**
     * @summary 下限要素を検索
     *
     * @desc
     * <p>bound と同じまたは後になるキーが存在すれば、その中で最初の要素を返す。</p>
     * <p>そのような要素が存在しない場合は null を返す。</p>
     *
     * <p>計算量: 要素数 n に対して O(log n)</p>
     *
     * @param {mapray.OrderedMap.Key} bound  境界キー
     *
     * @return {?mapray.OrderedMap.Item}  検索された要素、存在しなければ null
     */

  }, {
    key: "findLower",
    value: function findLower(bound) {
      return this._root._findLowerBound(bound, this._compare);
    }
    /**
     * @summary 上限要素を検索
     *
     * @desc
     * <p>bound より後になるキーが存在すれば、その中で最初の要素を返す。</p>
     * <p>そのような要素が存在しない場合は null を返す。</p>
     *
     * <p>計算量: 要素数 n に対して O(log n)</p>
     *
     * @param {mapray.OrderedMap.Key} bound  境界キー
     *
     * @return {?mapray.OrderedMap.Item}  検索された要素、存在しなければ null
     */

  }, {
    key: "findUpper",
    value: function findUpper(bound) {
      return this._root._findUpperBound(bound, this._compare);
    }
    /**
     * @summary 要素を検索
     *
     * @desc
     * <p>key と同じキーの要素が存在すれば返す。</p>
     * <p>そのような要素が存在しない場合は null を返す。</p>
     *
     * <p>計算量: 要素数 n に対して O(log n)</p>
     *
     * @param {mapray.OrderedMap.Key} key  キー
     *
     * @return {?mapray.OrderedMap.Item}  検索された要素、存在しなければ null
     */

  }, {
    key: "findEqual",
    value: function findEqual(key) {
      return this._root._findEqual(key, this._compare);
    }
    /**
     * @summary すべての要素を削除
     *
     * @desc
     * <p>計算量: 要素数 n に対して O(1)</p>
     */

  }, {
    key: "clear",
    value: function clear() {
      this._root = T_nil;
      this._size = 0;
    }
    /**
     * @summary 要素を挿入
     *
     * @desc
     * <p>キーを key として value を挿入し、そのアイテムを返す。</p>
     *
     * <p>計算量: 要素数 n に対して O(log n)</p>
     *
     * @param {mapray.OrderedMap.Key}   key    キー
     * @param {mapray.OrderedMap.Value} value  値
     *
     * @return {mapray.OrderedMap.Item}  挿入された要素
     */

  }, {
    key: "insert",
    value: function insert(key, value) {
      // 参照: IA3/13.3 挿入
      var trail = this._root;
      var parent = T_nil;
      var comp = this._compare;

      while (trail !== T_nil) {
        parent = trail;

        if (comp(key, trail.key)) {
          // 左へ下る
          trail = trail._child_L;
        } else if (comp(trail.key, key)) {
          // 右へ下る
          trail = trail._child_R;
        } else {
          // キーが一致したアイテムの値を更新して返す
          trail._value = value;
          return trail;
        }
      } // 新しいアイテムを追加


      var item = new Item(parent, key, value);
      item._is_red = true; // 黒 → 赤

      if (parent === T_nil) {
        this._root = item;
      } else if (comp(key, parent.key)) {
        parent._child_L = item;
      } else {
        parent._child_R = item;
      } // 要素数を増加


      ++this._size; // 2色木条件の回復

      this._insert_fixup(item);

      return item;
    }
    /**
     * @summary 挿入後に2色木条件を満たすように木を修正
     *
     * @desc
     * <p>計算量: 要素数 n に対して最悪 O(log n)</p>
     *
     * @param {mapray.OrderedMap.Item} item  挿入されたアイテム
     *
     * @see IA3/13.3 挿入
     *
     * @private
     */

  }, {
    key: "_insert_fixup",
    value: function _insert_fixup(item) {
      var trail = item;

      while (trail._parent._is_red
      /* 赤 */
      ) {
        // ここでは、常に不変式 a, b, c を満たす
        if (trail._parent === trail._parent._parent._child_L) {
          // trail の親が祖父の左側
          var uncle = trail._parent._parent._child_R;

          if (uncle._is_red
          /* 赤 */
          ) {
              // 場合 1
              trail._parent._is_red = false; // 黒

              uncle._is_red = false; // 黒

              trail._parent._parent._is_red = true; // 赤

              trail = trail._parent._parent;
            } else {
            if (trail === trail._parent._child_R) {
              // 場合 2
              trail = trail._parent;

              this._rotate_L(trail);
            } // 場合 2,3


            trail._parent._is_red = false; // 黒

            trail._parent._parent._is_red = true; // 赤

            this._rotate_R(trail._parent._parent);
          }
        } else {
          // trail の親が祖父の右側
          var _uncle = trail._parent._parent._child_L;

          if (_uncle._is_red
          /* 赤 */
          ) {
              // 場合 1
              trail._parent._is_red = false; // 黒

              _uncle._is_red = false; // 黒

              trail._parent._parent._is_red = true; // 赤

              trail = trail._parent._parent;
            } else {
            if (trail === trail._parent._child_L) {
              // 場合 2
              trail = trail._parent;

              this._rotate_R(trail);
            } // 場合 2,3


            trail._parent._is_red = false; // 黒

            trail._parent._parent._is_red = true; // 赤

            this._rotate_L(trail._parent._parent);
          }
        }
      }

      this._root._is_red = false; // 黒
      // ここで2色木条件を完全に満たす
    }
    /**
     * @summary 要素を削除
     *
     * @desc
     * <p>last を省略したときは first を削除して、first の後続を返す。このとき first に null
     *    を指定することはできない。</p>
     *
     * <p>last を指定したときは first から last の前までの要素を削除して last を返す。last は
     *    first と同じか後の要素でなければならない。</p>
     *
     * <p>null は this の末尾要素の次の要素を表す。</p>
     *
     * <p>計算量: 1 要素の削除の場合、要素数 n に対して O(log n)</p>
     *
     * todo: 複数要素の削除の計算量を分析
     *
     * @param {?mapray.OrderedMap.Item} first   削除する先頭の要素
     * @param {?mapray.OrderedMap.Item} [last]  削除する最後の要素の次
     *
     * @return {?mapray.OrderedMap.Item}  削除された要素の次の要素
     *
     * @private
     */

  }, {
    key: "remove",
    value: function remove(first, last) {
      if (last === undefined) {
        return this._remove(first);
      } else {
        for (var item = first; item != last;) {
          item = this._remove(item);
        }

        return last;
      }
    }
    /**
     * @summary アイテムを削除
     *
     * @desc
     * <p>計算量: 全体ツリーのアイテム数 n に対して最悪 O(log n)</p>
     *
     * @param {mapray.OrderedMap.Item} item  削除対象
     *
     * @return {?mapray.OrderedMap.Item}  item の後続、存在しなければ null
     *
     * @see IA3/13.4 削除
     *
     * @private
     */

  }, {
    key: "_remove",
    value: function _remove(item) {
      // item の後続 (無ければ null)
      var succ = item.findSuccessor();
      var orgY_is_red;
      var x_item;

      if (item._child_L === T_nil) {
        // (a) 左側なし
        orgY_is_red = item._is_red;
        x_item = item._child_R;

        this._replace(item._child_R, item);
      } else if (item._child_R === T_nil) {
        // (b) 右側なし (左側あり)
        orgY_is_red = item._is_red;
        x_item = item._child_L;

        this._replace(item._child_L, item);
      } else {
        // 左右あり
        orgY_is_red = succ._is_red;
        x_item = succ._child_R;

        if (succ._parent === item) {
          // (c) item の後続が item の右の子
          // x_item が T_nil であっても親を設定
          x_item._parent = succ;
        } else {
          // (d) item の後続が item の右の子の左側
          this._replace(succ._child_R, succ);

          succ._child_R = item._child_R;
          succ._child_R._parent = succ;
        } // (c), (d)


        this._replace(succ, item);

        succ._child_L = item._child_L;
        succ._child_L._parent = succ;
        succ._is_red = item._is_red;
      } // 要素数を減少


      --this._size;

      if (!orgY_is_red
      /* 黒 */
      ) {
          // 2色木条件の回復
          this._remove_fixup(x_item);
        }

      return succ;
    }
    /**
     * @summary 削除後に2色木条件を満たすように木を修正
     *
     * @param {mapray.OrderedMap.Item} x_item
     *
     * @see IA3/13.4 削除
     *
     * @private
     */

  }, {
    key: "_remove_fixup",
    value: function _remove_fixup(x_item) {
      var trail = x_item;

      while (trail !== this._root && !trail._is_red
      /* 黒 */
      ) {
        if (trail === trail._parent._child_L) {
          // trail は親の左側
          var sibling = trail._parent._child_R;

          if (sibling._is_red
          /* 赤 */
          ) {
              // 場合 1
              sibling._is_red = false; // 黒

              trail._parent._is_red = true; // 赤

              this._rotate_L(trail._parent);

              sibling = trail._parent._child_R;
            }

          if (!sibling._child_L._is_red
          /* 黒 */
          && !sibling._child_R._is_red
          /* 黒 */
          ) {
              // 場合 2
              sibling._is_red = true; // 赤

              trail = trail._parent;
            } else {
            if (!sibling._child_R._is_red
            /* 黒 */
            ) {
                // 場合 3
                sibling._child_L._is_red = false; // 黒

                sibling._is_red = true; // 赤

                this._rotate_R(sibling);

                sibling = trail._parent._child_R;
              } // 場合 3,4


            sibling._is_red = trail._parent._is_red;
            trail._parent._is_red = false; // 黒

            sibling._child_R._is_red = false; // 黒

            this._rotate_L(trail._parent);

            trail = this._root;
          }
        } else {
          // trail は親の右側
          var _sibling = trail._parent._child_L;

          if (_sibling._is_red
          /* 赤 */
          ) {
              // 場合 1
              _sibling._is_red = false; // 黒

              trail._parent._is_red = true; // 赤

              this._rotate_R(trail._parent);

              _sibling = trail._parent._child_L;
            }

          if (!_sibling._child_R._is_red
          /* 黒 */
          && !_sibling._child_L._is_red
          /* 黒 */
          ) {
              // 場合 2
              _sibling._is_red = true; // 赤

              trail = trail._parent;
            } else {
            if (!_sibling._child_L._is_red
            /* 黒 */
            ) {
                // 場合 3
                _sibling._child_R._is_red = false; // 黒

                _sibling._is_red = true; // 赤

                this._rotate_L(_sibling);

                _sibling = trail._parent._child_L;
              } // 場合 3,4


            _sibling._is_red = trail._parent._is_red;
            trail._parent._is_red = false; // 黒

            _sibling._child_L._is_red = false; // 黒

            this._rotate_R(trail._parent);

            trail = this._root;
          }
        }
      }

      trail._is_red = false; // 黒
    }
    /**
     * @summary アイテムの置き換え
     *
     * @desc
     * <p>dst の場所を src アイテムで置き換える。src が T_nil のときは dst の場所は葉になる。</p>
     * <p>dst の親の左または右の子供 (または this._root) と src._parent は変更されるが、dst
     *    自身の内容は変更されない。</p>
     *
     * @param {mapray.OrderedMap.Item} src
     * @param {mapray.OrderedMap.Item} dst
     *
     * @private
     */

  }, {
    key: "_replace",
    value: function _replace(src, dst) {
      var dp = dst._parent;

      if (dp !== T_nil) {
        if (dp._child_L === dst) {
          // dst は dp の左側
          dp._child_L = src;
        } else {
          // dst は dp の右側
          dp._child_R = src;
        }
      } else {
        // dst は最上位
        this._root = src;
      } // src の親を変更


      src._parent = dp;
    }
    /**
     * @summary アイテムを左回転
     *
     * 計算量: O(1)
     *
     * @see IA3/13.2 回転
     *
     * @param {mapray.OrderedMap.Item} pivot  回転中心のアイテム
     *
     * @private
     */

  }, {
    key: "_rotate_L",
    value: function _rotate_L(pivot) {
      // next は回転後に pivot の位置になる
      var next = pivot._child_R; // pivot の右側を next の左側に設定

      pivot._child_R = next._child_L;

      if (next._child_L !== T_nil) {
        next._child_L._parent = pivot;
      } // next の親を pivot の元の親に設定


      next._parent = pivot._parent;

      if (pivot._parent === T_nil) {
        this._root = next;
      } else if (pivot === pivot._parent._child_L) {
        pivot._parent._child_L = next;
      } else {
        pivot._parent._child_R = next;
      } // next の左側を pivot に設定


      next._child_L = pivot;
      pivot._parent = next;
    }
    /**
     * @summary アイテムを右回転
     *
     * 計算量: O(1)
     *
     * @see IA3/13.2 回転
     *
     * @param {mapray.OrderedMap.Item} pivot  回転中心のアイテム
     *
     * @private
     */

  }, {
    key: "_rotate_R",
    value: function _rotate_R(pivot) {
      // next は回転後に pivot の位置になる
      var next = pivot._child_L; // pivot の左側を next の右側に設定

      pivot._child_L = next._child_R;

      if (next._child_R !== T_nil) {
        next._child_R._parent = pivot;
      } // next の親を pivot の元の親に設定


      next._parent = pivot._parent;

      if (pivot._parent === T_nil) {
        this._root = next;
      } else if (pivot === pivot._parent._child_R) {
        pivot._parent._child_R = next;
      } else {
        pivot._parent._child_L = next;
      } // next の右側を pivot に設定


      next._child_R = pivot;
      pivot._parent = next;
    }
  }, {
    key: "size",
    get: function get() {
      return this._size;
    }
  }]);

  return OrderedMap;
}();
/**
 * @summary OrderedMap のアイテム
 *
 * @classdesc
 * <p>すべての this._child_L のアイテム L に対して Compare( L._key, this._key ) が成り立つ。</p>
 * <p>すべての this._child_R のアイテム R に対して Compare( this._key, R._key ) が成り立つ。</p>
 *
 * @memberof mapray.OrderedMap
 * @private
 */


var Item =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>色は黒に設定される。</p>
   *
   * @param {mapray.OrderedMap.Item}  parent  親アイテム
   * @param {mapray.OrderedMap.Key}   key     アイテムのキー
   * @param {mapray.OrderedMap.Value} value   アイテムの値
   */
  function Item(parent, key, value) {
    _classCallCheck(this, Item);

    this._parent = parent;
    this._child_L = T_nil; // 左側ツリー

    this._child_R = T_nil; // 右側ツリー

    this._is_red = false; // 色: 黒=false, 赤=true

    this._key = key;
    this._value = value;
  }
  /**
   * @summary キー
   *
   * @type {mapray.OrderedMap.Key}
   * @readonly
   */


  _createClass(Item, [{
    key: "_clone",

    /**
     * @summary インスタンスを複製
     *
     * @desc
     * <p>キー、値はシャローコピーされる。<p>
     *
     * @param {mapray.OrderedMap.Item} parant  親アイテム (this が根のときは T_nil)
     *
     * @return {mapray.OrderedMap.Item}  this の複製
     *
     * @private
     */
    value: function _clone(parent) {
      // 子孫と色以外を複製
      var cloned = new Item(parent, this._key, this._value); // 左側子孫を複製

      if (this._child_L !== T_nil) {
        cloned._child_L = this._child_L._clone(cloned);
      } // 右側子孫を複製


      if (this._child_R !== T_nil) {
        cloned._child_R = this._child_R._clone(cloned);
      } // 色を複製


      cloned._is_red = this._is_red;
      return cloned;
    }
    /**
     * @summary 先頭アイテムの検索
     *
     * @desc
     * <p>this ツリーの中で最も先の順序のアイテムを検索する。</p>
     *
     * <p>計算量: this ツリーのアイテム数 n に対して O(log n)</p>
     *
     * @return {mapray.OrderedMap.Item}  検索されたアイテム
     *
     * @private
     */

  }, {
    key: "_findMinimum",
    value: function _findMinimum() {
      var item = this; // 追跡ポインタ

      while (item._child_L !== T_nil) {
        item = item._child_L;
      }

      return item;
    }
    /**
     * @summary 後尾アイテムの検索
     *
     * @desc
     * <p>this ツリーの中で最も後の順序のアイテムを検索する。</p>
     *
     * <p>計算量: this ツリーのアイテム数 n に対して O(log n)</p>
     *
     * @return {mapray.OrderedMap.Item}  検索されたアイテム
     *
     * @private
     */

  }, {
    key: "_findMaximum",
    value: function _findMaximum() {
      var item = this; // 追跡ポインタ

      while (item._child_R !== T_nil) {
        item = item._child_R;
      }

      return item;
    }
    /**
     * @summary 前のアイテムの検索
     *
     * @desc
     * <p>root ツリーから this の前の順序のアイテムを検索する。this が先頭なら null を返す。</p>
     *
     * <p>計算量: 辞書の要素数 n に対して最悪 O(log n)</p>
     * <p>todo: 平均計算量を分析する</p>
     *
     * @return {?mapray.OrderedMap.Item}  検索されたアイテム、存在しなければ null
     */

  }, {
    key: "findPredecessor",
    value: function findPredecessor() {
      // 左側子孫がいれば、左側子孫の後尾
      if (this._child_L !== T_nil) {
        return this._child_L._findMaximum();
      } // 左側子孫がいなければ、this を右側子孫として持つ最も近い祖先
      // それがなければ this は全体ツリーの先頭なので検索失敗


      var item = this;
      var parent = item._parent;

      while (parent !== T_nil && item === parent._child_L) {
        item = parent;
        parent = item._parent;
      }

      return parent !== T_nil ? parent : null;
    }
    /**
     * @summary 次のアイテムの検索
     *
     * @desc
     * <p>root ツリーから this の次の順序のアイテムを検索する。this が後尾なら null を返す。</p>
     *
     * <p>計算量: 辞書の要素数 n に対して最悪 O(log n)</p>
     * <p>todo: 平均計算量を分析する</p>
     *
     * @return {?mapray.OrderedMap.Item}  検索されたアイテム、存在しなければ null
     */

  }, {
    key: "findSuccessor",
    value: function findSuccessor() {
      // 右側子孫がいれば、右側子孫の先頭
      if (this._child_R !== T_nil) {
        return this._child_R._findMinimum();
      } // 右側子孫がいなければ、this を左側子孫として持つ最も近い祖先
      // それがなければ this は全体ツリーの後尾なので検索失敗


      var item = this;
      var parent = item._parent;

      while (parent !== T_nil && item === parent._child_R) {
        item = parent;
        parent = item._parent;
      }

      return parent !== T_nil ? parent : null;
    }
    /**
     * @summary 下限アイテムを検索
     *
     * @desc
     * <p>this ツリーの中で !comp(item.key, bkey) となる最初のアイテムを検索する。</p>
     * <p>つまり bkey と同じまたは後になるキーが this ツリーに存在すれば、その中で最初のアイテムを返す。</p>
     * <p>そのようなアイテムが存在しない場合は null を返す。</p>
     * <p>this が T_nil の場合は null を返す。</p>
     *
     * <p>計算量: this ツリーのアイテム数 n に対して最悪 O(log n)</p>
     *
     * @param {mapray.OrderedMap.Key}     bkey  境界キー
     * @param {mapray.OrderedMap.Compare} comp  キー比較関数
     *
     * @return {?mapray.OrderedMap.Item}  検索されたアイテム、存在しなければ null
     *
     * @private
     */

  }, {
    key: "_findLowerBound",
    value: function _findLowerBound(bkey, comp) {
      var item = this;

      while (item !== T_nil) {
        if (comp(bkey, item._key)) {
          // bkey < item.key
          if (item._child_L !== T_nil) {
            var found = item._child_L._findLowerBound(bkey, comp);

            if (found !== null) return found;
          }

          return item;
        } else if (comp(item._key, bkey)) {
          // bkey > item.key
          item = item._child_R;
        } else {
          // bkey == item.key (等価)
          return item;
        }
      }

      return null;
    }
    /**
     * @summary 上限アイテムを検索
     *
     * @desc
     * <p>this ツリーの中で comp(bkey, item.key) となる最初のアイテムを検索する。</p>
     * <p>つまり bkey より後になるキーが this ツリーに存在すれば、その中で最初のアイテムを返す。</p>
     * <p>そのようなアイテムが存在しない場合は null を返す。</p>
     * <p>this が T_nil の場合は null を返す。</p>
     *
     * <p>計算量: this ツリーのアイテム数 n に対して最悪 O(log n)</p>
     *
     * @param {mapray.OrderedMap.Key}     bkey  境界キー
     * @param {mapray.OrderedMap.Compare} comp  キー比較関数
     *
     * @return {?mapray.OrderedMap.Item}  検索されたアイテム、存在しなければ null
     *
     * @private
     */

  }, {
    key: "_findUpperBound",
    value: function _findUpperBound(bkey, comp) {
      var item = this;

      while (item !== T_nil) {
        if (comp(bkey, item._key)) {
          // bkey < item.key
          if (item._child_L !== T_nil) {
            var found = item._child_L._findUpperBound(bkey, comp);

            if (found !== null) return found;
          }

          return item;
        } else {
          // bkey >= item.key
          item = item._child_R;
        }
      }

      return null;
    }
    /**
     * @summary 等価キーのアイテムを検索
     *
     * @desc
     * <p>this ツリーの中で !comp(key, item.key) かつ !comp(item.key, key) となるアイテムを検索する。</p>
     * <p>そのようなアイテムが存在しない場合は null を返す。</p>
     * <p>this == T_nil の場合は null を返す。</p>
     *
     * <p>計算量: this ツリーのアイテム数 n に対して最悪 O(log n)</p>
     *
     * @param {mapray.OrderedMap.Key}     key   キー
     * @param {mapray.OrderedMap.Compare} comp  キー比較関数
     *
     * @return {?mapray.OrderedMap.Item}  検索されたアイテム、存在しなければ null
     *
     * @private
     */

  }, {
    key: "_findEqual",
    value: function _findEqual(key, comp) {
      var item = this;

      while (item !== T_nil) {
        if (comp(key, item._key)) {
          // key < item.key
          item = item._child_L;
        } else if (comp(item._key, key)) {
          // bkey > item.key
          item = item._child_R;
        } else {
          // bkey == item.key (等価)
          return item;
        }
      }

      return null;
    }
    /**
     * @summary 下限アイテムを検索 (検討中)
     *
     * @desc
     * <p>root ツリーの中で !comp(item.key, bkey) となる最初のアイテムを検索する。</p>
     * <p>つまり bkey と同じまたは後になるキーが root ツリーに存在すれば、その中で最初のアイテムを返す。</p>
     * <p>そのようなアイテムが存在しない場合は null を返す。</p>
     *
     * <p>計算量: root ツリーのアイテム数 n に対して最悪 O(log^2 n)</p>
     *
     * @param {mapray.OrderedMap.Key}     bkey  境界キー
     * @param {mapray.OrderedMap.Compare} comp  キー比較関数
     *
     * @return {?mapray.OrderedMap.Item}  検索されたアイテム、存在しなければ null
     *
     * @private
     */

  }, {
    key: "_findLowerBoundR",
    value: function _findLowerBoundR(bkey, comp) {
      var item = this;

      if (item._parent !== T_nil) {
        // item == root
        return item._findLowerBound(bkey, comp);
      }

      var imin = item._findMinimum();

      var imax = item._findMaximum();

      do {
        if (!comp(bkey, imin._key) && !comp(imax._key, bkey)) {
          // imin <= bkey <= imax なので
          // item._findLowerBound() で必ず見つかる
          break;
        }

        if (item._parent._child_L === item) {
          // item は parent の左側なので、登ると imax のみが変化
          imax = item._findMaximum();
        } else {
          // item は parent の右側なので、登ると imin のみが変化
          imin = item._findMinimum();
        } // item は登る


        item = item._parent;
      } while (item._parent !== T_nil); // item == root


      return item._findLowerBound(bkey, comp);
    }
  }, {
    key: "key",
    get: function get() {
      return this._key;
    }
    /**
     * @summary 値
     *
     * @type {mapray.OrderedMap.Value}
     * @readonly
     */

  }, {
    key: "value",
    get: function get() {
      return this._value;
    }
  }]);

  return Item;
}(); // 番兵を生成


T_nil = new Item();

/**
 * @summary アニメーション関数値の不変性情報
 *
 * @classdesc
 * <p>Curve のサブクラスの実装者が、アニメーション関数値が一定となる時刻区間を表明するために利用するクラスである。</p>
 *
 * @see {@link mapray.animation.Curve#getInvariance}
 *
 * @memberof mapray.animation
 */

var Invariance =
/*#__PURE__*/
function () {
  function Invariance() {
    _classCallCheck(this, Invariance);

    this._imap = createEmptyMap();
  }
  /**
   * @summary 複製を取得
   *
   * @desc
   * <p>this と同じ内容のインスタンスを生成する。</p>
   *
   * <p>計算量: 時刻区間数 n に対して O(n)</p>
   *
   * @return {mapray.animation.Invariance}  this の複製
   */


  _createClass(Invariance, [{
    key: "clone",
    value: function clone() {
      var cloned = new Invariance(); // Time と Interval はイミュータブルなのでシャローコピーで十分

      cloned._imap = this._imap.clone();
      return cloned;
    }
    /**
     * @summary 同一値の時刻区間を上書き
     *
     * @desc
     * <p>this が持っているすべての同一値時刻区間に interval の時刻区間部分を上書きする。</p>
     *
     * <p>イメージ的には interval 部分に毎回新しい色を重ねていく。最終的にできた各色の区間を同一値の時刻区間と見なす。</p>
     *
     * @param {mapray.animation.Interval} interval  同一値を持つ時刻区間
     *
     * @return {mapray.animation.Invariance}  this
     */

  }, {
    key: "write",
    value: function write(interval) {
      // todo: 計算量を分析 (remove() に依存)
      this.remove(interval);

      this._insert(interval);

      return this;
    }
    /**
     * @summary 時刻区間の消去
     *
     * @desc
     * <p>this が持っているすべての同一値時刻区間から interval の時刻区間部分を消去する。</p>
     *
     * <p>イメージ的には {@link mapray.animation.Invariance#write write()} で重ねた色の
     *    interval 部分を透明にする。</p>
     *
     * @param {mapray.animation.Interval} interval  時刻区間
     *
     * @return {mapray.animation.Invariance}  this
     */

  }, {
    key: "remove",
    value: function remove(interval) {
      // todo: 計算量を分析 (OrderMap#remove() に依存)
      if (interval.isEmpty()) {
        // 空時刻区間の消去は変化なし
        return this;
      } // interval.lower 半区間に内包される最初の要素 (無ければ null)


      var fit = interval.l_open ? this._imap.findUpper(interval.lower) : this._imap.findLower(interval.lower); // fit に先行する要素 (無ければ null)

      var pfit = fit !== null ? fit.findPredecessor() : this._imap.findLast();

      this._chopItem(pfit, interval);

      if (fit !== null && interval.includes(fit.value)) {
        // fit は interval に内包される最初の要素
        // interval の後続で最初の要素 (無ければ null)
        var it2 = interval.u_open ? this._imap.findLower(interval.upper) : this._imap.findUpper(interval.upper); // it2 の先行 (非 null)

        var it1 = it2 !== null ? it2.findPredecessor() : this._imap.findLast(); // fit の後続で interval に内包されない最初の要素 (無ければ null)

        var lit = interval.includes(it1.value) ? it2 : it1; // interval に内包される要素をすべて削除

        this._imap.remove(fit, lit); // lit は interval と交差している可能性がある


        this._chopItem(lit, interval);
      } else {
        // interval はどの時刻区間も内包しない
        // fit は interval と交差している可能性がある
        this._chopItem(fit, interval);
      }

      return this;
    }
    /**
     * @summary 選択範囲に絞った不変性情報を取得
     *
     * @desc
     * <p>interval で指定した選択範囲と交差する一定値時刻区間を選択して、新しい不変性情報のインスタンスを返す。</p>
     *
     * @param {mapray.animation.Interval} narrow  選択範囲
     *
     * @return {mapray.animation.Invariance}  範囲を狭めた不変性情報
     */

  }, {
    key: "getNarrowed",
    value: function getNarrowed(narrow) {
      var invr = new Invariance();

      if (narrow.isEmpty()) {
        // 交差しないので空を返す
        return invr;
      } // narrow と交差する範囲を決定


      var lo1 = this._imap.findUpper(narrow.lower);

      var lo0 = lo1 !== null ? lo1.findPredecessor() : this._imap.findLast();
      var lower = lo0 !== null && lo0.value.hasIntersection(narrow) ? lo0 : lo1;
      var upper = narrow.u_open ? this._imap.findLower(narrow.upper) : this._imap.findUpper(narrow.upper); // invr へ [lower, upper) を追加

      for (var it = lower; it !== upper; it = it.findSuccessor()) {
        invr._imap.insert(it.key, it.value);
      }

      return invr;
    }
    /**
     * @summary 複数の Invariance を統合
     *
     * @desc
     * <p>invariances のすべての同一値時刻区間の共通区間を持った Invariance インスタンスを生成する。</p>
     *
     * @param {mapray.animation.Invariance[]} invariances  統合元のリスト
     *
     * @return {mapray.animation.Invariance}  統合結果
     */

  }, {
    key: "_$getArray",

    /**
     * @summary 時刻区間の配列を取得
     *
     * @desc
     * <p>Proper の時刻区間が時刻順で格納された配列を返す。</p>
     *
     * @return {mapray.animation.Interval[]}  時刻区間の配列
     *
     * @package
     */
    value: function _$getArray() {
      var array = [];

      for (var it = this._imap.findFirst(); it !== null; it = it.findSuccessor()) {
        array.push(it.value);
      }

      return array;
    }
    /**
     * @summary 不変性情報を修正
     *
     * @desc
     * <p>Curve#getInvariance() で得た一部の不変性情報 subinvr を元に this を更新する。</p>
     * <p>更新後の this は Curve インスタンス全体の不変性情報と一致することが期待される。</p>
     *
     * @param {mapray.animation.Invariance} subinvr  更新部分
     *
     * @package
     */

  }, {
    key: "_$modify",
    value: function _$modify(subinvr) {
      // subinvr の最初と最後
      var ita = subinvr._imap.findFirst();

      if (ita === null) {
        // subinvr は空なので変化なし
        return;
      }

      var itb = subinvr._imap.findLast(); // subinvr の全範囲をくりぬく


      var ai = ita.value;
      var bi = itb.value;
      this.remove(new Interval(ai.lower, bi.upper, ai.l_open, bi.u_open)); // subinvr のすべての時刻区間を挿入
      // 計算量: this の要素数 n, subinvr の要素数 m に対して O(m log n)

      for (var it = ita; it !== null; it = it.findSuccessor()) {
        this._insert(it.value);
      }
    }
    /**
     * @summary 時刻区間を整列により拡張
     *
     * @desc
     * <p>interval の端が this のある区間内にないなら、前または次の区間の境界まで拡大する。</p>
     *
     * <p>事前条件: !interval.isEmpty()</p>
     *
     * @param {mapray.animation.Interval} interval  拡大対象の時刻区間
     *
     * @return {mapray.animation.Interval}  拡大された時刻区間
     *
     * @package
     */

  }, {
    key: "_$expandIntervalByAlignment",
    value: function _$expandIntervalByAlignment(interval) {
      var map = this._imap; // 左側

      var lower; // Interval

      {
        var it1 = map.findLower(interval.lower);

        if (it1 !== null && it1.value.lower.equals(interval.lower) && (interval.l_open || !it1.value.l_open)) {
          // intervalの下限時刻 と it1 の下限時刻が一致し、
          // interval の左端時刻が it1 区間に含まれる
          lower = interval;
        } else {
          var it0 = it1 !== null ? it1.findPredecessor() : map.findLast();

          if (it0 !== null) {
            if (it0.value.hasIntersection(interval)) {
              // interval の左端と it0 が交差する
              lower = interval;
            } else {
              // interval の左端と it0 が交差しない
              lower = it0.value.getFollowings();
            }
          } else {
            // interval の左端と交差する区間はなく、その左側にも区間がない
            lower = Interval.UNIVERSAL;
          }
        }
      } // 右側

      var upper; // Interval

      {
        var _it = map.findLower(interval.upper);

        if (_it !== null && interval.upper.equals(_it.value.lower) && (!interval.u_open || !_it.value.l_open)) {
          // interval 上限時刻と it1 の下限時刻が一致し、
          // interval の右端時刻が it1 区間に含まれる
          upper = interval;
        } else {
          var _it2 = _it !== null ? _it.findPredecessor() : map.findLast();

          if (_it2 !== null && _it2.value.hasIntersection(interval) && (interval.upper.lessThan(_it2.value.upper) || interval.upper.equals(_it2.value.upper) && (interval.u_open || !_it2.value.u_open))) {
            // interval の右端と it0 が交差する
            upper = interval;
          } else {
            // interval の右端と it0 が交差しない
            upper = _it !== null ? _it.value.getPrecedings() : Interval.UNIVERSAL;
          }
        }
      }
      return new Interval(lower.lower, upper.upper, lower.l_open, upper.u_open);
    }
    /**
     * @summary item から interval 部分を削り取る
     *
     * @desc
     * <p>item の時刻区間から interval 部分を消去する。</p>
     * <p>ただし item が null のときは何もしない。</p>
     * <p>最後に item は無効になる。</p>
     *
     * @param {?mapray.OrderedMap.Item}   item
     * @param {mapray.animation.Interval} interval
     *
     * @private
     */

  }, {
    key: "_chopItem",
    value: function _chopItem(item, interval) {
      if (item === null) {
        // 何もしない
        return;
      }

      var diffs = item.value.getDifference(interval); // 削った時刻区間を入れ替え

      this._imap.remove(item);

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = diffs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var di = _step.value;

          if (di.isProper()) {
            this._imap.insert(di.lower, di);
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    }
    /**
     * @summary 時刻区間を挿入
     *
     * @desc
     * <p>条件: this._imap に interval と交差する区間が存在しない</p>
     *
     * <p>計算量: 時刻区間数 n に対して最悪 O(log n)</p>
     *
     * @param {mapray.animation.Interval} interval  時刻区間
     *
     * @private
     */

  }, {
    key: "_insert",
    value: function _insert(interval) {
      if (!interval.isProper()) {
        // Empty と Single の時刻区間は保持しない
        return;
      }

      this._imap.insert(interval.lower, interval);
    }
    /**
     * @summary Invariance を統合
     *
     * 計算量:
     *   this の時刻区間数 k
     *   source の時刻区間数 n
     *   this の各時刻区間範囲内の source の時刻区間数 m (平均値)
     *   merged_imap の時刻区間数 p
     *
     * findSuccessor() を O(1) と考えたとき
     *   O(k * (m * log p + log n))
     *
     * @param {mapray.animation.Invariance} source
     *
     * @private
     */

  }, {
    key: "_merge_from_invariance",
    value: function _merge_from_invariance(source) {
      var merged_imap = createEmptyMap();

      for (var target = this._imap.findFirst(); target !== null; target = target.findSuccessor()) {
        mergeIntervalInvariance(target.value, source, merged_imap);
      }

      this._imap = merged_imap;
    }
  }], [{
    key: "merge",
    value: function merge(invariances) {
      var result = new Invariance();
      result.write(Interval.UNIVERSAL);
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = invariances[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var source = _step2.value;

          result._merge_from_invariance(source);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      return result;
    }
  }]);

  return Invariance;
}();
/**
 * @summary _merge_from_invariance() の一部
 *
 * 計算量:
 *   source の時刻区間数 n
 *   tgtIv 範囲内の source 時刻区間数 m
 *   merged_imap の時刻区間数 p
 *
 * findSuccessor() を O(1) と考えたとき
 *   O(m * log p + log n)
 *
 * @param {mapray.animation.Interval}    tgtIv  時刻区間
 * @param {mapray.animation.Invariance} source
 * @param {mapray.OrderedMap}      merged_imap
 *
 * @private
 */


function mergeIntervalInvariance(tgtIv, source, merged_imap) {
  var src_imap = source._imap; // tgtIv の範囲の source 内の時刻区間を決定
  // 計算量: source の時刻区間数 n に対して O(log n)

  var lower = src_imap.findLower(tgtIv.lower);
  var fit = lower !== null ? lower.findPredecessor() : null;

  if (fit === null) {
    fit = src_imap.findFirst();
  }

  var lit = src_imap.findUpper(tgtIv.upper); // fit から lit までの時刻区間と tgtIv との交差を merged_imap へ追加
  // 計算量: merged_imap の時刻区間数 p, tgtIv 範囲内の source 時刻区間数 m
  // に対して最悪 O(m * log n * log p)

  for (var it = fit; it !== lit; it = it.findSuccessor()) {
    var srcIv = it.value;
    var cross = tgtIv.getIntersection(srcIv);

    if (cross.isProper()) {
      merged_imap.insert(cross.lower, cross);
    }
  }
}
/**
 * @summary 空の時刻区間マップを生成
 *
 * @desc
 * Proper 時刻区間が交差せず、時刻順に並んでいる
 * この条件では時刻区間の下限時刻をキーとして整列できる
 *
 * @return {mapray.OrderedMap}
 *
 * @private
 */


function createEmptyMap() {
  return new OrderedMap(function (a, b) {
    return a.lessThan(b);
  });
}

var freezing = !fails(function () {
  return Object.isExtensible(Object.preventExtensions({}));
});

var internalMetadata = createCommonjsModule(function (module) {
  var defineProperty = objectDefineProperty.f;
  var METADATA = uid('meta');
  var id = 0;

  var isExtensible = Object.isExtensible || function () {
    return true;
  };

  var setMetadata = function (it) {
    defineProperty(it, METADATA, {
      value: {
        objectID: 'O' + ++id,
        // object ID
        weakData: {} // weak collections IDs

      }
    });
  };

  var fastKey = function (it, create) {
    // return a primitive with prefix
    if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;

    if (!has(it, METADATA)) {
      // can't set metadata to uncaught frozen object
      if (!isExtensible(it)) return 'F'; // not necessary to add metadata

      if (!create) return 'E'; // add missing metadata

      setMetadata(it); // return object ID
    }

    return it[METADATA].objectID;
  };

  var getWeakData = function (it, create) {
    if (!has(it, METADATA)) {
      // can't set metadata to uncaught frozen object
      if (!isExtensible(it)) return true; // not necessary to add metadata

      if (!create) return false; // add missing metadata

      setMetadata(it); // return the store of weak collections IDs
    }

    return it[METADATA].weakData;
  }; // add metadata on freeze-family methods calling


  var onFreeze = function (it) {
    if (freezing && meta.REQUIRED && isExtensible(it) && !has(it, METADATA)) setMetadata(it);
    return it;
  };

  var meta = module.exports = {
    REQUIRED: false,
    fastKey: fastKey,
    getWeakData: getWeakData,
    onFreeze: onFreeze
  };
  hiddenKeys[METADATA] = true;
});
var internalMetadata_1 = internalMetadata.REQUIRED;
var internalMetadata_2 = internalMetadata.fastKey;
var internalMetadata_3 = internalMetadata.getWeakData;
var internalMetadata_4 = internalMetadata.onFreeze;

var ITERATOR$3 = wellKnownSymbol('iterator');
var ArrayPrototype$1 = Array.prototype; // check on default Array iterator

var isArrayIteratorMethod = function (it) {
  return it !== undefined && (iterators.Array === it || ArrayPrototype$1[ITERATOR$3] === it);
};

var ITERATOR$4 = wellKnownSymbol('iterator');

var getIteratorMethod = function (it) {
  if (it != undefined) return it[ITERATOR$4] || it['@@iterator'] || iterators[classof(it)];
};

var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
  try {
    return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value); // 7.4.6 IteratorClose(iterator, completion)
  } catch (error) {
    var returnMethod = iterator['return'];
    if (returnMethod !== undefined) anObject(returnMethod.call(iterator));
    throw error;
  }
};

var iterate_1 = createCommonjsModule(function (module) {
  var Result = function (stopped, result) {
    this.stopped = stopped;
    this.result = result;
  };

  var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITERATOR) {
    var boundFunction = functionBindContext(fn, that, AS_ENTRIES ? 2 : 1);
    var iterator, iterFn, index, length, result, next, step;

    if (IS_ITERATOR) {
      iterator = iterable;
    } else {
      iterFn = getIteratorMethod(iterable);
      if (typeof iterFn != 'function') throw TypeError('Target is not iterable'); // optimisation for array iterators

      if (isArrayIteratorMethod(iterFn)) {
        for (index = 0, length = toLength(iterable.length); length > index; index++) {
          result = AS_ENTRIES ? boundFunction(anObject(step = iterable[index])[0], step[1]) : boundFunction(iterable[index]);
          if (result && result instanceof Result) return result;
        }

        return new Result(false);
      }

      iterator = iterFn.call(iterable);
    }

    next = iterator.next;

    while (!(step = next.call(iterator)).done) {
      result = callWithSafeIterationClosing(iterator, boundFunction, step.value, AS_ENTRIES);
      if (typeof result == 'object' && result && result instanceof Result) return result;
    }

    return new Result(false);
  };

  iterate.stop = function (result) {
    return new Result(true, result);
  };
});

var anInstance = function (it, Constructor, name) {
  if (!(it instanceof Constructor)) {
    throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
  }

  return it;
};

var ITERATOR$5 = wellKnownSymbol('iterator');
var SAFE_CLOSING = false;

try {
  var called = 0;
  var iteratorWithReturn = {
    next: function () {
      return {
        done: !!called++
      };
    },
    'return': function () {
      SAFE_CLOSING = true;
    }
  };

  iteratorWithReturn[ITERATOR$5] = function () {
    return this;
  }; // eslint-disable-next-line no-throw-literal


  Array.from(iteratorWithReturn, function () {
    throw 2;
  });
} catch (error) {
  /* empty */
}

var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
  if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
  var ITERATION_SUPPORT = false;

  try {
    var object = {};

    object[ITERATOR$5] = function () {
      return {
        next: function () {
          return {
            done: ITERATION_SUPPORT = true
          };
        }
      };
    };

    exec(object);
  } catch (error) {
    /* empty */
  }

  return ITERATION_SUPPORT;
};

var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
  var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
  var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
  var ADDER = IS_MAP ? 'set' : 'add';
  var NativeConstructor = global_1[CONSTRUCTOR_NAME];
  var NativePrototype = NativeConstructor && NativeConstructor.prototype;
  var Constructor = NativeConstructor;
  var exported = {};

  var fixMethod = function (KEY) {
    var nativeMethod = NativePrototype[KEY];
    redefine(NativePrototype, KEY, KEY == 'add' ? function add(value) {
      nativeMethod.call(this, value === 0 ? 0 : value);
      return this;
    } : KEY == 'delete' ? function (key) {
      return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
    } : KEY == 'get' ? function get(key) {
      return IS_WEAK && !isObject(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
    } : KEY == 'has' ? function has(key) {
      return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
    } : function set(key, value) {
      nativeMethod.call(this, key === 0 ? 0 : key, value);
      return this;
    });
  }; // eslint-disable-next-line max-len


  if (isForced_1(CONSTRUCTOR_NAME, typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
    new NativeConstructor().entries().next();
  })))) {
    // create collection constructor
    Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
    internalMetadata.REQUIRED = true;
  } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
    var instance = new Constructor(); // early implementations not supports chaining

    var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance; // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false

    var THROWS_ON_PRIMITIVES = fails(function () {
      instance.has(1);
    }); // most early implementations doesn't supports iterables, most modern - not close it correctly
    // eslint-disable-next-line no-new

    var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) {
      new NativeConstructor(iterable);
    }); // for early implementations -0 and +0 not the same

    var BUGGY_ZERO = !IS_WEAK && fails(function () {
      // V8 ~ Chromium 42- fails only with 5+ elements
      var $instance = new NativeConstructor();
      var index = 5;

      while (index--) $instance[ADDER](index, index);

      return !$instance.has(-0);
    });

    if (!ACCEPT_ITERABLES) {
      Constructor = wrapper(function (dummy, iterable) {
        anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
        var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
        if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
        return that;
      });
      Constructor.prototype = NativePrototype;
      NativePrototype.constructor = Constructor;
    }

    if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
      fixMethod('delete');
      fixMethod('has');
      IS_MAP && fixMethod('get');
    }

    if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER); // weak collections should not contains .clear method

    if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
  }

  exported[CONSTRUCTOR_NAME] = Constructor;
  _export({
    global: true,
    forced: Constructor != NativeConstructor
  }, exported);
  setToStringTag(Constructor, CONSTRUCTOR_NAME);
  if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
  return Constructor;
};

var redefineAll = function (target, src, options) {
  for (var key in src) redefine(target, key, src[key], options);

  return target;
};

var SPECIES$1 = wellKnownSymbol('species');

var setSpecies = function (CONSTRUCTOR_NAME) {
  var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
  var defineProperty = objectDefineProperty.f;

  if (descriptors && Constructor && !Constructor[SPECIES$1]) {
    defineProperty(Constructor, SPECIES$1, {
      configurable: true,
      get: function () {
        return this;
      }
    });
  }
};

var defineProperty$6 = objectDefineProperty.f;
var fastKey = internalMetadata.fastKey;
var setInternalState$3 = internalState.set;
var internalStateGetterFor = internalState.getterFor;
var collectionStrong = {
  getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
    var C = wrapper(function (that, iterable) {
      anInstance(that, C, CONSTRUCTOR_NAME);
      setInternalState$3(that, {
        type: CONSTRUCTOR_NAME,
        index: objectCreate(null),
        first: undefined,
        last: undefined,
        size: 0
      });
      if (!descriptors) that.size = 0;
      if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
    });
    var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);

    var define = function (that, key, value) {
      var state = getInternalState(that);
      var entry = getEntry(that, key);
      var previous, index; // change existing entry

      if (entry) {
        entry.value = value; // create new entry
      } else {
        state.last = entry = {
          index: index = fastKey(key, true),
          key: key,
          value: value,
          previous: previous = state.last,
          next: undefined,
          removed: false
        };
        if (!state.first) state.first = entry;
        if (previous) previous.next = entry;
        if (descriptors) state.size++;else that.size++; // add to index

        if (index !== 'F') state.index[index] = entry;
      }

      return that;
    };

    var getEntry = function (that, key) {
      var state = getInternalState(that); // fast case

      var index = fastKey(key);
      var entry;
      if (index !== 'F') return state.index[index]; // frozen object case

      for (entry = state.first; entry; entry = entry.next) {
        if (entry.key == key) return entry;
      }
    };

    redefineAll(C.prototype, {
      // 23.1.3.1 Map.prototype.clear()
      // 23.2.3.2 Set.prototype.clear()
      clear: function clear() {
        var that = this;
        var state = getInternalState(that);
        var data = state.index;
        var entry = state.first;

        while (entry) {
          entry.removed = true;
          if (entry.previous) entry.previous = entry.previous.next = undefined;
          delete data[entry.index];
          entry = entry.next;
        }

        state.first = state.last = undefined;
        if (descriptors) state.size = 0;else that.size = 0;
      },
      // 23.1.3.3 Map.prototype.delete(key)
      // 23.2.3.4 Set.prototype.delete(value)
      'delete': function (key) {
        var that = this;
        var state = getInternalState(that);
        var entry = getEntry(that, key);

        if (entry) {
          var next = entry.next;
          var prev = entry.previous;
          delete state.index[entry.index];
          entry.removed = true;
          if (prev) prev.next = next;
          if (next) next.previous = prev;
          if (state.first == entry) state.first = next;
          if (state.last == entry) state.last = prev;
          if (descriptors) state.size--;else that.size--;
        }

        return !!entry;
      },
      // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
      // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
      forEach: function forEach(callbackfn
      /* , that = undefined */
      ) {
        var state = getInternalState(this);
        var boundFunction = functionBindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
        var entry;

        while (entry = entry ? entry.next : state.first) {
          boundFunction(entry.value, entry.key, this); // revert to the last existing entry

          while (entry && entry.removed) entry = entry.previous;
        }
      },
      // 23.1.3.7 Map.prototype.has(key)
      // 23.2.3.7 Set.prototype.has(value)
      has: function has(key) {
        return !!getEntry(this, key);
      }
    });
    redefineAll(C.prototype, IS_MAP ? {
      // 23.1.3.6 Map.prototype.get(key)
      get: function get(key) {
        var entry = getEntry(this, key);
        return entry && entry.value;
      },
      // 23.1.3.9 Map.prototype.set(key, value)
      set: function set(key, value) {
        return define(this, key === 0 ? 0 : key, value);
      }
    } : {
      // 23.2.3.1 Set.prototype.add(value)
      add: function add(value) {
        return define(this, value = value === 0 ? 0 : value, value);
      }
    });
    if (descriptors) defineProperty$6(C.prototype, 'size', {
      get: function () {
        return getInternalState(this).size;
      }
    });
    return C;
  },
  setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
    var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
    var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
    var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME); // add .keys, .values, .entries, [@@iterator]
    // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11

    defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
      setInternalState$3(this, {
        type: ITERATOR_NAME,
        target: iterated,
        state: getInternalCollectionState(iterated),
        kind: kind,
        last: undefined
      });
    }, function () {
      var state = getInternalIteratorState(this);
      var kind = state.kind;
      var entry = state.last; // revert to the last existing entry

      while (entry && entry.removed) entry = entry.previous; // get next entry


      if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
        // or finish the iteration
        state.target = undefined;
        return {
          value: undefined,
          done: true
        };
      } // return step by kind


      if (kind == 'keys') return {
        value: entry.key,
        done: false
      };
      if (kind == 'values') return {
        value: entry.value,
        done: false
      };
      return {
        value: [entry.key, entry.value],
        done: false
      };
    }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); // add [@@species], 23.1.2.2, 23.2.2.2

    setSpecies(CONSTRUCTOR_NAME);
  }
};

// https://tc39.github.io/ecma262/#sec-map-objects


var es_map = collection('Map', function (init) {
  return function Map() {
    return init(this, arguments.length ? arguments[0] : undefined);
  };
}, collectionStrong);

/**
 * @summary アニメーション値の型
 *
 * @classdesc
 * <p>アニメーションする値の型を表現するための抽象クラスである。</p>
 * <p>Binder インスタンスと結合するパラメータ値の型と、Curve インスタンスが返却する値の型を表現する。</p>
 *
 * <p>Type の具象クラスのインスタンスは {@link mapray.animation.Type.register}()
 *    により登録し、{@link mapray.animation.Type.find}() により取得することができる。</p>
 *
 * <p>特定の Type の具象クラスのインスタンスは 1 つしか存在しない。そのため Type インスタンスが表す型の同一性は
 *    === 演算子で判断することができる。</p>
 *
 * @abstract
 * @memberof mapray.animation
 */

var Type =
/*#__PURE__*/
function () {
  /**
   * @param {string} name  型の登録名
   * @protected
   */
  function Type(name) {
    _classCallCheck(this, Type);

    this._name = name;
  }
  /**
   * @summary 型名
   *
   * @type {string}
   * @readonly
   */


  _createClass(Type, [{
    key: "isConvertible",

    /**
     * @summary 変換可能か?
     *
     * @desc
     * <p>from 型の値を this 型の値への変換が可能かどうかを返す。</p>
     * <p>this と from が同一なら、必ず true を返す。</p>
     * <p>このメソッドが true を返した場合は convertValue() により from 型の値を
     *    this 型の値に変換することが可能である。</p>
     *
     * @param {mapray.animation.Type} from  変換元の型
     *
     * @return {boolean}  変換可能かなら true, そうでないなら false
     *
     * @see {@link mapray.animation.Type#convertValue}
     *
     * @abstract
     */
    value: function isConvertible(from) {
      this._override_error("isConvertible");
    }
    /**
     * @summary 値を変換
     *
     * @desc
     * <p>value を this 型へ変換したオブジェクトを返す。</p>
     * <p>変換結果が value と同じ値の場合、value 自身を返すことも可能である。</p>
     *
     * <p>事前条件1: value は from 型のオブジェクトである<br>
     *    事前条件2: this.isConvertible( from ) == true</p>
     *
     * @param {mapray.animation.Type} from  変換元の型
     * @param {object}               value  変換元の値 (from 型)
     *
     * @return {object}  変換された値 (this 型)
     *
     * @see {@link mapray.animation.Type#isConvertible}
     *
     * @abstract
     */

  }, {
    key: "convertValue",
    value: function convertValue(from, value) {
      this._override_error("convertValue");
    }
    /**
     * @summary 既定値を取得
     *
     * @desc
     * <p>this 型の既定値を返す。</p>
     *
     * @return {object}  既定値 (this 型)
     *
     * @abstract
     */

  }, {
    key: "getDefaultValue",
    value: function getDefaultValue() {
      this._override_error("getDefaultValue");
    }
    /**
     * @summary 値の複製を取得
     *
     * @desc
     * <p>value の新しい複製を返す。</p>
     * <p>ただし value がイミュータブルの場合、value 自身を返すことも可能である。</p>
     *
     * <p>事前条件: value は this 型のオブジェクトである</p>
     *
     * @param {object} value  複製元の値 (this 型)
     *
     * @return {object}  複製された値 (this 型)
     *
     * @abstract
     */

  }, {
    key: "getCloneValue",
    value: function getCloneValue(value) {
      this._override_error("getCloneValue");
    }
    /**
     * @summary 型を登録
     *
     * @desc
     * <p>名前を name として type 型を登録する。</p>
     * <p>登録された type は name により検索することができる。</p>
     *
     * @param {string}                name  型の名前
     * @param {mapray.animation.Type} type  Type インスタンス
     *
     * @return {mapray.animation.Type}  type
     *
     * @throws {@link mapray.animation.Type.AlreadyRegisteredError}  name がすでに登録されているとき
     *
     * @see {@link mapray.animation.Type.find}
     */

  }, {
    key: "_override_error",

    /**
     * @summary メソッドがオーバーライドされていない
     *
     * arguments.callee と Error#stack は互換性が低いので、関数名の取得に使わなかった
     *
     * @param {string} func_name
     *
     * @private
     */
    value: function _override_error(func_name) {
      throw new Error("Type#" + func_name + "() method has not been overridden in " + this.constructor.name);
    }
  }, {
    key: "name",
    get: function get() {
      return this._name;
    }
  }], [{
    key: "register",
    value: function register(name, type) {
      if (type_register_map.has(name)) {
        // name はすでに登録済み
        throw new AlreadyRegisteredError("specified name (" + name + ") has already been registered");
      }

      type_register_map.set(name, type);
      return type;
    }
    /**
     * @summary 型を検索
     *
     * @desc
     * <p>名前が name として登録された Type インスタンスを返す。</p>
     *
     * <p>name の型が登録されている場合、name に対して常に同じインスタンスを返す。
     *
     * @param {string} name  型の名前
     *
     * @return {mapray.animation.Type}
     *
     * @throws {@link mapray.animation.Type.NotRegisteredError}  name に対応する型が登録されていないとき
     *
     * @see {@link mapray.animation.Type.register}
     */

  }, {
    key: "find",
    value: function find(name) {
      var type = type_register_map.get(name);

      if (type === undefined) {
        // name は登録されていない
        throw new NotRegisteredError("type with the specified name (" + name + ") is not registered");
      }

      return type;
    }
  }]);

  return Type;
}();
/**
 * @summary 型の多重登録エラー
 *
 * @memberof mapray.animation.Type
 * @extends mapray.animation.AnimationError
 *
 * @see {@link mapray.animation.Type.register}
 */


var AlreadyRegisteredError =
/*#__PURE__*/
function (_AnimationError) {
  _inherits(AlreadyRegisteredError, _AnimationError);

  /**
   * @param {string} message  エラーの説明
   */
  function AlreadyRegisteredError(message) {
    var _this;

    _classCallCheck(this, AlreadyRegisteredError);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(AlreadyRegisteredError).call(this, message));
    _this.name = "mapray.animation.Type.AlreadyRegisteredError";
    return _this;
  }

  return AlreadyRegisteredError;
}(AnimationError);

Type.AlreadyRegisteredError = AlreadyRegisteredError;
/**
 * @summary 型の未登録エラー
 *
 * @memberof mapray.animation.Type
 * @extends mapray.animation.AnimationError
 *
 * @see {@link mapray.animation.Type.find}
 */

var NotRegisteredError =
/*#__PURE__*/
function (_AnimationError2) {
  _inherits(NotRegisteredError, _AnimationError2);

  /**
   * @param {string} message  エラーの説明
   */
  function NotRegisteredError(message) {
    var _this2;

    _classCallCheck(this, NotRegisteredError);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(NotRegisteredError).call(this, message));
    _this2.name = "mapray.animation.Type.NotRegisteredError";
    return _this2;
  }

  return NotRegisteredError;
}(AnimationError);

Type.NotRegisteredError = NotRegisteredError;
/**
 * @summary 型の登録情報
 *
 * @type {Map.<string, mapray.animation.Type>}
 * @readonly
 *
 * @private
 */

var type_register_map = new Map();

var $find = arrayIteration.find;
var FIND = 'find';
var SKIPS_HOLES = true;
var USES_TO_LENGTH$1 = arrayMethodUsesToLength(FIND); // Shouldn't skip holes

if (FIND in []) Array(1)[FIND](function () {
  SKIPS_HOLES = false;
}); // `Array.prototype.find` method
// https://tc39.github.io/ecma262/#sec-array.prototype.find

_export({
  target: 'Array',
  proto: true,
  forced: SKIPS_HOLES || !USES_TO_LENGTH$1
}, {
  find: function find(callbackfn
  /* , that = undefined */
  ) {
    return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
  }
}); // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables

addToUnscopables(FIND);

// https://tc39.github.io/ecma262/#sec-set-objects


var es_set = collection('Set', function (init) {
  return function Set() {
    return init(this, arguments.length ? arguments[0] : undefined);
  };
}, collectionStrong);

var arrayBufferNative = typeof ArrayBuffer !== 'undefined' && typeof DataView !== 'undefined';

// https://tc39.github.io/ecma262/#sec-toindex

var toIndex = function (it) {
  if (it === undefined) return 0;
  var number = toInteger(it);
  var length = toLength(number);
  if (number !== length) throw RangeError('Wrong length or index');
  return length;
};

// IEEE754 conversions based on https://github.com/feross/ieee754
// eslint-disable-next-line no-shadow-restricted-names
var Infinity$1 = 1 / 0;
var abs = Math.abs;
var pow = Math.pow;
var floor$1 = Math.floor;
var log$1 = Math.log;
var LN2$1 = Math.LN2;

var pack = function (number, mantissaLength, bytes) {
  var buffer = new Array(bytes);
  var exponentLength = bytes * 8 - mantissaLength - 1;
  var eMax = (1 << exponentLength) - 1;
  var eBias = eMax >> 1;
  var rt = mantissaLength === 23 ? pow(2, -24) - pow(2, -77) : 0;
  var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
  var index = 0;
  var exponent, mantissa, c;
  number = abs(number); // eslint-disable-next-line no-self-compare

  if (number != number || number === Infinity$1) {
    // eslint-disable-next-line no-self-compare
    mantissa = number != number ? 1 : 0;
    exponent = eMax;
  } else {
    exponent = floor$1(log$1(number) / LN2$1);

    if (number * (c = pow(2, -exponent)) < 1) {
      exponent--;
      c *= 2;
    }

    if (exponent + eBias >= 1) {
      number += rt / c;
    } else {
      number += rt * pow(2, 1 - eBias);
    }

    if (number * c >= 2) {
      exponent++;
      c /= 2;
    }

    if (exponent + eBias >= eMax) {
      mantissa = 0;
      exponent = eMax;
    } else if (exponent + eBias >= 1) {
      mantissa = (number * c - 1) * pow(2, mantissaLength);
      exponent = exponent + eBias;
    } else {
      mantissa = number * pow(2, eBias - 1) * pow(2, mantissaLength);
      exponent = 0;
    }
  }

  for (; mantissaLength >= 8; buffer[index++] = mantissa & 255, mantissa /= 256, mantissaLength -= 8);

  exponent = exponent << mantissaLength | mantissa;
  exponentLength += mantissaLength;

  for (; exponentLength > 0; buffer[index++] = exponent & 255, exponent /= 256, exponentLength -= 8);

  buffer[--index] |= sign * 128;
  return buffer;
};

var unpack = function (buffer, mantissaLength) {
  var bytes = buffer.length;
  var exponentLength = bytes * 8 - mantissaLength - 1;
  var eMax = (1 << exponentLength) - 1;
  var eBias = eMax >> 1;
  var nBits = exponentLength - 7;
  var index = bytes - 1;
  var sign = buffer[index--];
  var exponent = sign & 127;
  var mantissa;
  sign >>= 7;

  for (; nBits > 0; exponent = exponent * 256 + buffer[index], index--, nBits -= 8);

  mantissa = exponent & (1 << -nBits) - 1;
  exponent >>= -nBits;
  nBits += mantissaLength;

  for (; nBits > 0; mantissa = mantissa * 256 + buffer[index], index--, nBits -= 8);

  if (exponent === 0) {
    exponent = 1 - eBias;
  } else if (exponent === eMax) {
    return mantissa ? NaN : sign ? -Infinity$1 : Infinity$1;
  } else {
    mantissa = mantissa + pow(2, mantissaLength);
    exponent = exponent - eBias;
  }

  return (sign ? -1 : 1) * mantissa * pow(2, exponent - mantissaLength);
};

var ieee754 = {
  pack: pack,
  unpack: unpack
};

// https://tc39.github.io/ecma262/#sec-array.prototype.fill


var arrayFill = function fill(value
/* , start = 0, end = @length */
) {
  var O = toObject(this);
  var length = toLength(O.length);
  var argumentsLength = arguments.length;
  var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
  var end = argumentsLength > 2 ? arguments[2] : undefined;
  var endPos = end === undefined ? length : toAbsoluteIndex(end, length);

  while (endPos > index) O[index++] = value;

  return O;
};

var getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
var defineProperty$7 = objectDefineProperty.f;
var getInternalState$3 = internalState.get;
var setInternalState$4 = internalState.set;
var ARRAY_BUFFER = 'ArrayBuffer';
var DATA_VIEW = 'DataView';
var PROTOTYPE$2 = 'prototype';
var WRONG_LENGTH = 'Wrong length';
var WRONG_INDEX = 'Wrong index';
var NativeArrayBuffer = global_1[ARRAY_BUFFER];
var $ArrayBuffer = NativeArrayBuffer;
var $DataView = global_1[DATA_VIEW];
var $DataViewPrototype = $DataView && $DataView[PROTOTYPE$2];
var ObjectPrototype$2 = Object.prototype;
var RangeError$1 = global_1.RangeError;
var packIEEE754 = ieee754.pack;
var unpackIEEE754 = ieee754.unpack;

var packInt8 = function (number) {
  return [number & 0xFF];
};

var packInt16 = function (number) {
  return [number & 0xFF, number >> 8 & 0xFF];
};

var packInt32 = function (number) {
  return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];
};

var unpackInt32 = function (buffer) {
  return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
};

var packFloat32 = function (number) {
  return packIEEE754(number, 23, 4);
};

var packFloat64 = function (number) {
  return packIEEE754(number, 52, 8);
};

var addGetter = function (Constructor, key) {
  defineProperty$7(Constructor[PROTOTYPE$2], key, {
    get: function () {
      return getInternalState$3(this)[key];
    }
  });
};

var get$1 = function (view, count, index, isLittleEndian) {
  var intIndex = toIndex(index);
  var store = getInternalState$3(view);
  if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
  var bytes = getInternalState$3(store.buffer).bytes;
  var start = intIndex + store.byteOffset;
  var pack = bytes.slice(start, start + count);
  return isLittleEndian ? pack : pack.reverse();
};

var set$1 = function (view, count, index, conversion, value, isLittleEndian) {
  var intIndex = toIndex(index);
  var store = getInternalState$3(view);
  if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
  var bytes = getInternalState$3(store.buffer).bytes;
  var start = intIndex + store.byteOffset;
  var pack = conversion(+value);

  for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];
};

if (!arrayBufferNative) {
  $ArrayBuffer = function ArrayBuffer(length) {
    anInstance(this, $ArrayBuffer, ARRAY_BUFFER);
    var byteLength = toIndex(length);
    setInternalState$4(this, {
      bytes: arrayFill.call(new Array(byteLength), 0),
      byteLength: byteLength
    });
    if (!descriptors) this.byteLength = byteLength;
  };

  $DataView = function DataView(buffer, byteOffset, byteLength) {
    anInstance(this, $DataView, DATA_VIEW);
    anInstance(buffer, $ArrayBuffer, DATA_VIEW);
    var bufferLength = getInternalState$3(buffer).byteLength;
    var offset = toInteger(byteOffset);
    if (offset < 0 || offset > bufferLength) throw RangeError$1('Wrong offset');
    byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength);
    if (offset + byteLength > bufferLength) throw RangeError$1(WRONG_LENGTH);
    setInternalState$4(this, {
      buffer: buffer,
      byteLength: byteLength,
      byteOffset: offset
    });

    if (!descriptors) {
      this.buffer = buffer;
      this.byteLength = byteLength;
      this.byteOffset = offset;
    }
  };

  if (descriptors) {
    addGetter($ArrayBuffer, 'byteLength');
    addGetter($DataView, 'buffer');
    addGetter($DataView, 'byteLength');
    addGetter($DataView, 'byteOffset');
  }

  redefineAll($DataView[PROTOTYPE$2], {
    getInt8: function getInt8(byteOffset) {
      return get$1(this, 1, byteOffset)[0] << 24 >> 24;
    },
    getUint8: function getUint8(byteOffset) {
      return get$1(this, 1, byteOffset)[0];
    },
    getInt16: function getInt16(byteOffset
    /* , littleEndian */
    ) {
      var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
      return (bytes[1] << 8 | bytes[0]) << 16 >> 16;
    },
    getUint16: function getUint16(byteOffset
    /* , littleEndian */
    ) {
      var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
      return bytes[1] << 8 | bytes[0];
    },
    getInt32: function getInt32(byteOffset
    /* , littleEndian */
    ) {
      return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));
    },
    getUint32: function getUint32(byteOffset
    /* , littleEndian */
    ) {
      return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;
    },
    getFloat32: function getFloat32(byteOffset
    /* , littleEndian */
    ) {
      return unpackIEEE754(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);
    },
    getFloat64: function getFloat64(byteOffset
    /* , littleEndian */
    ) {
      return unpackIEEE754(get$1(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);
    },
    setInt8: function setInt8(byteOffset, value) {
      set$1(this, 1, byteOffset, packInt8, value);
    },
    setUint8: function setUint8(byteOffset, value) {
      set$1(this, 1, byteOffset, packInt8, value);
    },
    setInt16: function setInt16(byteOffset, value
    /* , littleEndian */
    ) {
      set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
    },
    setUint16: function setUint16(byteOffset, value
    /* , littleEndian */
    ) {
      set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
    },
    setInt32: function setInt32(byteOffset, value
    /* , littleEndian */
    ) {
      set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
    },
    setUint32: function setUint32(byteOffset, value
    /* , littleEndian */
    ) {
      set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
    },
    setFloat32: function setFloat32(byteOffset, value
    /* , littleEndian */
    ) {
      set$1(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);
    },
    setFloat64: function setFloat64(byteOffset, value
    /* , littleEndian */
    ) {
      set$1(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);
    }
  });
} else {
  if (!fails(function () {
    NativeArrayBuffer(1);
  }) || !fails(function () {
    new NativeArrayBuffer(-1); // eslint-disable-line no-new
  }) || fails(function () {
    new NativeArrayBuffer(); // eslint-disable-line no-new

    new NativeArrayBuffer(1.5); // eslint-disable-line no-new

    new NativeArrayBuffer(NaN); // eslint-disable-line no-new

    return NativeArrayBuffer.name != ARRAY_BUFFER;
  })) {
    $ArrayBuffer = function ArrayBuffer(length) {
      anInstance(this, $ArrayBuffer);
      return new NativeArrayBuffer(toIndex(length));
    };

    var ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE$2] = NativeArrayBuffer[PROTOTYPE$2];

    for (var keys$2 = getOwnPropertyNames$1(NativeArrayBuffer), j$1 = 0, key$1; keys$2.length > j$1;) {
      if (!((key$1 = keys$2[j$1++]) in $ArrayBuffer)) {
        createNonEnumerableProperty($ArrayBuffer, key$1, NativeArrayBuffer[key$1]);
      }
    }

    ArrayBufferPrototype.constructor = $ArrayBuffer;
  } // WebKit bug - the same parent prototype for typed arrays and data view


  if (objectSetPrototypeOf && objectGetPrototypeOf($DataViewPrototype) !== ObjectPrototype$2) {
    objectSetPrototypeOf($DataViewPrototype, ObjectPrototype$2);
  } // iOS Safari 7.x bug


  var testView = new $DataView(new $ArrayBuffer(2));
  var nativeSetInt8 = $DataViewPrototype.setInt8;
  testView.setInt8(0, 2147483648);
  testView.setInt8(1, 2147483649);
  if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll($DataViewPrototype, {
    setInt8: function setInt8(byteOffset, value) {
      nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
    },
    setUint8: function setUint8(byteOffset, value) {
      nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
    }
  }, {
    unsafe: true
  });
}

setToStringTag($ArrayBuffer, ARRAY_BUFFER);
setToStringTag($DataView, DATA_VIEW);
var arrayBuffer = {
  ArrayBuffer: $ArrayBuffer,
  DataView: $DataView
};

var SPECIES$2 = wellKnownSymbol('species'); // `SpeciesConstructor` abstract operation
// https://tc39.github.io/ecma262/#sec-speciesconstructor

var speciesConstructor = function (O, defaultConstructor) {
  var C = anObject(O).constructor;
  var S;
  return C === undefined || (S = anObject(C)[SPECIES$2]) == undefined ? defaultConstructor : aFunction$1(S);
};

var ArrayBuffer$1 = arrayBuffer.ArrayBuffer;
var DataView$1 = arrayBuffer.DataView;
var nativeArrayBufferSlice = ArrayBuffer$1.prototype.slice;
var INCORRECT_SLICE = fails(function () {
  return !new ArrayBuffer$1(2).slice(1, undefined).byteLength;
}); // `ArrayBuffer.prototype.slice` method
// https://tc39.github.io/ecma262/#sec-arraybuffer.prototype.slice

_export({
  target: 'ArrayBuffer',
  proto: true,
  unsafe: true,
  forced: INCORRECT_SLICE
}, {
  slice: function slice(start, end) {
    if (nativeArrayBufferSlice !== undefined && end === undefined) {
      return nativeArrayBufferSlice.call(anObject(this), start); // FF fix
    }

    var length = anObject(this).byteLength;
    var first = toAbsoluteIndex(start, length);
    var fin = toAbsoluteIndex(end === undefined ? length : end, length);
    var result = new (speciesConstructor(this, ArrayBuffer$1))(toLength(fin - first));
    var viewSource = new DataView$1(this);
    var viewTarget = new DataView$1(result);
    var index = 0;

    while (first < fin) {
      viewTarget.setUint8(index++, viewSource.getUint8(first++));
    }

    return result;
  }
});

var defineProperty$8 = objectDefineProperty.f;
var Int8Array$1 = global_1.Int8Array;
var Int8ArrayPrototype = Int8Array$1 && Int8Array$1.prototype;
var Uint8ClampedArray = global_1.Uint8ClampedArray;
var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
var TypedArray = Int8Array$1 && objectGetPrototypeOf(Int8Array$1);
var TypedArrayPrototype = Int8ArrayPrototype && objectGetPrototypeOf(Int8ArrayPrototype);
var ObjectPrototype$3 = Object.prototype;
var isPrototypeOf = ObjectPrototype$3.isPrototypeOf;
var TO_STRING_TAG$4 = wellKnownSymbol('toStringTag');
var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG'); // Fixing native typed arrays in Opera Presto crashes the browser, see #595

var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferNative && !!objectSetPrototypeOf && classof(global_1.opera) !== 'Opera';
var TYPED_ARRAY_TAG_REQIRED = false;
var NAME$1;
var TypedArrayConstructorsList = {
  Int8Array: 1,
  Uint8Array: 1,
  Uint8ClampedArray: 1,
  Int16Array: 2,
  Uint16Array: 2,
  Int32Array: 4,
  Uint32Array: 4,
  Float32Array: 4,
  Float64Array: 8
};

var isView = function isView(it) {
  var klass = classof(it);
  return klass === 'DataView' || has(TypedArrayConstructorsList, klass);
};

var isTypedArray = function (it) {
  return isObject(it) && has(TypedArrayConstructorsList, classof(it));
};

var aTypedArray = function (it) {
  if (isTypedArray(it)) return it;
  throw TypeError('Target is not a typed array');
};

var aTypedArrayConstructor = function (C) {
  if (objectSetPrototypeOf) {
    if (isPrototypeOf.call(TypedArray, C)) return C;
  } else for (var ARRAY in TypedArrayConstructorsList) if (has(TypedArrayConstructorsList, NAME$1)) {
    var TypedArrayConstructor = global_1[ARRAY];

    if (TypedArrayConstructor && (C === TypedArrayConstructor || isPrototypeOf.call(TypedArrayConstructor, C))) {
      return C;
    }
  }

  throw TypeError('Target is not a typed array constructor');
};

var exportTypedArrayMethod = function (KEY, property, forced) {
  if (!descriptors) return;
  if (forced) for (var ARRAY in TypedArrayConstructorsList) {
    var TypedArrayConstructor = global_1[ARRAY];

    if (TypedArrayConstructor && has(TypedArrayConstructor.prototype, KEY)) {
      delete TypedArrayConstructor.prototype[KEY];
    }
  }

  if (!TypedArrayPrototype[KEY] || forced) {
    redefine(TypedArrayPrototype, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property);
  }
};

var exportTypedArrayStaticMethod = function (KEY, property, forced) {
  var ARRAY, TypedArrayConstructor;
  if (!descriptors) return;

  if (objectSetPrototypeOf) {
    if (forced) for (ARRAY in TypedArrayConstructorsList) {
      TypedArrayConstructor = global_1[ARRAY];

      if (TypedArrayConstructor && has(TypedArrayConstructor, KEY)) {
        delete TypedArrayConstructor[KEY];
      }
    }

    if (!TypedArray[KEY] || forced) {
      // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
      try {
        return redefine(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && Int8Array$1[KEY] || property);
      } catch (error) {
        /* empty */
      }
    } else return;
  }

  for (ARRAY in TypedArrayConstructorsList) {
    TypedArrayConstructor = global_1[ARRAY];

    if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
      redefine(TypedArrayConstructor, KEY, property);
    }
  }
};

for (NAME$1 in TypedArrayConstructorsList) {
  if (!global_1[NAME$1]) NATIVE_ARRAY_BUFFER_VIEWS = false;
} // WebKit bug - typed arrays constructors prototype is Object.prototype


if (!NATIVE_ARRAY_BUFFER_VIEWS || typeof TypedArray != 'function' || TypedArray === Function.prototype) {
  // eslint-disable-next-line no-shadow
  TypedArray = function TypedArray() {
    throw TypeError('Incorrect invocation');
  };

  if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME$1 in TypedArrayConstructorsList) {
    if (global_1[NAME$1]) objectSetPrototypeOf(global_1[NAME$1], TypedArray);
  }
}

if (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype$3) {
  TypedArrayPrototype = TypedArray.prototype;
  if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME$1 in TypedArrayConstructorsList) {
    if (global_1[NAME$1]) objectSetPrototypeOf(global_1[NAME$1].prototype, TypedArrayPrototype);
  }
} // WebKit bug - one more object in Uint8ClampedArray prototype chain


if (NATIVE_ARRAY_BUFFER_VIEWS && objectGetPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {
  objectSetPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);
}

if (descriptors && !has(TypedArrayPrototype, TO_STRING_TAG$4)) {
  TYPED_ARRAY_TAG_REQIRED = true;
  defineProperty$8(TypedArrayPrototype, TO_STRING_TAG$4, {
    get: function () {
      return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined;
    }
  });

  for (NAME$1 in TypedArrayConstructorsList) if (global_1[NAME$1]) {
    createNonEnumerableProperty(global_1[NAME$1], TYPED_ARRAY_TAG, NAME$1);
  }
}

var arrayBufferViewCore = {
  NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS,
  TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQIRED && TYPED_ARRAY_TAG,
  aTypedArray: aTypedArray,
  aTypedArrayConstructor: aTypedArrayConstructor,
  exportTypedArrayMethod: exportTypedArrayMethod,
  exportTypedArrayStaticMethod: exportTypedArrayStaticMethod,
  isView: isView,
  isTypedArray: isTypedArray,
  TypedArray: TypedArray,
  TypedArrayPrototype: TypedArrayPrototype
};

/* eslint-disable no-new */

var NATIVE_ARRAY_BUFFER_VIEWS$1 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
var ArrayBuffer$2 = global_1.ArrayBuffer;
var Int8Array$2 = global_1.Int8Array;
var typedArrayConstructorsRequireWrappers = !NATIVE_ARRAY_BUFFER_VIEWS$1 || !fails(function () {
  Int8Array$2(1);
}) || !fails(function () {
  new Int8Array$2(-1);
}) || !checkCorrectnessOfIteration(function (iterable) {
  new Int8Array$2();
  new Int8Array$2(null);
  new Int8Array$2(1.5);
  new Int8Array$2(iterable);
}, true) || fails(function () {
  // Safari (11+) bug - a reason why even Safari 13 should load a typed array polyfill
  return new Int8Array$2(new ArrayBuffer$2(2), 1, undefined).length !== 1;
});

var toPositiveInteger = function (it) {
  var result = toInteger(it);
  if (result < 0) throw RangeError("The argument can't be less than 0");
  return result;
};

var toOffset = function (it, BYTES) {
  var offset = toPositiveInteger(it);
  if (offset % BYTES) throw RangeError('Wrong offset');
  return offset;
};

var aTypedArrayConstructor$1 = arrayBufferViewCore.aTypedArrayConstructor;

var typedArrayFrom = function from(source
/* , mapfn, thisArg */
) {
  var O = toObject(source);
  var argumentsLength = arguments.length;
  var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
  var mapping = mapfn !== undefined;
  var iteratorMethod = getIteratorMethod(O);
  var i, length, result, step, iterator, next;

  if (iteratorMethod != undefined && !isArrayIteratorMethod(iteratorMethod)) {
    iterator = iteratorMethod.call(O);
    next = iterator.next;
    O = [];

    while (!(step = next.call(iterator)).done) {
      O.push(step.value);
    }
  }

  if (mapping && argumentsLength > 2) {
    mapfn = functionBindContext(mapfn, arguments[2], 2);
  }

  length = toLength(O.length);
  result = new (aTypedArrayConstructor$1(this))(length);

  for (i = 0; length > i; i++) {
    result[i] = mapping ? mapfn(O[i], i) : O[i];
  }

  return result;
};

var typedArrayConstructor = createCommonjsModule(function (module) {

  var getOwnPropertyNames = objectGetOwnPropertyNames.f;
  var forEach = arrayIteration.forEach;
  var getInternalState = internalState.get;
  var setInternalState = internalState.set;
  var nativeDefineProperty = objectDefineProperty.f;
  var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
  var round = Math.round;
  var RangeError = global_1.RangeError;
  var ArrayBuffer = arrayBuffer.ArrayBuffer;
  var DataView = arrayBuffer.DataView;
  var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
  var TYPED_ARRAY_TAG = arrayBufferViewCore.TYPED_ARRAY_TAG;
  var TypedArray = arrayBufferViewCore.TypedArray;
  var TypedArrayPrototype = arrayBufferViewCore.TypedArrayPrototype;
  var aTypedArrayConstructor = arrayBufferViewCore.aTypedArrayConstructor;
  var isTypedArray = arrayBufferViewCore.isTypedArray;
  var BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT';
  var WRONG_LENGTH = 'Wrong length';

  var fromList = function (C, list) {
    var index = 0;
    var length = list.length;
    var result = new (aTypedArrayConstructor(C))(length);

    while (length > index) result[index] = list[index++];

    return result;
  };

  var addGetter = function (it, key) {
    nativeDefineProperty(it, key, {
      get: function () {
        return getInternalState(this)[key];
      }
    });
  };

  var isArrayBuffer = function (it) {
    var klass;
    return it instanceof ArrayBuffer || (klass = classof(it)) == 'ArrayBuffer' || klass == 'SharedArrayBuffer';
  };

  var isTypedArrayIndex = function (target, key) {
    return isTypedArray(target) && typeof key != 'symbol' && key in target && String(+key) == String(key);
  };

  var wrappedGetOwnPropertyDescriptor = function getOwnPropertyDescriptor(target, key) {
    return isTypedArrayIndex(target, key = toPrimitive(key, true)) ? createPropertyDescriptor(2, target[key]) : nativeGetOwnPropertyDescriptor(target, key);
  };

  var wrappedDefineProperty = function defineProperty(target, key, descriptor) {
    if (isTypedArrayIndex(target, key = toPrimitive(key, true)) && isObject(descriptor) && has(descriptor, 'value') && !has(descriptor, 'get') && !has(descriptor, 'set') // TODO: add validation descriptor w/o calling accessors
    && !descriptor.configurable && (!has(descriptor, 'writable') || descriptor.writable) && (!has(descriptor, 'enumerable') || descriptor.enumerable)) {
      target[key] = descriptor.value;
      return target;
    }

    return nativeDefineProperty(target, key, descriptor);
  };

  if (descriptors) {
    if (!NATIVE_ARRAY_BUFFER_VIEWS) {
      objectGetOwnPropertyDescriptor.f = wrappedGetOwnPropertyDescriptor;
      objectDefineProperty.f = wrappedDefineProperty;
      addGetter(TypedArrayPrototype, 'buffer');
      addGetter(TypedArrayPrototype, 'byteOffset');
      addGetter(TypedArrayPrototype, 'byteLength');
      addGetter(TypedArrayPrototype, 'length');
    }

    _export({
      target: 'Object',
      stat: true,
      forced: !NATIVE_ARRAY_BUFFER_VIEWS
    }, {
      getOwnPropertyDescriptor: wrappedGetOwnPropertyDescriptor,
      defineProperty: wrappedDefineProperty
    });

    module.exports = function (TYPE, wrapper, CLAMPED) {
      var BYTES = TYPE.match(/\d+$/)[0] / 8;
      var CONSTRUCTOR_NAME = TYPE + (CLAMPED ? 'Clamped' : '') + 'Array';
      var GETTER = 'get' + TYPE;
      var SETTER = 'set' + TYPE;
      var NativeTypedArrayConstructor = global_1[CONSTRUCTOR_NAME];
      var TypedArrayConstructor = NativeTypedArrayConstructor;
      var TypedArrayConstructorPrototype = TypedArrayConstructor && TypedArrayConstructor.prototype;
      var exported = {};

      var getter = function (that, index) {
        var data = getInternalState(that);
        return data.view[GETTER](index * BYTES + data.byteOffset, true);
      };

      var setter = function (that, index, value) {
        var data = getInternalState(that);
        if (CLAMPED) value = (value = round(value)) < 0 ? 0 : value > 0xFF ? 0xFF : value & 0xFF;
        data.view[SETTER](index * BYTES + data.byteOffset, value, true);
      };

      var addElement = function (that, index) {
        nativeDefineProperty(that, index, {
          get: function () {
            return getter(this, index);
          },
          set: function (value) {
            return setter(this, index, value);
          },
          enumerable: true
        });
      };

      if (!NATIVE_ARRAY_BUFFER_VIEWS) {
        TypedArrayConstructor = wrapper(function (that, data, offset, $length) {
          anInstance(that, TypedArrayConstructor, CONSTRUCTOR_NAME);
          var index = 0;
          var byteOffset = 0;
          var buffer, byteLength, length;

          if (!isObject(data)) {
            length = toIndex(data);
            byteLength = length * BYTES;
            buffer = new ArrayBuffer(byteLength);
          } else if (isArrayBuffer(data)) {
            buffer = data;
            byteOffset = toOffset(offset, BYTES);
            var $len = data.byteLength;

            if ($length === undefined) {
              if ($len % BYTES) throw RangeError(WRONG_LENGTH);
              byteLength = $len - byteOffset;
              if (byteLength < 0) throw RangeError(WRONG_LENGTH);
            } else {
              byteLength = toLength($length) * BYTES;
              if (byteLength + byteOffset > $len) throw RangeError(WRONG_LENGTH);
            }

            length = byteLength / BYTES;
          } else if (isTypedArray(data)) {
            return fromList(TypedArrayConstructor, data);
          } else {
            return typedArrayFrom.call(TypedArrayConstructor, data);
          }

          setInternalState(that, {
            buffer: buffer,
            byteOffset: byteOffset,
            byteLength: byteLength,
            length: length,
            view: new DataView(buffer)
          });

          while (index < length) addElement(that, index++);
        });
        if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
        TypedArrayConstructorPrototype = TypedArrayConstructor.prototype = objectCreate(TypedArrayPrototype);
      } else if (typedArrayConstructorsRequireWrappers) {
        TypedArrayConstructor = wrapper(function (dummy, data, typedArrayOffset, $length) {
          anInstance(dummy, TypedArrayConstructor, CONSTRUCTOR_NAME);
          return inheritIfRequired(function () {
            if (!isObject(data)) return new NativeTypedArrayConstructor(toIndex(data));
            if (isArrayBuffer(data)) return $length !== undefined ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES), $length) : typedArrayOffset !== undefined ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES)) : new NativeTypedArrayConstructor(data);
            if (isTypedArray(data)) return fromList(TypedArrayConstructor, data);
            return typedArrayFrom.call(TypedArrayConstructor, data);
          }(), dummy, TypedArrayConstructor);
        });
        if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
        forEach(getOwnPropertyNames(NativeTypedArrayConstructor), function (key) {
          if (!(key in TypedArrayConstructor)) {
            createNonEnumerableProperty(TypedArrayConstructor, key, NativeTypedArrayConstructor[key]);
          }
        });
        TypedArrayConstructor.prototype = TypedArrayConstructorPrototype;
      }

      if (TypedArrayConstructorPrototype.constructor !== TypedArrayConstructor) {
        createNonEnumerableProperty(TypedArrayConstructorPrototype, 'constructor', TypedArrayConstructor);
      }

      if (TYPED_ARRAY_TAG) {
        createNonEnumerableProperty(TypedArrayConstructorPrototype, TYPED_ARRAY_TAG, CONSTRUCTOR_NAME);
      }

      exported[CONSTRUCTOR_NAME] = TypedArrayConstructor;
      _export({
        global: true,
        forced: TypedArrayConstructor != NativeTypedArrayConstructor,
        sham: !NATIVE_ARRAY_BUFFER_VIEWS
      }, exported);

      if (!(BYTES_PER_ELEMENT in TypedArrayConstructor)) {
        createNonEnumerableProperty(TypedArrayConstructor, BYTES_PER_ELEMENT, BYTES);
      }

      if (!(BYTES_PER_ELEMENT in TypedArrayConstructorPrototype)) {
        createNonEnumerableProperty(TypedArrayConstructorPrototype, BYTES_PER_ELEMENT, BYTES);
      }

      setSpecies(CONSTRUCTOR_NAME);
    };
  } else module.exports = function () {
    /* empty */
  };
});

// https://tc39.github.io/ecma262/#sec-typedarray-objects

typedArrayConstructor('Float32', function (init) {
  return function Float32Array(data, byteOffset, length) {
    return init(this, data, byteOffset, length);
  };
});

// https://tc39.github.io/ecma262/#sec-typedarray-objects

typedArrayConstructor('Float64', function (init) {
  return function Float64Array(data, byteOffset, length) {
    return init(this, data, byteOffset, length);
  };
});

var min$2 = Math.min; // `Array.prototype.copyWithin` method implementation
// https://tc39.github.io/ecma262/#sec-array.prototype.copywithin

var arrayCopyWithin = [].copyWithin || function copyWithin(target
/* = 0 */
, start
/* = 0, end = @length */
) {
  var O = toObject(this);
  var len = toLength(O.length);
  var to = toAbsoluteIndex(target, len);
  var from = toAbsoluteIndex(start, len);
  var end = arguments.length > 2 ? arguments[2] : undefined;
  var count = min$2((end === undefined ? len : toAbsoluteIndex(end, len)) - from, len - to);
  var inc = 1;

  if (from < to && to < from + count) {
    inc = -1;
    from += count - 1;
    to += count - 1;
  }

  while (count-- > 0) {
    if (from in O) O[to] = O[from];else delete O[to];
    to += inc;
    from += inc;
  }

  return O;
};

var aTypedArray$1 = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$1 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.copyWithin` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.copywithin

exportTypedArrayMethod$1('copyWithin', function copyWithin(target, start
/* , end */
) {
  return arrayCopyWithin.call(aTypedArray$1(this), target, start, arguments.length > 2 ? arguments[2] : undefined);
});

var $every = arrayIteration.every;
var aTypedArray$2 = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$2 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.every` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every

exportTypedArrayMethod$2('every', function every(callbackfn
/* , thisArg */
) {
  return $every(aTypedArray$2(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
});

var aTypedArray$3 = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$3 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.fill` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.fill
// eslint-disable-next-line no-unused-vars

exportTypedArrayMethod$3('fill', function fill(value
/* , start, end */
) {
  return arrayFill.apply(aTypedArray$3(this), arguments);
});

var $filter = arrayIteration.filter;
var aTypedArray$4 = arrayBufferViewCore.aTypedArray;
var aTypedArrayConstructor$2 = arrayBufferViewCore.aTypedArrayConstructor;
var exportTypedArrayMethod$4 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.filter` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.filter

exportTypedArrayMethod$4('filter', function filter(callbackfn
/* , thisArg */
) {
  var list = $filter(aTypedArray$4(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
  var C = speciesConstructor(this, this.constructor);
  var index = 0;
  var length = list.length;
  var result = new (aTypedArrayConstructor$2(C))(length);

  while (length > index) result[index] = list[index++];

  return result;
});

var $find$1 = arrayIteration.find;
var aTypedArray$5 = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$5 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.find` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.find

exportTypedArrayMethod$5('find', function find(predicate
/* , thisArg */
) {
  return $find$1(aTypedArray$5(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
});

var $findIndex = arrayIteration.findIndex;
var aTypedArray$6 = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$6 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.findIndex` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.findindex

exportTypedArrayMethod$6('findIndex', function findIndex(predicate
/* , thisArg */
) {
  return $findIndex(aTypedArray$6(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
});

var $forEach$1 = arrayIteration.forEach;
var aTypedArray$7 = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$7 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.forEach` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.foreach

exportTypedArrayMethod$7('forEach', function forEach(callbackfn
/* , thisArg */
) {
  $forEach$1(aTypedArray$7(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
});

var $includes$1 = arrayIncludes.includes;
var aTypedArray$8 = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$8 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.includes` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.includes

exportTypedArrayMethod$8('includes', function includes(searchElement
/* , fromIndex */
) {
  return $includes$1(aTypedArray$8(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
});

var $indexOf = arrayIncludes.indexOf;
var aTypedArray$9 = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$9 = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.indexOf` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.indexof

exportTypedArrayMethod$9('indexOf', function indexOf(searchElement
/* , fromIndex */
) {
  return $indexOf(aTypedArray$9(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
});

var ITERATOR$6 = wellKnownSymbol('iterator');
var Uint8Array$1 = global_1.Uint8Array;
var arrayValues = es_array_iterator.values;
var arrayKeys = es_array_iterator.keys;
var arrayEntries = es_array_iterator.entries;
var aTypedArray$a = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$a = arrayBufferViewCore.exportTypedArrayMethod;
var nativeTypedArrayIterator = Uint8Array$1 && Uint8Array$1.prototype[ITERATOR$6];
var CORRECT_ITER_NAME = !!nativeTypedArrayIterator && (nativeTypedArrayIterator.name == 'values' || nativeTypedArrayIterator.name == undefined);

var typedArrayValues = function values() {
  return arrayValues.call(aTypedArray$a(this));
}; // `%TypedArray%.prototype.entries` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.entries


exportTypedArrayMethod$a('entries', function entries() {
  return arrayEntries.call(aTypedArray$a(this));
}); // `%TypedArray%.prototype.keys` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.keys

exportTypedArrayMethod$a('keys', function keys() {
  return arrayKeys.call(aTypedArray$a(this));
}); // `%TypedArray%.prototype.values` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.values

exportTypedArrayMethod$a('values', typedArrayValues, !CORRECT_ITER_NAME); // `%TypedArray%.prototype[@@iterator]` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype-@@iterator

exportTypedArrayMethod$a(ITERATOR$6, typedArrayValues, !CORRECT_ITER_NAME);

var aTypedArray$b = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$b = arrayBufferViewCore.exportTypedArrayMethod;
var $join = [].join; // `%TypedArray%.prototype.join` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.join
// eslint-disable-next-line no-unused-vars

exportTypedArrayMethod$b('join', function join(separator) {
  return $join.apply(aTypedArray$b(this), arguments);
});

var arrayMethodIsStrict = function (METHOD_NAME, argument) {
  var method = [][METHOD_NAME];
  return !!method && fails(function () {
    // eslint-disable-next-line no-useless-call,no-throw-literal
    method.call(null, argument || function () {
      throw 1;
    }, 1);
  });
};

var min$3 = Math.min;
var nativeLastIndexOf = [].lastIndexOf;
var NEGATIVE_ZERO = !!nativeLastIndexOf && 1 / [1].lastIndexOf(1, -0) < 0;
var STRICT_METHOD = arrayMethodIsStrict('lastIndexOf'); // For preventing possible almost infinite loop in non-standard implementations, test the forward version of the method

var USES_TO_LENGTH$2 = arrayMethodUsesToLength('indexOf', {
  ACCESSORS: true,
  1: 0
});
var FORCED = NEGATIVE_ZERO || !STRICT_METHOD || !USES_TO_LENGTH$2; // `Array.prototype.lastIndexOf` method implementation
// https://tc39.github.io/ecma262/#sec-array.prototype.lastindexof

var arrayLastIndexOf = FORCED ? function lastIndexOf(searchElement
/* , fromIndex = @[*-1] */
) {
  // convert -0 to +0
  if (NEGATIVE_ZERO) return nativeLastIndexOf.apply(this, arguments) || 0;
  var O = toIndexedObject(this);
  var length = toLength(O.length);
  var index = length - 1;
  if (arguments.length > 1) index = min$3(index, toInteger(arguments[1]));
  if (index < 0) index = length + index;

  for (; index >= 0; index--) if (index in O && O[index] === searchElement) return index || 0;

  return -1;
} : nativeLastIndexOf;

var aTypedArray$c = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$c = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.lastIndexOf` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.lastindexof
// eslint-disable-next-line no-unused-vars

exportTypedArrayMethod$c('lastIndexOf', function lastIndexOf(searchElement
/* , fromIndex */
) {
  return arrayLastIndexOf.apply(aTypedArray$c(this), arguments);
});

var $map = arrayIteration.map;
var aTypedArray$d = arrayBufferViewCore.aTypedArray;
var aTypedArrayConstructor$3 = arrayBufferViewCore.aTypedArrayConstructor;
var exportTypedArrayMethod$d = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.map` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.map

exportTypedArrayMethod$d('map', function map(mapfn
/* , thisArg */
) {
  return $map(aTypedArray$d(this), mapfn, arguments.length > 1 ? arguments[1] : undefined, function (O, length) {
    return new (aTypedArrayConstructor$3(speciesConstructor(O, O.constructor)))(length);
  });
});

var createMethod$4 = function (IS_RIGHT) {
  return function (that, callbackfn, argumentsLength, memo) {
    aFunction$1(callbackfn);
    var O = toObject(that);
    var self = indexedObject(O);
    var length = toLength(O.length);
    var index = IS_RIGHT ? length - 1 : 0;
    var i = IS_RIGHT ? -1 : 1;
    if (argumentsLength < 2) while (true) {
      if (index in self) {
        memo = self[index];
        index += i;
        break;
      }

      index += i;

      if (IS_RIGHT ? index < 0 : length <= index) {
        throw TypeError('Reduce of empty array with no initial value');
      }
    }

    for (; IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
      memo = callbackfn(memo, self[index], index, O);
    }

    return memo;
  };
};

var arrayReduce = {
  // `Array.prototype.reduce` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.reduce
  left: createMethod$4(false),
  // `Array.prototype.reduceRight` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.reduceright
  right: createMethod$4(true)
};

var $reduce = arrayReduce.left;
var aTypedArray$e = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$e = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.reduce` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduce

exportTypedArrayMethod$e('reduce', function reduce(callbackfn
/* , initialValue */
) {
  return $reduce(aTypedArray$e(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
});

var $reduceRight = arrayReduce.right;
var aTypedArray$f = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$f = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.reduceRicht` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduceright

exportTypedArrayMethod$f('reduceRight', function reduceRight(callbackfn
/* , initialValue */
) {
  return $reduceRight(aTypedArray$f(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
});

var aTypedArray$g = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$g = arrayBufferViewCore.exportTypedArrayMethod;
var floor$2 = Math.floor; // `%TypedArray%.prototype.reverse` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reverse

exportTypedArrayMethod$g('reverse', function reverse() {
  var that = this;
  var length = aTypedArray$g(that).length;
  var middle = floor$2(length / 2);
  var index = 0;
  var value;

  while (index < middle) {
    value = that[index];
    that[index++] = that[--length];
    that[length] = value;
  }

  return that;
});

var aTypedArray$h = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$h = arrayBufferViewCore.exportTypedArrayMethod;
var FORCED$1 = fails(function () {
  // eslint-disable-next-line no-undef
  new Int8Array(1).set({});
}); // `%TypedArray%.prototype.set` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.set

exportTypedArrayMethod$h('set', function set(arrayLike
/* , offset */
) {
  aTypedArray$h(this);
  var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);
  var length = this.length;
  var src = toObject(arrayLike);
  var len = toLength(src.length);
  var index = 0;
  if (len + offset > length) throw RangeError('Wrong length');

  while (index < len) this[offset + index] = src[index++];
}, FORCED$1);

var aTypedArray$i = arrayBufferViewCore.aTypedArray;
var aTypedArrayConstructor$4 = arrayBufferViewCore.aTypedArrayConstructor;
var exportTypedArrayMethod$i = arrayBufferViewCore.exportTypedArrayMethod;
var $slice = [].slice;
var FORCED$2 = fails(function () {
  // eslint-disable-next-line no-undef
  new Int8Array(1).slice();
}); // `%TypedArray%.prototype.slice` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.slice

exportTypedArrayMethod$i('slice', function slice(start, end) {
  var list = $slice.call(aTypedArray$i(this), start, end);
  var C = speciesConstructor(this, this.constructor);
  var index = 0;
  var length = list.length;
  var result = new (aTypedArrayConstructor$4(C))(length);

  while (length > index) result[index] = list[index++];

  return result;
}, FORCED$2);

var $some = arrayIteration.some;
var aTypedArray$j = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$j = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.some` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.some

exportTypedArrayMethod$j('some', function some(callbackfn
/* , thisArg */
) {
  return $some(aTypedArray$j(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
});

var aTypedArray$k = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$k = arrayBufferViewCore.exportTypedArrayMethod;
var $sort = [].sort; // `%TypedArray%.prototype.sort` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort

exportTypedArrayMethod$k('sort', function sort(comparefn) {
  return $sort.call(aTypedArray$k(this), comparefn);
});

var aTypedArray$l = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$l = arrayBufferViewCore.exportTypedArrayMethod; // `%TypedArray%.prototype.subarray` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.subarray

exportTypedArrayMethod$l('subarray', function subarray(begin, end) {
  var O = aTypedArray$l(this);
  var length = O.length;
  var beginIndex = toAbsoluteIndex(begin, length);
  return new (speciesConstructor(O, O.constructor))(O.buffer, O.byteOffset + beginIndex * O.BYTES_PER_ELEMENT, toLength((end === undefined ? length : toAbsoluteIndex(end, length)) - beginIndex));
});

var Int8Array$3 = global_1.Int8Array;
var aTypedArray$m = arrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod$m = arrayBufferViewCore.exportTypedArrayMethod;
var $toLocaleString = [].toLocaleString;
var $slice$1 = [].slice; // iOS Safari 6.x fails here

var TO_LOCALE_STRING_BUG = !!Int8Array$3 && fails(function () {
  $toLocaleString.call(new Int8Array$3(1));
});
var FORCED$3 = fails(function () {
  return [1, 2].toLocaleString() != new Int8Array$3([1, 2]).toLocaleString();
}) || !fails(function () {
  Int8Array$3.prototype.toLocaleString.call([1, 2]);
}); // `%TypedArray%.prototype.toLocaleString` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tolocalestring

exportTypedArrayMethod$m('toLocaleString', function toLocaleString() {
  return $toLocaleString.apply(TO_LOCALE_STRING_BUG ? $slice$1.call(aTypedArray$m(this)) : aTypedArray$m(this), arguments);
}, FORCED$3);

var exportTypedArrayMethod$n = arrayBufferViewCore.exportTypedArrayMethod;
var Uint8Array$2 = global_1.Uint8Array;
var Uint8ArrayPrototype = Uint8Array$2 && Uint8Array$2.prototype || {};
var arrayToString = [].toString;
var arrayJoin = [].join;

if (fails(function () {
  arrayToString.call({});
})) {
  arrayToString = function toString() {
    return arrayJoin.call(this);
  };
}

var IS_NOT_ARRAY_METHOD = Uint8ArrayPrototype.toString != arrayToString; // `%TypedArray%.prototype.toString` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tostring

exportTypedArrayMethod$n('toString', arrayToString, IS_NOT_ARRAY_METHOD);

/**
 * @summary 数学ユーティリティー
 *
 * @classdesc
 * <p>数学関連の関数または定数を定義するユーティリティークラスである。</p>
 * <p>このクラスは static メンバーしか持たない。</p>
 *
 * @hideconstructor
 * @memberof mapray
 * @see mapray.Matrix
 */
var GeoMath =
/*#__PURE__*/
function () {
  function GeoMath() {
    _classCallCheck(this, GeoMath);
  }

  _createClass(GeoMath, null, [{
    key: "createMatrix",

    /**
     * @summary 行列オブジェクトを作成
     * @desc
     * <p>mat を複製する。ただし mat を省略したときは、すべての要素が 0 の行列を生成する。</p>
     *
     * @param  {mapray.Matrix} [mat]  入力行列
     * @return {mapray.Matrix}        新しい行列
     */
    value: function createMatrix(mat) {
      return new Float64Array(mat || 16);
    }
    /**
     * @summary 行列 (単精度) オブジェクトを作成
     * @param  {mapray.Matrix} [mat]  入力行列
     * @return {mapray.Matrix}        新しい行列
     * @package
     */

  }, {
    key: "createMatrixf",
    value: function createMatrixf(mat) {
      return new Float32Array(mat || 16);
    }
    /**
     * @summary 4 次ベクトルの生成
     * @desc
     * <p>vec を複製して 4 次ベクトルを生成する。ただし vec を省略したときは、すべての要素が 0 のベクトルを生成する。</p>
     * @param  {mapray.Vector4} [vec]  入力ベクトル
     * @return {mapray.Vector4}        新しいベクトル
     */

  }, {
    key: "createVector4",
    value: function createVector4(vec) {
      return new Float64Array(vec || 4);
    }
    /**
     * @summary 4 次ベクトル (単精度) の生成
     * @param  {mapray.Vector4} [vec]  入力ベクトル
     * @return {mapray.Vector4}        新しいベクトル
     * @package
     */

  }, {
    key: "createVector4f",
    value: function createVector4f(vec) {
      return new Float32Array(vec || 4);
    }
    /**
     * @summary 3 次ベクトルの生成
     * <p>vec を複製して 3 次ベクトルを生成する。ただし vec を省略したときは、すべての要素が 0 のベクトルを生成する。</p>
     * @param  {mapray.Vector3} [vec]  入力ベクトル
     * @return {mapray.Vector3}        新しいベクトル
     */

  }, {
    key: "createVector3",
    value: function createVector3(vec) {
      return new Float64Array(vec || 3);
    }
    /**
     * @summary 3 次ベクトル (単精度) の生成
     * @param  {mapray.Vector3} [vec]  入力ベクトル
     * @return {mapray.Vector3}        新しいベクトル
     * @package
     */

  }, {
    key: "createVector3f",
    value: function createVector3f(vec) {
      return new Float32Array(vec || 3);
    }
    /**
     * @summary 2 次ベクトルの生成
     * <p>vec を複製して 2 次ベクトルを生成する。ただし vec を省略したときは、すべての要素が 0 のベクトルを生成する。</p>
     * @param  {mapray.Vector2} [vec]  入力ベクトル
     * @return {mapray.Vector2}        新しいベクトル
     */

  }, {
    key: "createVector2",
    value: function createVector2(vec) {
      return new Float64Array(vec || 2);
    }
    /**
     * @summary 2 次ベクトル (単精度) の生成
     * @param  {mapray.Vector2} [vec]  入力ベクトル
     * @return {mapray.Vector2}        新しいベクトル
     * @package
     */

  }, {
    key: "createVector2f",
    value: function createVector2f(vec) {
      return new Float32Array(vec || 2);
    }
    /**
     * @summary 行列を代入
     * @desc
     * <p>src を dst に代入する。</p>
     * @param  {mapray.Matrix} src  代入元
     * @param  {mapray.Matrix} dst  代入先
     * @return {mapray.Matrix}      dst
     */

  }, {
    key: "copyMatrix",
    value: function copyMatrix(src, dst) {
      for (var i = 0; i < 16; ++i) {
        dst[i] = src[i];
      }

      return dst;
    }
    /**
     * @summary 4 次ベクトルを代入
     * @desc
     * <p>src を dst に代入する。</p>
     * @param  {mapray.Vector4} src  代入元
     * @param  {mapray.Vector4} dst  代入先
     * @return {mapray.Vector4}      dst
     */

  }, {
    key: "copyVector4",
    value: function copyVector4(src, dst) {
      for (var i = 0; i < 4; ++i) {
        dst[i] = src[i];
      }

      return dst;
    }
    /**
     * @summary 3 次ベクトルを代入
     * @desc
     * <p>src を dst に代入する。</p>
     * @param  {mapray.Vector3} src  代入元
     * @param  {mapray.Vector3} dst  代入先
     * @return {mapray.Vector3}      dst
     */

  }, {
    key: "copyVector3",
    value: function copyVector3(src, dst) {
      for (var i = 0; i < 3; ++i) {
        dst[i] = src[i];
      }

      return dst;
    }
    /**
     * @summary 2 次ベクトルを代入
     * @desc
     * <p>src を dst に代入する。</p>
     * @param  {mapray.Vector2} src  代入元
     * @param  {mapray.Vector2} dst  代入先
     * @return {mapray.Vector2}      dst
     */

  }, {
    key: "copyVector2",
    value: function copyVector2(src, dst) {
      dst[0] = src[0];
      dst[1] = src[1];
      return dst;
    }
    /**
     * @summary 恒等行列を設定
     * @param  {mapray.Matrix} dst  結果を代入する行列
     * @return {mapray.Matrix}      dst
     */

  }, {
    key: "setIdentity",
    value: function setIdentity(dst) {
      dst[0] = 1;
      dst[1] = 0;
      dst[2] = 0;
      dst[3] = 0;
      dst[4] = 0;
      dst[5] = 1;
      dst[6] = 0;
      dst[7] = 0;
      dst[8] = 0;
      dst[9] = 0;
      dst[10] = 1;
      dst[11] = 0;
      dst[12] = 0;
      dst[13] = 0;
      dst[14] = 0;
      dst[15] = 1;
      return dst;
    }
    /**
     * @summary 3 次ベクトルの内積を計算
     * @param  {mapray.Vector3} a  左のベクトル
     * @param  {mapray.Vector3} b  右のベクトル
     * @return {number}            a と b の内積
     */

  }, {
    key: "dot3",
    value: function dot3(a, b) {
      return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
    }
    /**
     * @summary 3次ベクトルの外積を計算
     * @param  {mapray.Vector3} a    左のベクトル
     * @param  {mapray.Vector3} b    右のベクトル
     * @param  {mapray.Vector3} dst  a と b の外積を代入するベクトル
     * @return {mapray.Vector3}      dst
     */

  }, {
    key: "cross3",
    value: function cross3(a, b, dst) {
      var x = a[1] * b[2] - a[2] * b[1];
      var y = a[2] * b[0] - a[0] * b[2];
      var z = a[0] * b[1] - a[1] * b[0];
      dst[0] = x;
      dst[1] = y;
      dst[2] = z;
      return dst;
    }
    /**
     * @summary 3次ベクトルの正規化を計算
     * @param  {mapray.Vector3} vec  ベクトル
     * @param  {mapray.Vector3} dst  正規化された値を代入するベクトル
     * @return {mapray.Vector3}      dst
     */

  }, {
    key: "normalize3",
    value: function normalize3(vec, dst) {
      var x = vec[0];
      var y = vec[1];
      var z = vec[2];
      var ilen = 1 / Math.sqrt(x * x + y * y + z * z); // 長さの逆数

      dst[0] = vec[0] * ilen;
      dst[1] = vec[1] * ilen;
      dst[2] = vec[2] * ilen;
      return dst;
    }
  }, {
    key: "scale3",
    value: function scale3(a, vec, dst) {
      dst[0] = a * vec[0];
      dst[1] = a * vec[1];
      dst[2] = a * vec[2];
      return dst;
    }
    /**
     * @summary 行列の積を計算 (アフィン変換 x アフィン変換)
     * @param  {mapray.Matrix}  a    左の行列
     * @param  {mapray.Matrix}  b    右の行列
     * @param  {mapray.Matrix}  dst  結果を代入する行列
     * @return {mapray.Matrix}       dst
     */

  }, {
    key: "mul_AA",
    value: function mul_AA(a, b, dst) {
      var a00 = a[0],
          a01 = a[4],
          a02 = a[8],
          a03 = a[12],
          a10 = a[1],
          a11 = a[5],
          a12 = a[9],
          a13 = a[13],
          a20 = a[2],
          a21 = a[6],
          a22 = a[10],
          a23 = a[14];
      var b00 = b[0],
          b01 = b[4],
          b02 = b[8],
          b03 = b[12],
          b10 = b[1],
          b11 = b[5],
          b12 = b[9],
          b13 = b[13],
          b20 = b[2],
          b21 = b[6],
          b22 = b[10],
          b23 = b[14];
      dst[0] = a00 * b00 + a01 * b10 + a02 * b20;
      dst[1] = a10 * b00 + a11 * b10 + a12 * b20;
      dst[2] = a20 * b00 + a21 * b10 + a22 * b20;
      dst[3] = 0;
      dst[4] = a00 * b01 + a01 * b11 + a02 * b21;
      dst[5] = a10 * b01 + a11 * b11 + a12 * b21;
      dst[6] = a20 * b01 + a21 * b11 + a22 * b21;
      dst[7] = 0;
      dst[8] = a00 * b02 + a01 * b12 + a02 * b22;
      dst[9] = a10 * b02 + a11 * b12 + a12 * b22;
      dst[10] = a20 * b02 + a21 * b12 + a22 * b22;
      dst[11] = 0;
      dst[12] = a00 * b03 + a01 * b13 + a02 * b23 + a03;
      dst[13] = a10 * b03 + a11 * b13 + a12 * b23 + a13;
      dst[14] = a20 * b03 + a21 * b13 + a22 * b23 + a23;
      dst[15] = 1;
      return dst;
    }
    /**
     * @summary 行列の積を計算 (一般変換 x アフィン変換)
     * @param  {mapray.Matrix}  a    左の行列
     * @param  {mapray.Matrix}  b    右の行列
     * @param  {mapray.Matrix}  dst  結果を代入する行列
     * @return {mapray.Matrix}       dst
     */

  }, {
    key: "mul_GA",
    value: function mul_GA(a, b, dst) {
      var a00 = a[0],
          a01 = a[4],
          a02 = a[8],
          a03 = a[12],
          a10 = a[1],
          a11 = a[5],
          a12 = a[9],
          a13 = a[13],
          a20 = a[2],
          a21 = a[6],
          a22 = a[10],
          a23 = a[14],
          a30 = a[3],
          a31 = a[7],
          a32 = a[11],
          a33 = a[15];
      var b00 = b[0],
          b01 = b[4],
          b02 = b[8],
          b03 = b[12],
          b10 = b[1],
          b11 = b[5],
          b12 = b[9],
          b13 = b[13],
          b20 = b[2],
          b21 = b[6],
          b22 = b[10],
          b23 = b[14];
      dst[0] = a00 * b00 + a01 * b10 + a02 * b20;
      dst[1] = a10 * b00 + a11 * b10 + a12 * b20;
      dst[2] = a20 * b00 + a21 * b10 + a22 * b20;
      dst[3] = a30 * b00 + a31 * b10 + a32 * b20;
      dst[4] = a00 * b01 + a01 * b11 + a02 * b21;
      dst[5] = a10 * b01 + a11 * b11 + a12 * b21;
      dst[6] = a20 * b01 + a21 * b11 + a22 * b21;
      dst[7] = a30 * b01 + a31 * b11 + a32 * b21;
      dst[8] = a00 * b02 + a01 * b12 + a02 * b22;
      dst[9] = a10 * b02 + a11 * b12 + a12 * b22;
      dst[10] = a20 * b02 + a21 * b12 + a22 * b22;
      dst[11] = a30 * b02 + a31 * b12 + a32 * b22;
      dst[12] = a00 * b03 + a01 * b13 + a02 * b23 + a03;
      dst[13] = a10 * b03 + a11 * b13 + a12 * b23 + a13;
      dst[14] = a20 * b03 + a21 * b13 + a22 * b23 + a23;
      dst[15] = a30 * b03 + a31 * b13 + a32 * b23 + a33;
      return dst;
    }
    /**
     * @summary 行列の積を計算 (投影変換 x アフィン変換)
     * @param  {mapray.Matrix}  a    左の行列
     * @param  {mapray.Matrix}  b    右の行列
     * @param  {mapray.Matrix}  dst  結果を代入する行列
     * @return {mapray.Matrix}       dst
     */

  }, {
    key: "mul_PzA",
    value: function mul_PzA(a, b, dst) {
      var a00 = a[0],
          a02 = a[8],
          a03 = a[12];
      var a11 = a[5],
          a12 = a[9],
          a13 = a[13];
      var a22 = a[10],
          a23 = a[14];
      var a32 = a[11],
          a33 = a[15];
      var b00 = b[0],
          b01 = b[4],
          b02 = b[8],
          b03 = b[12],
          b10 = b[1],
          b11 = b[5],
          b12 = b[9],
          b13 = b[13],
          b20 = b[2],
          b21 = b[6],
          b22 = b[10],
          b23 = b[14];
      dst[0] = a00 * b00 + a02 * b20;
      dst[1] = a11 * b10 + a12 * b20;
      dst[2] = a22 * b20;
      dst[3] = a32 * b20;
      dst[4] = a00 * b01 + a02 * b21;
      dst[5] = a11 * b11 + a12 * b21;
      dst[6] = a22 * b21;
      dst[7] = a32 * b21;
      dst[8] = a00 * b02 + a02 * b22;
      dst[9] = a11 * b12 + a12 * b22;
      dst[10] = a22 * b22;
      dst[11] = a32 * b22;
      dst[12] = a00 * b03 + a02 * b23 + a03;
      dst[13] = a11 * b13 + a12 * b23 + a13;
      dst[14] = a22 * b23 + a23;
      dst[15] = a32 * b23 + a33;
      return dst;
    }
    /**
     * @summary 逆行列を計算 (アフィン変換)
     * @param  {mapray.Matrix}  mat  行列
     * @param  {mapray.Matrix}  dst  結果を代入する行列
     * @return {mapray.Matrix}       dst
     */

  }, {
    key: "inverse_A",
    value: function inverse_A(mat, dst) {
      var a00 = mat[0],
          a01 = mat[4],
          a02 = mat[8],
          a03 = mat[12],
          a10 = mat[1],
          a11 = mat[5],
          a12 = mat[9],
          a13 = mat[13],
          a20 = mat[2],
          a21 = mat[6],
          a22 = mat[10],
          a23 = mat[14]; // cofactors

      var b00 = a11 * a22 - a21 * a12;
      var b01 = a20 * a12 - a10 * a22;
      var b02 = a10 * a21 - a20 * a11;
      var b10 = a21 * a02 - a01 * a22;
      var b11 = a00 * a22 - a20 * a02;
      var b12 = a20 * a01 - a00 * a21;
      var b20 = a01 * a12 - a11 * a02;
      var b21 = a10 * a02 - a00 * a12;
      var b22 = a00 * a11 - a10 * a01;
      var b30 = -(a03 * b00 + a13 * b10 + a23 * b20);
      var b31 = -(a03 * b01 + a13 * b11 + a23 * b21);
      var b32 = -(a03 * b02 + a13 * b12 + a23 * b22); // 1/det(mat)

      var idet = 1 / (a00 * b00 + a01 * b01 + a02 * b02); // matの余因子行列 / det(mat)

      dst[0] = b00 * idet;
      dst[1] = b01 * idet;
      dst[2] = b02 * idet;
      dst[3] = 0;
      dst[4] = b10 * idet;
      dst[5] = b11 * idet;
      dst[6] = b12 * idet;
      dst[7] = 0;
      dst[8] = b20 * idet;
      dst[9] = b21 * idet;
      dst[10] = b22 * idet;
      dst[11] = 0;
      dst[12] = b30 * idet;
      dst[13] = b31 * idet;
      dst[14] = b32 * idet;
      dst[15] = 1;
      return dst;
    }
    /**
     * @summary 平面ベクトルを変換 (アフィン変換)
     * @desc
     * <p>mat には平面ベクトルを変換する行列を指定する。
     * 位置ベクトルを変換する行列が M なら、平面ベクトルを変換する行列は M<sup>-1</sup> を指定する。</p>
     *
     * <p>dst には plane * mat が代入される。</p>
     *
     * @param  mat   {mapray.Matrix}   変換行列
     * @param  plane {mapray.Vector4}  平面ベクトル
     * @param  dst   {mapray.Vector4}  結果を代入するベクトル
     * @return       {mapray.Vector4}  dst
     */

  }, {
    key: "transformPlane_A",
    value: function transformPlane_A(mat, plane, dst) {
      var m = mat;
      var x = plane[0];
      var y = plane[1];
      var z = plane[2];
      var w = plane[3];
      dst[0] = x * m[0] + y * m[1] + z * m[2];
      dst[1] = x * m[4] + y * m[5] + z * m[6];
      dst[2] = x * m[8] + y * m[9] + z * m[10];
      dst[3] = x * m[12] + y * m[13] + z * m[14] + w;
      return dst;
    }
    /**
     * @summary 座標変換行列を計算 (Inou 球面座標系 → 地心直交座標系)
     * @desc
     * <p>原点が position の直交座標系 (LOCS) から地心直交座標系 (GOCS) に変換する行列を計算する。</p>
     * <p>position.height + GeoMath.EARTH_RADIUS > 0 かつ position.latitude == 0 のとき、LOCS の Z 軸は上方向、Y 軸は北方向、X 軸は東方向となる。</p>
     *
     * @param  {object}         position             位置 (Inou 球面座標系)
     * @param  {number}         position.latitude    緯度 (Degrees)
     * @param  {number}         position.longitude   経度 (Degrees)
     * @param  {number}         position.height      高度 (Meters)
     * @param  {mapray.Matrix}  dst                  結果を代入する行列
     * @return {mapray.Matrix}                       dst
     *
     * @deprecated {@link mapray.GeoPoint#getMlocsToGocsMatrix} の使用を推奨
     */

  }, {
    key: "iscs_to_gocs_matrix",
    value: function iscs_to_gocs_matrix(position, dst) {
      var λ = position.longitude * GeoMath.DEGREE;
      var φ = position.latitude * GeoMath.DEGREE;
      var sinλ = Math.sin(λ);
      var cosλ = Math.cos(λ);
      var sinφ = Math.sin(φ);
      var cosφ = Math.cos(φ);
      var r = GeoMath.EARTH_RADIUS + position.height; // ∂u/∂λ

      dst[0] = -sinλ;
      dst[1] = cosλ;
      dst[2] = 0;
      dst[3] = 0; // ∂u/∂φ

      dst[4] = -cosλ * sinφ;
      dst[5] = -sinλ * sinφ;
      dst[6] = cosφ;
      dst[7] = 0; // u = {x, y, z} / r

      dst[8] = cosφ * cosλ;
      dst[9] = cosφ * sinλ;
      dst[10] = sinφ;
      dst[11] = 0; // {x, y, z}

      dst[12] = r * cosφ * cosλ;
      dst[13] = r * cosφ * sinλ;
      dst[14] = r * sinφ;
      dst[15] = 1;
      return dst;
    }
    /**
     * @summary 地心直交座標を Inou 球面座標に変換
     *
     * @param  {mapray.Vector3} src            入力 GOCS 座標 (Meters)
     * @param  {object}         dst            出力 ISCS 座標
     * @param  {number}         dst.latitude   緯度 (Degrees)
     * @param  {number}         dst.longitude  経度 (Degrees)
     * @param  {number}         dst.height     高度 (Meters)
     * @return {object}                        dst
     *
     * @deprecated {@link mapray.GeoPoint#setFromGocs} の使用を推奨
     */

  }, {
    key: "gocs_to_iscs",
    value: function gocs_to_iscs(src, dst) {
      var x = src[0];
      var y = src[1];
      var z = src[2];
      var x2 = x * x;
      var y2 = y * y;
      var z2 = z * z; // 緯度 φ = ArcTan[z / √(x^2 + y^2)]
      // 経度 λ = ArcTan[x, y]

      if (x != 0 || y != 0) {
        dst.latitude = Math.atan(z / Math.sqrt(x2 + y2)) / GeoMath.DEGREE;
        dst.longitude = Math.atan2(y, x) / GeoMath.DEGREE;
      } else {
        // x == 0 && y == 0
        if (z > 0) dst.latitude = 90;else if (z < 0) dst.latitude = -90;else dst.latitude = 0;
        dst.longitude = 0;
      } // 高度 h = √(x^2 + y^2 + z^2) - R


      dst.height = Math.sqrt(x2 + y2 + z2) - GeoMath.EARTH_RADIUS;
      return dst;
    }
    /**
     * @summary 座標変換行列を計算 (視点座標系 → クリップ同次座標系)
     * @param  {number}        left
     * @param  {number}        right
     * @param  {number}        bottom
     * @param  {number}        top
     * @param  {number}        nearVal
     * @param  {number}        farVal
     * @param  {mapray.Matrix} dst     結果を代入する行列
     * @return {mapray.Matrix}         dst
     *
     * @see https://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml
     */

  }, {
    key: "frustum_matrix",
    value: function frustum_matrix(left, right, bottom, top, nearVal, farVal, dst) {
      dst[0] = 2 * nearVal / (right - left);
      dst[1] = 0;
      dst[2] = 0;
      dst[3] = 0;
      dst[4] = 0;
      dst[5] = 2 * nearVal / (top - bottom);
      dst[6] = 0;
      dst[7] = 0;
      dst[8] = (right + left) / (right - left);
      dst[9] = (top + bottom) / (top - bottom);
      dst[10] = (farVal + nearVal) / (nearVal - farVal);
      dst[11] = -1;
      dst[12] = 0;
      dst[13] = 0;
      dst[14] = 2 * farVal * nearVal / (nearVal - farVal);
      dst[15] = 0;
      return dst;
    }
    /**
     * @summary 座標変換行列を計算 (右手座標系 → 視点座標系)
     *
     * @param  {mapray.Vector3}  eye     視点の位置
     * @param  {mapray.Vector3}  center  注視点の位置
     * @param  {mapray.Vector3}  up      上方向ベクトル
     * @param  {mapray.Matrix}   dst     結果を代入する行列
     * @return {mapray.Matrix}           dst
     */

  }, {
    key: "lookat_matrix",
    value: function lookat_matrix(eye, center, up, dst) {
      var xaxis = GeoMath._xaxis;
      var yaxis = GeoMath._yaxis;
      var zaxis = GeoMath._zaxis;
      zaxis[0] = eye[0] - center[0];
      zaxis[1] = eye[1] - center[1];
      zaxis[2] = eye[2] - center[2];
      GeoMath.normalize3(zaxis, zaxis);
      GeoMath.cross3(up, zaxis, xaxis);
      GeoMath.normalize3(xaxis, xaxis);
      GeoMath.cross3(zaxis, xaxis, yaxis); // 単位ベクトルになっている

      dst[0] = xaxis[0];
      dst[1] = xaxis[1];
      dst[2] = xaxis[2];
      dst[3] = 0;
      dst[4] = yaxis[0];
      dst[5] = yaxis[1];
      dst[6] = yaxis[2];
      dst[7] = 0;
      dst[8] = zaxis[0];
      dst[9] = zaxis[1];
      dst[10] = zaxis[2];
      dst[11] = 0;
      dst[12] = eye[0];
      dst[13] = eye[1];
      dst[14] = eye[2];
      dst[15] = 1;
      return dst;
    }
    /**
     * @summary 任意軸回りの回転行列
     * @desc
     * <p>axis を Z 軸方向とすると、X 軸から Y 軸の方向に angle 度回転させる変換行列を返す。</p>
     * @param  {mapray.Vector3} axis   回転軸 (単位ベクトル)
     * @param  {number}         angle  回転角 (Degrees)
     * @param  {mapray.Matrix}  dst    結果を代入する行列
     * @return {mapray.Matrix}         dst
     */

  }, {
    key: "rotation_matrix",
    value: function rotation_matrix(axis, angle, dst) {
      var θ = angle * GeoMath.DEGREE;
      var sinθ = Math.sin(θ);
      var cosθ = Math.cos(θ);
      var ax = axis[0];
      var ay = axis[1];
      var az = axis[2];
      dst[0] = ax * ax * (1 - cosθ) + cosθ;
      dst[1] = ax * ay * (1 - cosθ) + az * sinθ;
      dst[2] = ax * az * (1 - cosθ) - ay * sinθ;
      dst[3] = 0;
      dst[4] = ax * ay * (1 - cosθ) - az * sinθ;
      dst[5] = ay * ay * (1 - cosθ) + cosθ;
      dst[6] = ay * az * (1 - cosθ) + ax * sinθ;
      dst[7] = 0;
      dst[8] = ax * az * (1 - cosθ) + ay * sinθ;
      dst[9] = ay * az * (1 - cosθ) - ax * sinθ;
      dst[10] = az * az * (1 - cosθ) + cosθ;
      dst[11] = 0;
      dst[12] = 0;
      dst[13] = 0;
      dst[14] = 0;
      dst[15] = 1;
      return dst;
    }
    /**
     * @summary KML 互換のモデル変換行列
     *
     * @desc
     * <p>変換は scale -> roll -> tilt -> heading の順に行われる。</p>
     *
     * @param  {number}         heading  Z 軸を中心に Y 軸から X 軸の方向の回転角 (Degrees)
     * @param  {number}         tilt     X 軸を中心に Z 軸から Y 軸の方向の回転角 (Degrees)
     * @param  {number}         roll     Y 軸を中心に X 軸から Z 軸の方向の回転角 (Degrees)
     * @param  {mapray.Vector3} scale    スケール
     * @param  {mapray.Matrix}  dst      結果を代入する行列
     * @return {mapray.Matrix}           dst
     *
     * @package
     * @see https://developers.google.com/kml/documentation/kmlreference#model
     *
     * @deprecated {@link mapray.Orientation#getTransformMatrix} の使用を推奨
     */

  }, {
    key: "kml_model_matrix",
    value: function kml_model_matrix(heading, tilt, roll, scale, dst) {
      var h = heading * GeoMath.DEGREE;
      var t = tilt * GeoMath.DEGREE;
      var r = roll * GeoMath.DEGREE;
      var sinH = Math.sin(h);
      var cosH = Math.cos(h);
      var sinT = Math.sin(t);
      var cosT = Math.cos(t);
      var sinR = Math.sin(r);
      var cosR = Math.cos(r);
      var sx = scale[0];
      var sy = scale[1];
      var sz = scale[2];
      dst[0] = sx * (sinH * sinR * sinT + cosH * cosR);
      dst[1] = sx * (cosH * sinR * sinT - sinH * cosR);
      dst[2] = sx * sinR * cosT;
      dst[3] = 0;
      dst[4] = sy * sinH * cosT;
      dst[5] = sy * cosH * cosT;
      dst[6] = -sy * sinT;
      dst[7] = 0;
      dst[8] = sz * (sinH * cosR * sinT - cosH * sinR);
      dst[9] = sz * (cosH * cosR * sinT + sinH * sinR);
      dst[10] = sz * cosR * cosT;
      dst[11] = 0;
      dst[12] = 0;
      dst[13] = 0;
      dst[14] = 0;
      dst[15] = 1;
      return dst;
    }
    /**
     * @summary グーデルマン関数
     * @param  {number}  x   数値
     * @return {number}      gd( x )
     */

  }, {
    key: "gudermannian",
    value: function gudermannian(x) {
      return 2 * Math.atan(Math.exp(x)) - Math.PI / 2;
    }
    /**
     * @summary 逆グーデルマン関数
     * @param  {number}  x   数値
     * @return {number}      gd<sup>-1</sup>( x )
     */

  }, {
    key: "invGudermannian",
    value: function invGudermannian(x) {
      return Math.log(Math.tan(x / 2 + Math.PI / 4));
    }
    /**
     * @summary 値を指定区間内に制限
     * @param  {number}  x    値
     * @param  {number}  min  最小値
     * @param  {number}  max  最大値
     * @return {number}       min <= x <= max のとき x, x < min のとき min, x > max のとき max
     */

  }, {
    key: "clamp",
    value: function clamp(x, min, max) {
      return Math.min(Math.max(x, min), max);
    }
  }]);

  return GeoMath;
}();
/**
 * @summary 地球の半径
 * @desc
 * <p>Inou 球面座標系で定義された、地球の半径 (Meters) である。</p>
 * @type {number}
 * @constant
 */


GeoMath.EARTH_RADIUS = 6378137;
/**
 * @summary 1度に対応するラジアンの数値
 * @desc
 * <p>この数値は π / 180 である。</p>
 * <p>度数を DEGREE で掛け合せることによってラジアンに変換することができる。</p>
 * @type {number}
 * @constant
 */

GeoMath.DEGREE = 0.017453292519943295769;
/**
 * @summary log2(π)
 * @type {number}
 * @constant
 */

GeoMath.LOG2PI = 1.6514961294723187980;
/**
 * @summary 4行4列の行列を表現
 * @desc
 * <p>このクラスは実在しない便宜的なものであり、Array や TypedArray 等の 16 要素の配列に置き換えることができる。
 * この配列の数値の並びは列優先である。</p>
 *
 * @class mapray.Matrix
 * @see mapray.GeoMath
 */

/**
 * @summary 2次ベクトルを表現
 * @desc
 * <p>このクラスは実在しない便宜的なものであり、Array や TypedArray 等の 2 要素の配列に置き換えることができる。</p>
 *
 * @class mapray.Vector2
 * @see mapray.GeoMath
 */

/**
 * @summary 3次ベクトルを表現
 * @desc
 * <p>このクラスは実在しない便宜的なものであり、Array や TypedArray 等の 3 要素の配列に置き換えることができる。</p>
 *
 * @class mapray.Vector3
 * @see mapray.GeoMath
 */

/**
 * @summary 4次ベクトルを表現
 * @desc
 * <p>このクラスは実在しない便宜的なものであり、Array や TypedArray 等の 4 要素の配列に置き換えることができる。</p>
 *
 * @class mapray.Vector4
 * @see mapray.GeoMath
 */
// GeoMath の内部テンポラリ変数を生成

{
  GeoMath._xaxis = GeoMath.createVector3();
  GeoMath._yaxis = GeoMath.createVector3();
  GeoMath._zaxis = GeoMath.createVector3();
}
/**
 * @summary 球面座標
 *
 * @classdesc
 * <p>経度、緯度、高度により位置を表現する。</p>
 *
 * @memberof mapray
 */

var GeoPoint =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>経度、緯度、高度を与えてインスタンスを生成する。</p>
   *
   * @param {number} [longitude=0]  経度 (Degrees)
   * @param {number} [latitude=0]   緯度 (Degrees)
   * @param {number} [altitude=0]   高度 (Meters)
   */
  function GeoPoint(longitude, latitude, altitude) {
    _classCallCheck(this, GeoPoint);

    /**
     *  @summary 経度 (Degrees)
     *  @member mapray.GeoPoint#longitude
     *  @type {number}
     */
    this.longitude = longitude !== undefined ? longitude : 0;
    /**
     *  @summary 緯度 (Degrees)
     *  @member mapray.GeoPoint#latitude
     *  @type {number}
     */

    this.latitude = latitude !== undefined ? latitude : 0;
    /**
     *  @summary 高度 (Meters)
     *  @member mapray.GeoPoint#altitude
     *  @type {number}
     */

    this.altitude = altitude !== undefined ? altitude : 0;
  }
  /**
   * @summary インスタンスを複製
   *
   * @desc
   * <p>this の複製を生成して返す。</p>
   *
   * @return {mapray.GeoPoint}  this の複製
   */


  _createClass(GeoPoint, [{
    key: "clone",
    value: function clone() {
      return new GeoPoint(this.longitude, this.latitude, this.altitude);
    }
    /**
     * @summary インスタンスを代入
     *
     * @desc
     * <p>src を this に代入する。</p>
     *
     * @param  {mapray.GeoPoint} src  代入元
     * @return {mapray.GeoPoint}      this
     */

  }, {
    key: "assign",
    value: function assign(src) {
      this.longitude = src.longitude;
      this.latitude = src.latitude;
      this.altitude = src.altitude;
      return this;
    }
    /**
     * @summary 配列からの設定
     *
     * @desc
     * <p>longitude, latitude, altitude の順序で格納されている配列 position によりプロパティを設定する。</p>
     * <p>position の長さは 2 または 3 で、長さが 2 なら altitude は 0 に設定される。</p>
     *
     * @param  {number[]} position  [longitude, latitude, altitude] または [longitude, latitude]
     * @return {mapray.GeoPoint} this
     */

  }, {
    key: "setFromArray",
    value: function setFromArray(position) {
      this.longitude = position[0];
      this.latitude = position[1];
      this.altitude = position.length > 2 ? position[2] : 0;
      return this;
    }
    /**
     * @summary 地心直交座標からの設定
     *
     * @desc
     * <p>地心直交座標 position を球面座標に変換して this に設定する。</p>
     *
     * @param  {mapray.Vector3} position  入力 GOCS 座標 (Meters)
     * @return {mapray.GeoPoint}  this
     */

  }, {
    key: "setFromGocs",
    value: function setFromGocs(position) {
      var x = position[0];
      var y = position[1];
      var z = position[2];
      var x2 = x * x;
      var y2 = y * y;
      var z2 = z * z; // 緯度 φ = ArcTan[z / √(x^2 + y^2)]
      // 経度 λ = ArcTan[x, y]

      if (x != 0 || y != 0) {
        this.latitude = Math.atan(z / Math.sqrt(x2 + y2)) / GeoMath.DEGREE;
        this.longitude = Math.atan2(y, x) / GeoMath.DEGREE;
      } else {
        // x == 0 && y == 0
        if (z > 0) this.latitude = 90;else if (z < 0) this.latitude = -90;else this.latitude = 0;
        this.longitude = 0;
      } // 高度 h = √(x^2 + y^2 + z^2) - R


      this.altitude = Math.sqrt(x2 + y2 + z2) - GeoMath.EARTH_RADIUS;
      return this;
    }
    /**
     * @summary 地心直交座標として取得
     *
     * @param  {mapray.Vector3} dst  結果を格納するオブジェクト
     * @return {mapray.Vector3}      dst
     */

  }, {
    key: "getAsGocs",
    value: function getAsGocs(dst) {
      var λ = this.longitude * GeoMath.DEGREE;
      var φ = this.latitude * GeoMath.DEGREE;
      var r = GeoMath.EARTH_RADIUS + this.altitude;
      var cosφ = Math.cos(φ);
      dst[0] = r * cosφ * Math.cos(λ);
      dst[1] = r * cosφ * Math.sin(λ);
      dst[2] = r * Math.sin(φ);
      return dst;
    }
    /**
     * @summary 座標変換行列を計算 (MLOCS → GOCS)
     * @desc
     * <p>原点が this の Mapray ローカル直交座標系 (MLOCS) から地心直交座標系 (GOCS) に変換する行列を計算する。</p>
     *
     * @param  {mapray.Matrix} dst  結果を代入する行列
     * @return {mapray.Matrix}      dst
     */

  }, {
    key: "getMlocsToGocsMatrix",
    value: function getMlocsToGocsMatrix(dst) {
      var λ = this.longitude * GeoMath.DEGREE;
      var φ = this.latitude * GeoMath.DEGREE;
      var sinλ = Math.sin(λ);
      var cosλ = Math.cos(λ);
      var sinφ = Math.sin(φ);
      var cosφ = Math.cos(φ);
      var r = GeoMath.EARTH_RADIUS + this.altitude; // ∂u/∂λ

      dst[0] = -sinλ;
      dst[1] = cosλ;
      dst[2] = 0;
      dst[3] = 0; // ∂u/∂φ

      dst[4] = -cosλ * sinφ;
      dst[5] = -sinλ * sinφ;
      dst[6] = cosφ;
      dst[7] = 0; // u = {x, y, z} / r

      dst[8] = cosφ * cosλ;
      dst[9] = cosφ * sinλ;
      dst[10] = sinφ;
      dst[11] = 0; // {x, y, z}

      dst[12] = r * cosφ * cosλ;
      dst[13] = r * cosφ * sinλ;
      dst[14] = r * sinφ;
      dst[15] = 1;
      return dst;
    }
    /**
     * @summary 球面座標を地心直交座標に変換
     *
     * @param  {number[]} points      [lon_0, lat_0, alt_0, ...]
     * @param  {number}   num_points  点の数
     * @param  {number[]} dst         [x0, y0, z0, ...] (結果を格納する配列)
     * @return {number[]} dst
     *
     * @see {@link mapray.GeoPoint.getAsGocs}
     */

  }], [{
    key: "toGocsArray",
    value: function toGocsArray(points, num_points, dst) {
      var degree = GeoMath.DEGREE;
      var radius = GeoMath.EARTH_RADIUS;

      for (var i = 0; i < num_points; ++i) {
        var b = 3 * i;
        var λ = points[b] * degree;
        var φ = points[b + 1] * degree;
        var r = radius + points[b + 2];
        var cosφ = Math.cos(φ);
        dst[b] = r * cosφ * Math.cos(λ);
        dst[b + 1] = r * cosφ * Math.sin(λ);
        dst[b + 2] = r * Math.sin(φ);
      }

      return dst;
    }
  }]);

  return GeoPoint;
}();
/**
 * @summary 方向表現
 *
 * @classdesc
 * <p>heading (機首方位)、tilt (前後の傾き)、roll (左右の傾き) により方向を表現する。</p>
 *
 * @memberof mapray
 * @see https://developers.google.com/kml/documentation/kmlreference#model
 */


var Orientation =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>heading, tilt, roll に角度を与えてインスタンスを生成する。</p>
   *
   * @param {number} [heading=0]  機首方位 (Degrees)
   * @param {number} [tilt=0]     前後の傾き (Degrees)
   * @param {number} [roll=0]     左右の傾き (Degrees)
   */
  function Orientation(heading, tilt, roll) {
    _classCallCheck(this, Orientation);

    /**
     *  @summary 機首方位 (Degrees)
     *  @member mapray.Orientation#heading
     *  @type {number}
     */
    this.heading = heading !== undefined ? heading : 0;
    /**
     *  @summary 前後の傾き (Degrees)
     *  @member mapray.Orientation#tilt
     *  @type {number}
     */

    this.tilt = tilt !== undefined ? tilt : 0;
    /**
     *  @summary 左右の傾き (Degrees)
     *  @member mapray.Orientation#roll
     *  @type {number}
     */

    this.roll = roll !== undefined ? roll : 0;
  }
  /**
   * @summary インスタンスを複製
   *
   * @desc
   * <p>this の複製を生成して返す。</p>
   *
   * @return {mapray.Orientation}  this の複製
   */


  _createClass(Orientation, [{
    key: "clone",
    value: function clone() {
      return new Orientation(this.heading, this.tilt, this.roll);
    }
    /**
     * @summary インスタンスを代入
     *
     * @desc
     * <p>src を this に代入する。</p>
     *
     * @param  {mapray.Orientation} src  代入元
     * @return {mapray.Orientation}      this
     */

  }, {
    key: "assign",
    value: function assign(src) {
      this.heading = src.heading;
      this.tilt = src.tilt;
      this.roll = src.roll;
      return this;
    }
    /**
     * @summary 変換行列を取得
     *
     * @desc
     * <p>変換は scale -> roll -> tilt -> heading の順に行われる。</p>
     *
     * @param  {mapray.Vector3} scale  スケール
     * @param  {mapray.Matrix}  dst    結果を代入する行列
     * @return {mapray.Matrix}  dst
     */

  }, {
    key: "getTransformMatrix",
    value: function getTransformMatrix(scale, dst) {
      var h = this.heading * GeoMath.DEGREE;
      var t = this.tilt * GeoMath.DEGREE;
      var r = this.roll * GeoMath.DEGREE;
      var sinH = Math.sin(h);
      var cosH = Math.cos(h);
      var sinT = Math.sin(t);
      var cosT = Math.cos(t);
      var sinR = Math.sin(r);
      var cosR = Math.cos(r);
      var sx = scale[0];
      var sy = scale[1];
      var sz = scale[2];
      dst[0] = sx * (sinH * sinR * sinT + cosH * cosR);
      dst[1] = sx * (cosH * sinR * sinT - sinH * cosR);
      dst[2] = sx * sinR * cosT;
      dst[3] = 0;
      dst[4] = sy * sinH * cosT;
      dst[5] = sy * cosH * cosT;
      dst[6] = -sy * sinT;
      dst[7] = 0;
      dst[8] = sz * (sinH * cosR * sinT - cosH * sinR);
      dst[9] = sz * (cosH * cosR * sinT + sinH * sinR);
      dst[10] = sz * cosR * cosT;
      dst[11] = 0;
      dst[12] = 0;
      dst[13] = 0;
      dst[14] = 0;
      dst[15] = 1;
      return dst;
    }
  }]);

  return Orientation;
}();

/*
 * 解説: このファイルで GeoPoint クラスと Orientation クラスを定義している理由
 *
 *   GeoPoint と Orientation のインタフェースは GeoMath に依存しないが、GeoMath
 *   のインタフェースは GeoPoint や Orientation に依存する可能性がある。
 *
 *   一方、GeoPoint と Orientation の内部実装では一部の GeoMath インタフェースを
 *   使用できたほうが都合がよい。
 *
 *   GeoPoint と Orientation を個別のファイルで定義したいが、この場合実装のために
 *   GeoMath をインポートすることになる。
 *
 *   そうすると、GeoMath.js に GeoPoint や Orientation が (循環依存のため)
 *   インポートできなくなってしまう。
 *
 *   そこで GeoMath.js 内で GeoPoint と Orientation を定義する。これで GeoPoint
 *   と Orientation の実装で GeoMath を使用でき、GeoMath のインタフェースと実装で
 *   GeoPoint や Orientation を使用できる。
 *
 *   GeoPoint はまず GeoMath.js から GeoPoint.js にエクスポートし、さらに
 *   GeoPoint.js から GeoPoint を他のファイルにエクスポートする。
 *   Orientation も同様のことを行う。
 *
 *   このようにすることで、他のファイルからは実装の事情は見えなくなる。
 */

/**
 * @summary 真理値型
 *
 * @classdesc
 * <p>登録名: "boolean"</p>
 * <p>実装型: boolean</p>
 * <p>次の型へ変換可能: {@link mapray.animation.NumberType}</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Type
 * @hideconstructor
 */

var BooleanType =
/*#__PURE__*/
function (_Type) {
  _inherits(BooleanType, _Type);

  /**
   */
  function BooleanType() {
    var _this;

    _classCallCheck(this, BooleanType);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(BooleanType).call(this, "boolean"));
    _this._number_type = null;
    _this._convertibles = new Set([_assertThisInitialized(_this)]);
    return _this;
  }
  /**
   * @private
   */


  _createClass(BooleanType, [{
    key: "_postinit",
    value: function _postinit() {
      this._number_type = Type.find("number");

      this._convertibles.add(this._number_type);
    }
    /**
     * @override
     */

  }, {
    key: "isConvertible",
    value: function isConvertible(from) {
      return this._convertibles.has(from);
    }
    /**
     * @override
     */

  }, {
    key: "convertValue",
    value: function convertValue(from, value) {
      if (from === this) {
        // 同一型
        return value;
      } else {
        // assert: from === this._number_type
        return value >= 0.5;
      }
    }
    /**
     * @override
     */

  }, {
    key: "getDefaultValue",
    value: function getDefaultValue() {
      return false;
    }
    /**
     * @override
     */

  }, {
    key: "getCloneValue",
    value: function getCloneValue(value) {
      return value;
    }
  }]);

  return BooleanType;
}(Type);
/**
 * @summary 数値型
 *
 * @classdesc
 * <p>登録名: "number"</p>
 * <p>実装型: number</p>
 * <p>次の型へ変換可能: {@link mapray.animation.BooleanType}</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Type
 * @hideconstructor
 */


var NumberType =
/*#__PURE__*/
function (_Type2) {
  _inherits(NumberType, _Type2);

  /**
   */
  function NumberType() {
    var _this2;

    _classCallCheck(this, NumberType);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(NumberType).call(this, "number"));
    _this2._boolean_type = null;
    _this2._convertibles = new Set([_assertThisInitialized(_this2)]);
    return _this2;
  }
  /**
   * @private
   */


  _createClass(NumberType, [{
    key: "_postinit",
    value: function _postinit() {
      this._boolean_type = Type.find("boolean");

      this._convertibles.add(this._boolean_type);
    }
    /**
     * @override
     */

  }, {
    key: "isConvertible",
    value: function isConvertible(from) {
      return this._convertibles.has(from);
    }
    /**
     * @override
     */

  }, {
    key: "convertValue",
    value: function convertValue(from, value) {
      if (from === this) {
        // 同一型
        return value;
      } else {
        // assert: from === this._boolean_type
        return value ? 1 : 0;
      }
    }
    /**
     * @override
     */

  }, {
    key: "getDefaultValue",
    value: function getDefaultValue() {
      return 0;
    }
    /**
     * @override
     */

  }, {
    key: "getCloneValue",
    value: function getCloneValue(value) {
      return value;
    }
  }]);

  return NumberType;
}(Type);
/**
 * @summary 文字列型
 *
 * @classdesc
 * <p>登録名: "string"</p>
 * <p>実装型: string</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Type
 * @hideconstructor
 */


var StringType =
/*#__PURE__*/
function (_Type3) {
  _inherits(StringType, _Type3);

  /**
   */
  function StringType() {
    _classCallCheck(this, StringType);

    return _possibleConstructorReturn(this, _getPrototypeOf(StringType).call(this, "string"));
  }
  /**
   * @private
   */


  _createClass(StringType, [{
    key: "_postinit",
    value: function _postinit() {}
    /**
     * @override
     */

  }, {
    key: "isConvertible",
    value: function isConvertible(from) {
      return from === this;
    }
    /**
     * @override
     */

  }, {
    key: "convertValue",
    value: function convertValue(from, value) {
      return value;
    }
    /**
     * @override
     */

  }, {
    key: "getDefaultValue",
    value: function getDefaultValue() {
      return "";
    }
    /**
     * @override
     */

  }, {
    key: "getCloneValue",
    value: function getCloneValue(value) {
      return value;
    }
  }]);

  return StringType;
}(Type);
/**
 * @summary 2 次ベクトル型
 *
 * @classdesc
 * <p>登録名: "vector2"</p>
 * <p>実装型: {@link mapray.Vector2}</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Type
 * @hideconstructor
 */


var Vector2Type =
/*#__PURE__*/
function (_Type4) {
  _inherits(Vector2Type, _Type4);

  /**
   */
  function Vector2Type() {
    _classCallCheck(this, Vector2Type);

    return _possibleConstructorReturn(this, _getPrototypeOf(Vector2Type).call(this, "vector2"));
  }
  /**
   * @private
   */


  _createClass(Vector2Type, [{
    key: "_postinit",
    value: function _postinit() {}
    /**
     * @override
     */

  }, {
    key: "isConvertible",
    value: function isConvertible(from) {
      return from === this;
    }
    /**
     * @override
     */

  }, {
    key: "convertValue",
    value: function convertValue(from, value) {
      return value;
    }
    /**
     * @override
     */

  }, {
    key: "getDefaultValue",
    value: function getDefaultValue() {
      return GeoMath.createVector2();
    }
    /**
     * @override
     */

  }, {
    key: "getCloneValue",
    value: function getCloneValue(value) {
      return GeoMath.createVector2(value);
    }
  }]);

  return Vector2Type;
}(Type);
/**
 * @summary 3 次ベクトル型
 *
 * @classdesc
 * <p>登録名: "vector3"</p>
 * <p>実装型: {@link mapray.Vector3}</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Type
 * @hideconstructor
 */


var Vector3Type =
/*#__PURE__*/
function (_Type5) {
  _inherits(Vector3Type, _Type5);

  /**
   */
  function Vector3Type() {
    _classCallCheck(this, Vector3Type);

    return _possibleConstructorReturn(this, _getPrototypeOf(Vector3Type).call(this, "vector3"));
  }
  /**
   * @private
   */


  _createClass(Vector3Type, [{
    key: "_postinit",
    value: function _postinit() {}
    /**
     * @override
     */

  }, {
    key: "isConvertible",
    value: function isConvertible(from) {
      return from === this;
    }
    /**
     * @override
     */

  }, {
    key: "convertValue",
    value: function convertValue(from, value) {
      return value;
    }
    /**
     * @override
     */

  }, {
    key: "getDefaultValue",
    value: function getDefaultValue() {
      return GeoMath.createVector3();
    }
    /**
     * @override
     */

  }, {
    key: "getCloneValue",
    value: function getCloneValue(value) {
      return GeoMath.createVector3(value);
    }
  }]);

  return Vector3Type;
}(Type);
/**
 * @summary 4 次ベクトル型
 *
 * @classdesc
 * <p>登録名: "vector4"</p>
 * <p>実装型: {@link mapray.Vector4}</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Type
 * @hideconstructor
 */


var Vector4Type =
/*#__PURE__*/
function (_Type6) {
  _inherits(Vector4Type, _Type6);

  /**
   */
  function Vector4Type() {
    _classCallCheck(this, Vector4Type);

    return _possibleConstructorReturn(this, _getPrototypeOf(Vector4Type).call(this, "vector4"));
  }
  /**
   * @private
   */


  _createClass(Vector4Type, [{
    key: "_postinit",
    value: function _postinit() {}
    /**
     * @override
     */

  }, {
    key: "isConvertible",
    value: function isConvertible(from) {
      return from === this;
    }
    /**
     * @override
     */

  }, {
    key: "convertValue",
    value: function convertValue(from, value) {
      return value;
    }
    /**
     * @override
     */

  }, {
    key: "getDefaultValue",
    value: function getDefaultValue() {
      return GeoMath.createVector4();
    }
    /**
     * @override
     */

  }, {
    key: "getCloneValue",
    value: function getCloneValue(value) {
      return GeoMath.createVector4(value);
    }
  }]);

  return Vector4Type;
}(Type);
/**
 * @summary 行列型
 *
 * @classdesc
 * <p>登録名: "matrix"</p>
 * <p>実装型: {@link mapray.Matrix}</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Type
 * @hideconstructor
 */


var MatrixType =
/*#__PURE__*/
function (_Type7) {
  _inherits(MatrixType, _Type7);

  /**
   */
  function MatrixType() {
    _classCallCheck(this, MatrixType);

    return _possibleConstructorReturn(this, _getPrototypeOf(MatrixType).call(this, "matrix"));
  }
  /**
   * @private
   */


  _createClass(MatrixType, [{
    key: "_postinit",
    value: function _postinit() {}
    /**
     * @override
     */

  }, {
    key: "isConvertible",
    value: function isConvertible(from) {
      return from === this;
    }
    /**
     * @override
     */

  }, {
    key: "convertValue",
    value: function convertValue(from, value) {
      return value;
    }
    /**
     * @override
     */

  }, {
    key: "getDefaultValue",
    value: function getDefaultValue() {
      return GeoMath.setIdentity(GeoMath.createMatrix());
    }
    /**
     * @override
     */

  }, {
    key: "getCloneValue",
    value: function getCloneValue(value) {
      return GeoMath.createMatrix(value);
    }
  }]);

  return MatrixType;
}(Type);
/**
 * @summary 事前定義型を登録
 *
 * @private
 */


function registerPredefinedTypes() {
  var type_classes = [BooleanType, NumberType, StringType, Vector3Type, Vector2Type, Vector4Type, MatrixType];
  var type_instances = []; // 型を登録

  for (var _i = 0, _type_classes = type_classes; _i < _type_classes.length; _i++) {
    var type_class = _type_classes[_i];
    var type = new type_class();
    Type.register(type.name, type);
    type_instances.push(type);
  } // 登録後の処理


  for (var _i2 = 0, _type_instances = type_instances; _i2 < _type_instances.length; _i2++) {
    var _type = _type_instances[_i2];

    _type._postinit();
  }
}

registerPredefinedTypes();

/**
 * @summary アニメーション関数
 *
 * @classdesc
 * <p>指定時刻のアニメーション関数値を取得するための抽象クラスである。</p>
 *
 * @abstract
 * @memberof mapray.animation
 */
var Curve =
/*#__PURE__*/
function () {
  /**
   * @protected
   */
  function Curve() {
    _classCallCheck(this, Curve);

    this._value_change_listeners = new Set();
  }
  /**
   * @summary 型はサポートされるか?
   *
   * @desc
   * <p>type 型がアニメーション関数の返却値の型として使用できるかどうかを返す。</p>
   * <p>this の生存中、このメソッドの type に対する結果は一定である。</p>
   * <p>このメソッドが true を返した場合、getValue() により
   *    アニメーション関数値を type 型で取得することが可能である。</p>
   *
   * @param {mapray.animation.Type} type  確認する型
   *
   * @return {boolean}  type がサポートされるとき true, それ以外は false
   *
   * @see {@link mapray.animation.Curve#getValue}
   *
   * @abstract
   */


  _createClass(Curve, [{
    key: "isTypeSupported",
    value: function isTypeSupported(type) {
      this._override_error("isTypeSupported");
    }
    /**
     * @summary 指定時刻の値を取得
     *
     * @desc
     * <p>時刻 time のアニメーション関数値を type 型として取得する。</p>
     *
     * <p>事前条件: this.isTypeSupported( type ) == true</p>
     *
     * @param {mapray.animation.Time} time  時刻パラメータ
     * @param {mapray.animation.Type} type  返却値の型
     *
     * @return {object}  時刻 time に対する type 型の値
     *
     * @see {@link mapray.animation.Curve#isTypeSupported}
     *
     * @abstract
     */

  }, {
    key: "getValue",
    value: function getValue(time, type) {
      this._override_error("getValue");
    }
    /**
     * @summary 不変性情報を取得
     *
     * @desc
     * <p>interval で指定される範囲の不変性情報を返す。</p>
     *
     * <p>不変性情報は interval に内包されるまたは交差する時刻区間を持っている。</p>
     * <p>一部が interval と交差する時刻区間はクリップしない。</p>
     *
     * <p>事前条件: interval.isEmpty() == false</p>
     *
     * @param {mapray.animation.Interval} interval  対象とする時刻区間
     *
     * @return {mapray.animation.Invariance}  不変性情報
     *
     * @abstract
     */

  }, {
    key: "getInvariance",
    value: function getInvariance(interval) {
      this._override_error("getInvariance");
    }
    /**
     * @summary 関数値が変化したことを通知
     *
     * @desc
     * <p>時刻区間 interval の範囲の関数値が変化したことをフレームワークに通知する。</p>
     * <p>このメソッドは関数値が変化したときにサブクラスの実装者が呼び出す。</p>
     *
     * @param {mapray.animation.Interval} interval  関数値が変化した時刻区間
     *
     * @see {@link mapray.animation.Curve#addValueChangeListener}
     * @see {@link mapray.animation.Curve#removeValueChangeListener}
     *
     * @protected
     */

  }, {
    key: "notifyValueChange",
    value: function notifyValueChange(interval) {
      if (interval.isEmpty()) {
        // 空時刻区間なので実際には変化なし
        // ValueChangeListener の事前条件も満たさない
        return;
      } // 関数値変化リスナーの呼び出し


      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this._value_change_listeners[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var vcl = _step.value;
          vcl(interval);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    }
    /**
     * @summary 関数値変化リスナーの登録
     *
     * @param {mapray.animation.Curve.ValueChangeListener} vcl  関数値変化リスナー
     *
     * @see {@link mapray.animation.Curve#notifyValueChange}
     * @see {@link mapray.animation.Curve#removeValueChangeListener}
     */

  }, {
    key: "addValueChangeListener",
    value: function addValueChangeListener(vcl) {
      this._value_change_listeners.add(vcl);
    }
    /**
     * @summary 関数値変化リスナーの登録解除
     *
     * @param {mapray.animation.Curve.ValueChangeListener} vcl  関数値変化リスナー
     *
     * @see {@link mapray.animation.Curve#notifyValueChange}
     * @see {@link mapray.animation.Curve#addValueChangeListener}
     */

  }, {
    key: "removeValueChangeListener",
    value: function removeValueChangeListener(vcl) {
      this._value_change_listeners["delete"](vcl);
    }
    /**
     * @summary メソッドがオーバーライドされていない
     *
     * arguments.callee と Error#stack は互換性が低いので、関数名の取得に使わなかった
     *
     * @param {string} func_name
     *
     * @private
     */

  }, {
    key: "_override_error",
    value: function _override_error(func_name) {
      throw new Error("Curve#" + func_name + "() method has not been overridden in " + this.constructor.name);
    }
  }]);

  return Curve;
}();

var createProperty = function (object, key, value) {
  var propertyKey = toPrimitive(key);
  if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));else object[propertyKey] = value;
};

// https://tc39.github.io/ecma262/#sec-array.from


var arrayFrom = function from(arrayLike
/* , mapfn = undefined, thisArg = undefined */
) {
  var O = toObject(arrayLike);
  var C = typeof this == 'function' ? this : Array;
  var argumentsLength = arguments.length;
  var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
  var mapping = mapfn !== undefined;
  var iteratorMethod = getIteratorMethod(O);
  var index = 0;
  var length, result, step, iterator, next, value;
  if (mapping) mapfn = functionBindContext(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2); // if the target is not iterable or it's an array with the default iterator - use a simple case

  if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
    iterator = iteratorMethod.call(O);
    next = iterator.next;
    result = new C();

    for (; !(step = next.call(iterator)).done; index++) {
      value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
      createProperty(result, index, value);
    }
  } else {
    length = toLength(O.length);
    result = new C(length);

    for (; length > index; index++) {
      value = mapping ? mapfn(O[index], index) : O[index];
      createProperty(result, index, value);
    }
  }

  result.length = index;
  return result;
};

var INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {
  Array.from(iterable);
}); // `Array.from` method
// https://tc39.github.io/ecma262/#sec-array.from

_export({
  target: 'Array',
  stat: true,
  forced: INCORRECT_ITERATION
}, {
  from: arrayFrom
});

/**
 * @summary アニメーションパラメータの更新管理
 *
 * @classdesc
 * <p>アニメーション関数と結合しているアニメーションパラメータを更新するための機能を提供する。</p>
 *
 * @memberof mapray.animation
 */

var Updater =
/*#__PURE__*/
function () {
  /**
   */
  function Updater() {
    _classCallCheck(this, Updater);

    // 前回更新した時刻 (一度も更新していないときは null)
    this._prev_time = null; // Curve -> Tracked 辞書

    this._track_binders = new Map(); // パラメータがまだ更新されていない、またはアニメーション関数値と
    // 矛盾する可能性のある Binder インスタンス

    this._dirty_binders = new Set(); // 関数値が変化した Curve を管理

    this._vary_curves = new VaryCurves();
  }
  /**
   * @summary アニメーションパラメータを更新
   *
   * @desc
   * <p>時刻 time でのアニメーション関数値をアニメーションパラメータに設定する。</p>
   *
   * @param {mapray.animation.Time} time  時刻
   */


  _createClass(Updater, [{
    key: "update",
    value: function update(time) {
      this._update_dirty_binders(time);

      if (this._prev_time !== null) {
        var vary_curves = this._vary_curves.getVaryCurves(this._prev_time, time);

        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
          for (var _iterator = vary_curves[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var curve = _step.value;

            var tracked = this._track_binders.get(curve);

            tracked.updateBinders(time);
          }
        } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion && _iterator["return"] != null) {
              _iterator["return"]();
            }
          } finally {
            if (_didIteratorError) {
              throw _iteratorError;
            }
          }
        }
      }

      this._flush_dirty_binders(); // 前回の時刻を更新


      this._prev_time = time;
    }
    /**
     * @summary Binder インスタンスの登録
     *
     * @desc
     * <p>事前条件: binder は this で管理されていない</p>
     *
     * @param {mapray.animation.Binder} binder
     *
     * @package
     */

  }, {
    key: "_$register",
    value: function _$register(binder) {
      // 最初は dirty_binders に登録
      this._dirty_binders.add(binder);
    }
    /**
     * @summary Binder インスタンスの抹消
     *
     * @desc
     * <p>事前条件: binder は this で管理されている</p>
     *
     * @param {mapray.animation.Binder} binder
     *
     * @package
     */

  }, {
    key: "_$unregister",
    value: function _$unregister(binder) {
      if (this._dirty_binders["delete"](binder)) ; else {
        // binder は track_binders 側に存在する
        var tracked = this._track_binders.get(binder._$curve);

        tracked.unregister(binder);
      }
    }
    /**
     * @summary _dirty_binders のすべてのパラメータを更新
     *
     * @param {mapray.animation.Time} time
     *
     * @private
     */

  }, {
    key: "_update_dirty_binders",
    value: function _update_dirty_binders(time) {
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this._dirty_binders[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var binder = _step2.value;

          binder._$update(time);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
    }
    /**
     * @summary _dirty_binders から _track_binders へ Binder を移動
     *
     * @private
     */

  }, {
    key: "_flush_dirty_binders",
    value: function _flush_dirty_binders() {
      for (var _i = 0, _Array$from = Array.from(this._dirty_binders); _i < _Array$from.length; _i++) {
        var binder = _Array$from[_i];

        // dirty_binders から binder を削除
        this._dirty_binders["delete"](binder); // track_binders へ binder を追加


        var curve = binder._$curve;

        var tracked = this._track_binders.get(curve);

        if (tracked === undefined) {
          // curve を使っている Binder インスタンスが初めて登録される
          tracked = new Tracked(this, curve, binder);

          this._track_binders.set(curve, tracked);
        } else {
          // 2つ目以降の Binder インスタンス
          tracked.register(binder);
        }
      }
    }
  }]);

  return Updater;
}();
/**
 * @summary 追跡されたバインダ
 *
 * @memberof mapray.animation.Updater
 * @private
 */


var Tracked =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>updater._track_binders に追加されるときに呼び出される。</p>
   * <p>updater._vary_curves も更新する。</p>
   *
   * @param {mapray.animation.Updater} updater      this を管理する Updater インスタンス
   * @param {mapray.animation.Curve}   curve        対象とする Curve インスタンス
   * @param {mapray.animation.Binder}  init_binder  最初の Binder インスタンス
   */
  function Tracked(updater, curve, init_binder) {
    var _this = this;

    _classCallCheck(this, Tracked);

    this._updater = updater;
    this._curve = curve; // curve と結合している Binder インスタンスの集合

    this._binders = new Set([init_binder]); // curve の現在の不変性

    this._invariance = curve.getInvariance(Interval.UNIVERSAL); // アニメーション関数値の変更管理

    this._listener = function (interval) {
      _this._onValueChange(interval);
    };

    curve.addValueChangeListener(this._listener); // vary_curves に curve を追加

    updater._vary_curves.addCurve(curve, this._invariance);
  }
  /**
   * @summary Curve を持つ Binder を登録
   *
   * @param {mapray.animation.Binder} binder
   */


  _createClass(Tracked, [{
    key: "register",
    value: function register(binder) {
      // Assert: !this._binders.has( binder )
      this._binders.add(binder);
    }
    /**
     * @summary Curve を持つ Binder を抹消
     *
     * @desc
     * <p>this が updater._track_binders から削除されることがある。</p>
     * <p>curve が updater._vary_curves から削除されることがある。</p>
     *
     * @param {mapray.animation.Binder} binder
     */

  }, {
    key: "unregister",
    value: function unregister(binder) {
      // Assert: this._binders.has( binder )
      this._binders["delete"](binder);

      if (this._binders.size > 0) {
        // まだ this._curve と関連した Binder インスタンスが this に存在する
        return;
      } // this._curve と関連した唯一の Binder インスタンスが this から削除された
      // vary_curves から curve を削除


      this._updater._vary_curves.removeCurve(this._curve, this._invariance); // 変更を追跡する必要はなくなったのでリスナーを削除


      this._curve.removeValueChangeListener(this._listener); // this を this._updater から削除


      this._updater._track_binders["delete"](this._curve);
    }
    /**
     * @summary アニメーションパラメータを更新
     *
     * @desc
     * <p>時刻 time でのアニメーション関数値をアニメーションパラメータに設定する。</p>
     *
     * @param {mapray.animation.Time} time  時刻
     */

  }, {
    key: "updateBinders",
    value: function updateBinders(time) {
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = this._binders[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var binder = _step3.value;

          binder._$update(time);
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }
    }
    /**
     * @summary アニメーション間数値が変更された
     *
     * @param {mapray.animation.Interval} chg_ival  変更された時刻区間
     *
     * @private
     */

  }, {
    key: "_onValueChange",
    value: function _onValueChange(chg_ival) {
      // assert: !chg_ival.isEmpty()
      // assert: this._updater._prev_time != null
      if (chg_ival.includesTime(this._updater._prev_time)) {
        // 現在設定されているパラメータ値と矛盾が生じる
        // this._binders を dirty_binders に移動
        this._move_to_dirty_binders();
      } else {
        // 不変性情報を部分的に更新
        var subinvr = this._curve.getInvariance(chg_ival);

        this._updater._vary_curves.modifyCurve(this._curve, chg_ival, subinvr, this._invariance);

        this._invariance._$modify(subinvr);
      }
    }
    /**
     * @summary this を dirty_binders に移動
     *
     * @desc
     * <p>this は updater._track_binders, updater._vary_curves から削除される。</p>
     *
     * @private
     */

  }, {
    key: "_move_to_dirty_binders",
    value: function _move_to_dirty_binders() {
      for (var _i2 = 0, _Array$from2 = Array.from(this._binders); _i2 < _Array$from2.length; _i2++) {
        var binder = _Array$from2[_i2];
        // this から binder を削除
        this.unregister(binder); // dirty_binders に binder を追加

        this._updater._dirty_binders.add(binder);
      }
    }
  }]);

  return Tracked;
}();
/**
 * @summary 時刻間での関数値が変化した Curve を得る
 *
 * @memberof mapray.animation.Updater
 * @private
 */


var VaryCurves =
/*#__PURE__*/
function () {
  /**
   */
  function VaryCurves() {
    _classCallCheck(this, VaryCurves);

    // 連続変化の時刻区間 (すべて Proper)
    // OrderedMap<Time, ContCurves>
    //   外から内部に入る、内部で動くとき変化する
    //   下限が '[' のとき、左から下限に入る、下限から左へ出るとき変化する
    //   上限が ']' のとき、右から上限に入る、上限から右へ出るとき変化する
    this._continuous = createTimeMap(); // 単発変化の時刻 []
    // OrderedMap<Time, Set<Curve>>
    //   点を通過、点に入る、点から出るとき変化する

    this._oneshot = createTimeMap(); // 単発変化の時刻 [)
    // OrderedMap<Time, Set<Curve>>
    //   点を通過、左から点に入る、点から左へ出るとき変化する

    this._oneshot_L = createTimeMap(); // 単発変化の時刻 (]
    // OrderedMap<Time, Set<Curve>>
    //   点を通過、右から点に入る、点から右へ出るとき変化する

    this._oneshot_R = createTimeMap();
  }
  /**
   * @summary Curve を追加
   *
   * @desc
   * <p>データベースに不変性が invariance である curve を追加する。</p>
   *
   * <p>事前条件: curve は filter 内に存在しない</p>
   *
   * @param {mapray.animation.Curve}        curve     追加する Curve インスタンス
   * @param {mapray.animation.Invariance} invariance  curve の不変性情報
   * @param {mapray.animation.Interval}    [filter]   追加する時刻区間 (前回の不変性情報で整列済み)
   */


  _createClass(VaryCurves, [{
    key: "addCurve",
    value: function addCurve(curve, invariance) {
      var filter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Interval.UNIVERSAL;

      var invr_ivals = invariance.getNarrowed(filter)._$getArray();

      if (invr_ivals.length == 0) {
        // 全時刻区間が変化
        this._addToGeneric(curve, filter);
      } else {
        // 不変区間が存在する場合
        var lastIndex = invr_ivals.length - 1; // 最初

        {
          var invr_ival = invr_ivals[0];
          var vary_ival = filter.getIntersection(invr_ival.getPrecedings());

          if (!vary_ival.isEmpty()) {
            this._addToGeneric(curve, vary_ival);
          } else if (isSameInterval_L(filter, invr_ival) && !this._hasContiguous_L(invr_ival, curve)) {
            // invr_ival と filter の左が一致して、curve を持った invr_ival の左隣接が存在しない
            if (invr_ival.l_open) {
              this._addToOneshotGroup(curve, invr_ival, "_oneshot_R");
            } else if (!invr_ival.getPrecedings().isEmpty()) {
              this._addToOneshotGroup(curve, invr_ival, "_oneshot_L");
            }
          }
        } // 中間

        for (var i = 0; i < lastIndex; ++i) {
          var lower = invr_ivals[i].getFollowings();
          var upper = invr_ivals[i + 1].getPrecedings();

          var _vary_ival = lower.getIntersection(upper);

          if (_vary_ival.isEmpty()) {
            //  lower と upper に間がない
            this._addToOneshotGroup(curve, lower, lower.l_open ? "_oneshot_R" : "_oneshot_L");
          } else {
            // lower と upper に間がある
            this._addToGeneric(curve, _vary_ival);
          }
        } // 最後


        {
          var _invr_ival = invr_ivals[lastIndex];

          var _vary_ival2 = filter.getIntersection(_invr_ival.getFollowings());

          if (!_vary_ival2.isEmpty()) {
            this._addToGeneric(curve, _vary_ival2);
          } else if (isSameInterval_R(filter, _invr_ival) && !this._hasContiguous_R(_invr_ival, curve)) {
            if (_invr_ival.u_open) {
              this._addToOneshotGroup(curve, _invr_ival, "_oneshot_L");
            } else if (!_invr_ival.getFollowings().isEmpty()) {
              this._addToOneshotGroup(curve, _invr_ival, "_oneshot_R");
            }
          }
        }
      }
    }
    /**
     * @summary interval の左の隣接する区間は存在するか?
     *
     * @desc
     * <p>continuous の中に interval の左に隣接する区間があり、かつ
     *    curve を持っているものは存在するかどうかを返す。</p>
     *
     * @param {mapray.animation.Interval} interval (!= Φ)
     * @param {mapray.animation.Curve}    curve
     *
     * @return {boolean}
     *
     * @private
     */

  }, {
    key: "_hasContiguous_L",
    value: function _hasContiguous_L(interval, curve) {
      var map = this._continuous; // interval の左のアイテム

      var it1 = map.findLower(interval.lower);
      var it0 = it1 !== null ? it1.findPredecessor() : map.findLast();

      if (it0 !== null) {
        var pred = it0.value; // ContCurves

        var pred_ival = pred.interval;

        if (pred_ival.upper.equals(interval.lower) && (interval.l_open && !pred_ival.u_open || !interval.l_open && pred_ival.u_open)) {
          // 隣接している
          if (pred.curves.has(curve)) {
            // 隣接して curve を持っている
            return true;
          }
        }
      }

      return false;
    }
    /**
     * @summary interval の右の隣接する区間は存在するか?
     *
     * @desc
     * <p>continuous の中に interval の右に隣接する区間があり、かつ
     *    curve を持っているものは存在するかどうかを返す。</p>
     *
     * @param {mapray.animation.Interval} interval (!= Φ)
     * @param {mapray.animation.Curve}    curve
     *
     * @return {boolean}
     *
     * @private
     */

  }, {
    key: "_hasContiguous_R",
    value: function _hasContiguous_R(interval, curve) {
      var map = this._continuous; // interval の右のアイテム

      var it = map.findLower(interval.upper);

      if (it === null) {
        // interval の右に区間が存在しない
        return false;
      }

      var succ = it.value; // ContCurves

      var succ_ival = succ.interval;

      if (!succ_ival.lower.equals(interval.upper)) {
        // 境界が不一致
        return false;
      }

      if (succ_ival.l_open && interval.u_open || !succ_ival.l_open && !interval.u_open) {
        // 重複または離れている
        return false;
      }

      return succ.curves.has(curve);
    }
    /**
     * @summary Curve を削除
     *
     * @desc
     * <p>filter 範囲の curve を削除する。filter は整列済みを想定しているので区間の分割は行わない。</p>
     *
     * <p>事前条件: curve は invariance と矛盾しない状態で this に存在する</p>
     * <p>事前条件: !filter.isEmpty()</p>
     *
     * <p>todo: 削除後に隣接区間が同じ集合になったときの統合処理</p>
     *
     * @param {mapray.animation.Curve}        curve     削除する Curve インスタンス
     * @param {mapray.animation.Invariance} invariance  curve の不変性情報
     * @param {mapray.animation.Interval}    [filter]   削除する時刻区間 (invariance で整列済み)
     */

  }, {
    key: "removeCurve",
    value: function removeCurve(curve, invariance) {
      var filter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Interval.UNIVERSAL;

      var invr_ivals = invariance.getNarrowed(filter)._$getArray();

      if (invr_ivals.length == 0) {
        // filter の全時刻区間が変化
        this._removeForGeneric(curve, filter);
      } else {
        // 不変区間が存在する場合
        var lastIndex = invr_ivals.length - 1; // 最初

        {
          var invr_ival = invr_ivals[0];
          var vary_ival = filter.getIntersection(invr_ival.getPrecedings());

          if (!vary_ival.isEmpty()) {
            this._removeForGeneric(curve, vary_ival);
          } else {
            if (isSameInterval_L(filter, invr_ival)) {
              // oneshot_L/R の可能性に対応
              this._removeForOneshotGroup(curve, filter);
            }
          }
        } // 中間

        for (var i = 0; i < lastIndex; ++i) {
          var lower = invr_ivals[i].getFollowings();
          var upper = invr_ivals[i + 1].getPrecedings();

          var _vary_ival3 = lower.getIntersection(upper);

          if (_vary_ival3.isEmpty()) {
            // ai と bi に間がない
            this._removeForOneshotGroup(curve, lower);
          } else {
            // ai と bi に間がある
            this._removeForGeneric(curve, _vary_ival3);
          }
        } // 最後


        {
          var _invr_ival2 = invr_ivals[lastIndex];

          var _vary_ival4 = filter.getIntersection(_invr_ival2.getFollowings());

          if (!_vary_ival4.isEmpty()) {
            this._removeForGeneric(curve, _vary_ival4);
          } else {
            if (isSameInterval_R(filter, _invr_ival2)) {
              // oneshot_L/R の可能性に対応
              var _upper = filter.upper;

              this._removeForOneshotGroup(curve, new Interval(_upper, _upper));
            }
          }
        }
      }
    }
    /**
     * @summary Curve を変更
     *
     * @param {mapray.animation.Curve}      curve
     * @param {mapray.animation.Interval}   chg_ival  更新時刻区間 (!= Φ)
     * @param {mapray.animation.Invariance} sub_invr  更新部分の Invariance
     * @param {mapray.animation.Invariance} old_invr  以前の Invariance
     */

  }, {
    key: "modifyCurve",
    value: function modifyCurve(curve, chg_ival, sub_invr, old_invr) {
      // old_invr を基にして chg_ival を整列拡張
      var aligned = old_invr._$expandIntervalByAlignment(chg_ival); // this のデータベースから aligned 区間の curve を削除


      this.removeCurve(curve, old_invr, aligned); // aligned 区間で sub_invr を追加

      this.addCurve(curve, sub_invr, aligned);
    }
    /**
     * @summary 関数値が変化した Curve インスタンス集合を取得
     *
     * @desc
     * <p>時刻が prev_time から time に連続変化したときに、関数値が変化する可能性のある
     *    Curve インスタンスを得るための列挙可能オブジェクトを返す。</p>
     *
     * @param {mapray.animation.Time} prev_time  始点時刻
     * @param {mapray.animation.Time} time       終点時刻
     *
     * @return {iterable.<mapray.animation.Curve>}
     */

  }, {
    key: "getVaryCurves",
    value: function getVaryCurves(prev_time, time) {
      if (prev_time.lessThan(time)) {
        // 順再生
        return this._collectCurves(prev_time, time);
      } else if (time.lessThan(prev_time)) {
        // 逆再生
        return this._collectCurves(time, prev_time);
      } else {
        // 時刻変わらず
        return [];
      }
    }
    /**
     * @summary curve を continuous または oneshot へ追加
     *
     * @desc
     * <p>curve を continuous または oneshot に登録する。
     *    ただし interval.isEmpty() のときは何もしない。</p>
     *
     * @param {mapray.animation.Curve}       curve  追加する Curve インスタンス
     * @param {mapray.animation.Interval} interval  変化する時刻区間
     *
     * @private
     */

  }, {
    key: "_addToGeneric",
    value: function _addToGeneric(curve, interval) {
      if (interval.isProper()) {
        this._addToContinuous(curve, interval);
      } else if (interval.isSingle()) {
        this._addToOneshotGroup(curve, interval, "_oneshot");
      }
    }
    /**
     * @summary curve を oneshot 族へ追加
     *
     * @param {mapray.animation.Curve}       curve  追加する Curve インスタンス
     * @param {mapray.animation.Interval} interval  lower が時刻として使われる
     * @param {string}                       pname  oneshot 族のプロパティ名
     *
     * @private
     */

  }, {
    key: "_addToOneshotGroup",
    value: function _addToOneshotGroup(curve, interval, pname) {
      var map = this[pname]; // OrderedMap<Time, Set<Curve>>

      var time = interval.lower;
      var item = map.findEqual(time);

      if (item === null) {
        // 新規の時刻
        // 空の Set<Curve> インスタンスを追加
        item = map.insert(time, new Set());
      }

      item.value.add(curve);
    }
    /**
     * @summary curve を continuous へ追加
     *
     * @desc
     * <p>事前条件: interval.isProper()</p>
     *
     * @param {mapray.animation.Curve}       curve  追加する Curve インスタンス
     * @param {mapray.animation.Interval} interval  変化する時刻区間
     *
     * @private
     */

  }, {
    key: "_addToContinuous",
    value: function _addToContinuous(curve, interval) {
      // assert: interval.isProper()
      // A は追加する連続区間
      // T は登録済みの連続区間 (A と交差する区間の中で一番左側の区間)
      // 交差タイプ
      //
      // (1) 登録済みの区間に A と交差する区間はない
      //     A: ====
      //
      // (2) T は A の左から飛び出し、右からは飛び出していない
      //     A:  ====
      //     T: ====
      //
      // (3) T は A の右から飛び出し、左からは飛び出していない
      //     A: ====
      //     T:  ====
      //
      // (4) T は A の左右どちらからも飛び出している
      //     A:  ===
      //     T: =====
      //
      // (5) T は A の左右どちらからも飛び出していない
      //     A: =====
      //     T:  ===
      // 記号の意味
      //
      //   $X は X.getPrecedings()
      //   X$ は X.getFollowings()
      var A_ival = interval; // A

      var A_curve = curve;

      for (;;) {
        // assert: A != Φ
        var target = this._removeFirstCrossInContinuous(A_ival);

        if (target !== null) {
          var T_ival = target.cc.interval; // T: A と交差する区間で一番左側の区間

          var T_curves = target.cc.curves; // T の Curve インタンス集合

          var A_x_T = target.cross; // A∩T

          var $A_x_T = A_ival.getPrecedings().getIntersection(T_ival); // $A∩T

          if ($A_x_T.isEmpty()) {
            // 交差タイプ (3) または (5)
            var A_x_$T = A_ival.getIntersection(T_ival.getPrecedings()); // A∩$T

            if (!A_x_$T.isEmpty()) {
              // (d) A∩$T != Φ なら、A∩$T として、A_curve を新規登録
              this._addForContinuous(A_x_$T, A_curve);
            }
          } else {
            // 交差タイプ (2) または (4)
            // (b) $A∩T として、T_curves を新規登録
            this._addForContinuous($A_x_T, new Set(T_curves));
          }

          var A$_x_T = A_ival.getFollowings().getIntersection(T_ival); // A$∩T

          if (A$_x_T.isEmpty()) {
            // 交差タイプ (2) または (5)
            // (a) A∩T として、T_curves に A_curve を加えた集合を新規登録
            this._addForContinuous(A_x_T, T_curves.add(A_curve)); // (z) A∩T$ != Φ なら、A を A∩T$ として再処理


            var A_x_T$ = A_ival.getIntersection(T_ival.getFollowings()); // A∩T$

            if (!A_x_T$.isEmpty()) {
              A_ival = A_x_T$;
              continue;
            }
          } else {
            // 交差タイプ (3) または (4)
            // (c) A$∩T として、T_curves を新規登録
            this._addForContinuous(A$_x_T, new Set(T_curves)); // (a) A∩T として、T_curves に A_curve を加えた集合を新規登録


            this._addForContinuous(A_x_T, T_curves.add(A_curve));
          }
        } else {
          // 交差タイプ (1)
          // A として、A_curve を新規登録
          this._addForContinuous(A_ival, A_curve);
        }

        break;
      }
    }
    /**
     * @summary 最初に interval と交差する要素を削除
     *
     * @desc
     * <p></p>
     * <p>this._continuous 内の時刻区間の中から、最初に interval と交差する要素を削除しする。
     *    その交差区間と要素が持っていた ContCurves インスタンスを返す。</p>
     * <p>ただし、交差する区間が存在しなければ null を返す。</p>
     *
     * @param {mapray.animation.Interval} interval  時刻区間
     *
     * @return {!object}  { cc: ContCurves, cross: Interval }
     *
     * @private
     */

  }, {
    key: "_removeFirstCrossInContinuous",
    value: function _removeFirstCrossInContinuous(interval) {
      var map = this._continuous; // 各区間は Proper 前提

      var t1 = map.findUpper(interval.lower);
      var t0 = t1 !== null ? t1.findPredecessor() : map.findLast();

      if (t0 !== null) {
        var cross = interval.getIntersection(t0.value.interval);

        if (!cross.isEmpty()) {
          var cc = t0.value;
          map.remove(t0);
          return {
            cc: cc,
            cross: cross
          };
        }
      }

      if (t1 !== null) {
        var _cross = interval.getIntersection(t1.value.interval);

        if (!_cross.isEmpty()) {
          var _cc = t1.value;
          map.remove(t1);
          return {
            cc: _cc,
            cross: _cross
          };
        }
      } // 交差は存在しない


      return null;
    }
    /**
     * @summary curves を continuous または oneshot へ追加
     *
     * @desc
     * <p>interval.isSingle() のときは curves を this._oneshot の Curve 集合に追加する。</p>
     * <p>interval.isProper() のときは ContCurves インスタンスを新規に this._continuous へ追加する。</p>
     *
     * <p>事前条件: !interval.isEmpty()</p>
     *
     * @param {mapray.animation.Interval} interval  時刻区間、または時刻 (lower を時刻とする)
     * @param {mapray.animation.Curve|Set}  curves  追加する Curve インスタンス、またはその集合
     *
     * @private
     */

  }, {
    key: "_addForContinuous",
    value: function _addForContinuous(interval, curves) {
      var time = interval.lower; // 時刻へ変換

      if (interval.isSingle()) {
        // oneshot: curves を Curve 集合へ追加
        var it = this._oneshot.findEqual(time);

        if (it === null) {
          // 新規の時刻
          // 空の Set<Curve> インスタンスを追加
          it = this._oneshot.insert(time, new Set());
        }

        var dst_set = it.value;

        if (curves instanceof Set) {
          // 複数 Curve
          var _iteratorNormalCompletion4 = true;
          var _didIteratorError4 = false;
          var _iteratorError4 = undefined;

          try {
            for (var _iterator4 = curves[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
              var curve = _step4.value;
              dst_set.add(curve);
            }
          } catch (err) {
            _didIteratorError4 = true;
            _iteratorError4 = err;
          } finally {
            try {
              if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) {
                _iterator4["return"]();
              }
            } finally {
              if (_didIteratorError4) {
                throw _iteratorError4;
              }
            }
          }
        } else {
          // 単一 Curve
          dst_set.add(curves);
        }
      } else {
        // continuous: curves を新規追加
        this._continuous.insert(time, new ContCurves(interval, curves));
      }
    }
    /**
     * @summary curve を continuous または oneshot から削除
     *
     * @desc
     * <p>curve を continuous または oneshot から削除するe。
     *    ただし interval.isEmpty() のときは何もしない。</p>
     *
     * @param {mapray.animation.Curve}       curve  削除する Curve インスタンス
     * @param {mapray.animation.Interval} interval  変化する時刻区間
     *
     * @private
     */

  }, {
    key: "_removeForGeneric",
    value: function _removeForGeneric(curve, interval) {
      if (interval.isProper()) {
        this._removeForContinuous(curve, interval);
      } else if (interval.isSingle()) {
        this._removeForOneshotGroup(curve, interval);
      }
    }
    /**
     * @summary curve を oneshot 族から削除
     *
     * @desc
     * <p>ある oneshot 族の時刻 interval.lower に curve
     *    が存在すれば削除し、存在しなければ何もしない。</p>
     *
     * @param {mapray.animation.Curve}       curve  削除する Curve インスタンス
     * @param {mapray.animation.Interval} interval  lower が時刻として使われる
     *
     * @private
     */

  }, {
    key: "_removeForOneshotGroup",
    value: function _removeForOneshotGroup(curve, interval) {
      var time = interval.lower;

      for (var _i3 = 0, _arr = ["_oneshot", "_oneshot_L", "_oneshot_R"]; _i3 < _arr.length; _i3++) {
        var pname = _arr[_i3];
        var map = this[pname]; // OrderedMap<Time, Set<Curve>>

        var item = map.findEqual(time);

        if (item !== null) {
          var curves = item.value; // curve を削除し、空になったら curves も削除

          if (curves.has(curve)) {
            curves["delete"](curve);

            if (curves.size == 0) {
              map.remove(item);
            }
          } // curve は複数に所属することはないので、1つ削除したら終了


          break;
        }
      }
    }
    /**
     * @summary curves を continuous または oneshot から削除
     *
     * @desc
     * <p>interval 区間にある continuous と oneshot の curve を削除する。</p>
     * <p>事前条件: interval.isProper()</p>
     *
     * @param {mapray.animation.Curve}       curve  削除する Curve インスタンス
     * @param {mapray.animation.Interval} interval  時刻区間
     *
     * @private
     */

  }, {
    key: "_removeForContinuous",
    value: function _removeForContinuous(curve, interval) {
      // this._continuous
      {
        var map = this._continuous; // 各区間は Proper 前提

        var it1 = map.findUpper(interval.lower);
        var it0 = it1 !== null ? it1.findPredecessor() : map.findLast();
        var end = map.findUpper(interval.upper);

        for (var it = it0 || it1; it !== end;) {
          var curves = it.value.curves;
          curves["delete"](curve);
          it = curves.size == 0 ? map.remove(it) : it.findSuccessor();
        }
      } // this._oneshot

      {
        var _map = this._oneshot;

        var _it = _map.findLower(interval.lower);

        var _end = _map.findUpper(interval.upper);

        for (var _it2 = _it; _it2 !== _end;) {
          var _curves = _it2.value;

          _curves["delete"](curve);

          _it2 = _curves.size == 0 ? _map.remove(_it2) : _it2.findSuccessor();
        }
      }
    }
    /**
     * @summary Curve インスタンスを収集
     *
     * @desc
     * 事前条件: t1.lessThan( t2 )
     *
     * @param {mapray.animation.Time} t1
     * @param {mapray.animation.Time} t2
     *
     * @return {iterable.<mapray.animation.Curve>}
     *
     * @private
     */

  }, {
    key: "_collectCurves",
    value: function _collectCurves(t1, t2) {
      var curves = new Set(); // Set<Curve>

      this._collectContinuousCurves(t1, t2, curves);

      this._collectOneshotCurves(t1, t2, "_oneshot", true, true, curves);

      this._collectOneshotCurves(t1, t2, "_oneshot_L", false, true, curves);

      this._collectOneshotCurves(t1, t2, "_oneshot_R", true, false, curves);

      return curves;
    }
    /**
     * @summary continuous から Curve インスタンスを収集
     *
     * @desc
     * 事前条件: t1.lessThan( t2 )
     *
     * @param {mapray.animation.Time}        t1
     * @param {mapray.animation.Time}        t2
     * @param {Set.<mapray.animation.Curve>} curves
     *
     * @private
     */

  }, {
    key: "_collectContinuousCurves",
    value: function _collectContinuousCurves(t1, t2, curves) {
      // 時刻区間 [t1, ∞) と交差する最初の時刻区間
      var it_A = this._continuous.findLower(t1);

      if (it_A !== null) {
        var it_P = it_A.findPredecessor();

        if (it_P !== null) {
          if (it_P.value.interval.includeTime(t1)) {
            // it_A の直前が [t1, ∞) と交差するなら it_A の直前を選ぶ
            it_A = it_P;
          }
        }
      } // 時刻区間 (∞, t2] と交差する最後の時刻区間の直後


      var it_Z = this._continuous.findLower(t2);

      if (it_Z !== null) {
        var Z_ival = it_Z.value.interval;

        if (Z_ival.lower.equals(t2) && !Z_ival.l_open) {
          // it_Z の最小時刻がギリギリ (∞, t2] に入るので it_Z の直後を選ぶ
          it_Z = it_Z.findSuccessor();
        }
      } // assert: it_A != null || it_Z == null
      // Curve インスタンスを収集


      for (var it = it_A; it !== it_Z; it = it.findSuccessor()) {
        var _iteratorNormalCompletion5 = true;
        var _didIteratorError5 = false;
        var _iteratorError5 = undefined;

        try {
          for (var _iterator5 = it.value.curves[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
            var curve = _step5.value;
            curves.add(curve);
          }
        } catch (err) {
          _didIteratorError5 = true;
          _iteratorError5 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion5 && _iterator5["return"] != null) {
              _iterator5["return"]();
            }
          } finally {
            if (_didIteratorError5) {
              throw _iteratorError5;
            }
          }
        }
      }
    }
    /**
     * @summary oneshot から Curve インスタンスを収集
     *
     * @desc
     * 事前条件: t1.lessThan( t2 )
     *
     * @param {mapray.animation.Time}        t1
     * @param {mapray.animation.Time}        t2
     * @param {string}                       pname
     * @param {boolean}                      closed1
     * @param {boolean}                      closed2
     * @param {Set.<mapray.animation.Curve>} curves
     *
     * @private
     */

  }, {
    key: "_collectOneshotCurves",
    value: function _collectOneshotCurves(t1, t2, pname, closed1, closed2, curves) {
      var map = this[pname]; // OrderedMap<Time, Set<Curve>>
      // 時刻区間 [t1, ∞) に含まれる最初の時刻

      var it_A = closed1 ? map.findLower(t1) : map.findUpper(t1); // 時刻区間 (∞, t2] に含まれる最後の時刻区間の直後

      var it_Z = closed1 ? map.findUpper(t2) : map.findLower(t2); // assert: it_A != null || it_Z == null
      // Curve インスタンスを収集

      for (var it = it_A; it !== it_Z; it = it.findSuccessor()) {
        var _iteratorNormalCompletion6 = true;
        var _didIteratorError6 = false;
        var _iteratorError6 = undefined;

        try {
          for (var _iterator6 = it.value[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
            var curve = _step6.value;
            curves.add(curve);
          }
        } catch (err) {
          _didIteratorError6 = true;
          _iteratorError6 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion6 && _iterator6["return"] != null) {
              _iterator6["return"]();
            }
          } finally {
            if (_didIteratorError6) {
              throw _iteratorError6;
            }
          }
        }
      }
    }
  }]);

  return VaryCurves;
}();
/**
 * summary VaryCurves#continuous の値
 *
 * @memberof mapray.animation.Updater.VaryCurves
 * @private
 */


var ContCurves =
/**
 * @param {mapray.animation.Interval} interval  継続的に変化する時刻区間
 * @param {mapray.animation.Curve|Set}  curves  初期の Curve インスタンス、またはその集合
 */
function ContCurves(interval, curves) {
  _classCallCheck(this, ContCurves);

  // assert: interval.isProper()
  this.interval = interval;
  this.curves = new Set(curves instanceof Set ? curves : [curves]);
};
/**
 * @summary Time を昇順に順序付ける辞書を生成
 *
 * @private
 */


function createTimeMap() {
  return new OrderedMap(function (a, b) {
    return a.lessThan(b);
  });
}
/**
 * @summary a と b の左側は同じか?
 *
 * @param {mapray.animation.Interval} a
 * @param {mapray.animation.Interval} b
 *
 * @private
 */


function isSameInterval_L(a, b) {
  return a.lower.equals(b.lower) && (a.l_open && b.l_open || !a.l_open && !b.l_open);
}
/**
 * @summary a と b の右側は同じか?
 *
 * @param {mapray.animation.Interval} a
 * @param {mapray.animation.Interval} b
 *
 * @private
 */


function isSameInterval_R(a, b) {
  return a.upper.equals(b.upper) && (a.u_open && b.u_open || !a.u_open && !b.u_open);
}

/**
 * @summary 型不一致エラー
 *
 * @memberof mapray.animation
 * @extends mapray.animation.AnimationError
 *
 * @see {@link mapray.animation.Binder}
 */

var TypeMismatchError =
/*#__PURE__*/
function (_AnimationError) {
  _inherits(TypeMismatchError, _AnimationError);

  /**
   * @param {string} message  エラーの説明
   */
  function TypeMismatchError(message) {
    var _this;

    _classCallCheck(this, TypeMismatchError);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(TypeMismatchError).call(this, message));
    _this.name = "mapray.animation.TypeMismatchError";
    return _this;
  }

  return TypeMismatchError;
}(AnimationError);

/**
 * @summary アニメーションパラメータの結合
 *
 * @classdesc
 * <p>パラメータ、Curve インスタンス、Updater インスンタンスを結合する。</p>
 *
 * @see {@link mapray.animation.Curve}
 * @see {@link mapray.animation.Updater}
 *
 * @memberof mapray.animation
 */

var Binder =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>パラメータと curve と updater を結合する。</p>
   * <p>パラメータ値は setter を通して設定される。</p>
   * <p>setter には type 型の値が渡される。</p>
   *
   * @param {mapray.animation.Updater}      updater  アニメーションパラメータの更新管理
   * @param {mapray.animation.Curve}          curve  アニメーション関数
   * @param {mapray.animation.Type}            type  パラメータ値の型
   * @param {mapray.animation.Binder.Setter} setter  パラメータ設定関数
   *
   * @throws {@link mapray.animation.TypeMismatchError}  curve が type 型をサポートしていないとき
   */
  function Binder(updater, curve, type, setter) {
    _classCallCheck(this, Binder);

    if (!curve.isTypeSupported(type)) {
      throw new TypeMismatchError("type mismatch error");
    }

    this._updater = updater;
    this._curve = curve;
    this._type = type;
    this._setter = setter; // updater に this を登録

    updater._$register(this);
  }
  /**
   * @summary アニメーションパラメータの更新管理
   *
   * @type {mapray.animation.Updater}
   * @readonly
   */


  _createClass(Binder, [{
    key: "unbind",

    /**
     * @summary 結合を解除
     */
    value: function unbind() {
      // updater から this を抹消
      this._updater._$unregister(this);
    }
    /**
     * @summary アニメーション関数
     *
     * @type {mapray.animation.Curve}
     * @readonly
     *
     * @package
     */

  }, {
    key: "_$update",

    /**
     * @summary アニメーションパラメータを更新
     *
     * @desc
     * <p>時刻 time でのアニメーション関数値をアニメーションパラメータに設定する。</p>
     *
     * @param {mapray.animation.Time} time  時刻
     *
     * @package
     */
    value: function _$update(time) {
      var value = this._curve.getValue(time, this._type);

      var setter = this._setter;
      setter(value);
    }
  }, {
    key: "updater",
    get: function get() {
      return this._updater;
    }
    /**
     * @summary アニメーション関数
     *
     * @type {mapray.animation.Curve}
     * @readonly
     */

  }, {
    key: "curve",
    get: function get() {
      return this._curve;
    }
    /**
     * @summary パラメータ値の型
     *
     * @type {mapray.animation.Type}
     * @readonly
     *
     * @see {@link mapray.animation.Binder.Setter}
     */

  }, {
    key: "type",
    get: function get() {
      return this._type;
    }
    /**
     * @summary パラメータ設定関数
     *
     * @type {mapray.animation.Binder.Setter}
     * @readonly
     */

  }, {
    key: "setter",
    get: function get() {
      return this._setter;
    }
  }, {
    key: "_$curve",
    get: function get() {
      return this._curve;
    }
  }]);

  return Binder;
}();

var engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';

var process = global_1.process;
var versions = process && process.versions;
var v8 = versions && versions.v8;
var match, version;

if (v8) {
  match = v8.split('.');
  version = match[0] + match[1];
} else if (engineUserAgent) {
  match = engineUserAgent.match(/Edge\/(\d+)/);

  if (!match || match[1] >= 74) {
    match = engineUserAgent.match(/Chrome\/(\d+)/);
    if (match) version = match[1];
  }
}

var engineV8Version = version && +version;

var SPECIES$3 = wellKnownSymbol('species');

var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
  // We can't use this feature detection in V8 since it causes
  // deoptimization and serious performance degradation
  // https://github.com/zloirock/core-js/issues/677
  return engineV8Version >= 51 || !fails(function () {
    var array = [];
    var constructor = array.constructor = {};

    constructor[SPECIES$3] = function () {
      return {
        foo: 1
      };
    };

    return array[METHOD_NAME](Boolean).foo !== 1;
  });
};

var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded'; // We can't use this feature detection in V8 since it causes
// deoptimization and serious performance degradation
// https://github.com/zloirock/core-js/issues/679

var IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {
  var array = [];
  array[IS_CONCAT_SPREADABLE] = false;
  return array.concat()[0] !== array;
});
var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');

var isConcatSpreadable = function (O) {
  if (!isObject(O)) return false;
  var spreadable = O[IS_CONCAT_SPREADABLE];
  return spreadable !== undefined ? !!spreadable : isArray(O);
};

var FORCED$4 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT; // `Array.prototype.concat` method
// https://tc39.github.io/ecma262/#sec-array.prototype.concat
// with adding support of @@isConcatSpreadable and @@species

_export({
  target: 'Array',
  proto: true,
  forced: FORCED$4
}, {
  concat: function concat(arg) {
    // eslint-disable-line no-unused-vars
    var O = toObject(this);
    var A = arraySpeciesCreate(O, 0);
    var n = 0;
    var i, k, length, len, E;

    for (i = -1, length = arguments.length; i < length; i++) {
      E = i === -1 ? O : arguments[i];

      if (isConcatSpreadable(E)) {
        len = toLength(E.length);
        if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);

        for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
      } else {
        if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
        createProperty(A, n++, E);
      }
    }

    A.length = n;
    return A;
  }
});

/**
 * @summary アニメーション設定の標準インタフェース
 *
 * @classdesc
 * <p>オブジェクトのアニメーション可能パラメータにアニメーションを設定 (バインド)
 +    するための標準的なインタフェースを提供する。<p>
 *
 * <p>具体的には内部で各パラメータに適した {@link mapray.animation.Binder Binder}
 *    インスタンスの生成し、ユーザーが簡単にアニメーションを設定できるようにする。<p>
 *
 * <p>一般的に、アニメーション可能パラメータを持つオブジェクトの <em>animation</em>
 *    プロパティから、このインタフェースを得ることができる。<p>
 *
 * <p>注意: アニメーションを設定しているパラメータは
 *    {@link mapray.animation.Updater Updater} のメソッドを通してのみ更新することができる。
 *    それ以外の手段でパラメータを更新した場合はパラメータ値に矛盾が生じる可能性がある。<p>
 *
 * @see {@link mapray.animation.Binder}
 * @see {@link mapray.animation.Updater}
 *
 * @memberof mapray.animation
 * @abstract
 */
var BindingBlock =
/*#__PURE__*/
function () {
  /**
   * @protected
   */
  function BindingBlock() {
    _classCallCheck(this, BindingBlock);
  }
  /**
   * @summary アニメーション可能パラメータの情報を取得
   *
   * @desc
   * <p>アニメーションに対応したパラメータの情報を配列として取得する。</p>
   * <p>返される配列は 0 個またはそれ以上の要素を含み、要素間のパラメータ ID は重複しない。</p>
   * <p>this の生存期間中、(順序以外) 常に同じ内容を返す。</p>
   *
   * @return {mapray.animation.BindingBlock.Parameter[]}
   *
   * @abstract
   */


  _createClass(BindingBlock, [{
    key: "enumSupportedParameters",
    value: function enumSupportedParameters() {
      this._override_error("enumSupportedParameters");
    }
    /**
     * @summary パラメータは結合中か?
     *
     * @desc
     * <p>id が示すパラメータが結合されているとき true, 結合されていないとき false を返す。</p>
     * <p>ただし id が示すパラメータがアニメーションに対応していないときは false を返す。</p>
     *
     * @param {string} id  パラメータ ID
     *
     * @return {boolean}
     *
     * @abstract
     */

  }, {
    key: "isBound",
    value: function isBound(id) {
      this._override_error("isBound");
    }
    /**
     * @summary パラメータに結合されている Updater インスタンスを取得
     *
     * @desc
     * <p>id が示すパラメータが結合されている Updater インスタンスを返す。</p>
     * <p>ただし id が示すパラメータがアニメーションに対応していないときは null を返す。</p>
     *
     * @param {string} id  パラメータ ID
     *
     * @return {?mapray.animation.Updater}
     *
     * @abstract
     */

  }, {
    key: "getBoundUpdater",
    value: function getBoundUpdater(id) {
      this._override_error("getBoundUpdater");
    }
    /**
     * @summary パラメータに結合されている Curve インスタンスを取得
     *
     * @desc
     * <p>id が示すパラメータが結合されている Curve インスタンスを返す。</p>
     * <p>ただし id が示すパラメータがアニメーションに対応していないときは null を返す。</p>
     *
     * @param {string} id  パラメータ ID
     *
     * @return {?mapray.animation.Curve}
     *
     * @abstract
     */

  }, {
    key: "getBoundCurve",
    value: function getBoundCurve(id) {
      this._override_error("getBoundCurve");
    }
    /**
     * @summary パラメータにアニメーションを結合
     *
     * @desc
     * <p>id が示すパラメータと updater と curve を結びつける。ただし、すでに id
     *    が示すパラメータに結合があれば、先にその結合を解除してから行う。</p>
     *
     * <p>パラメータが結合されている間、updater によりそのパラメータを更新することができる。</p>
     *
     * @param {string}                        id  パラメータ ID
     * @param {mapray.animation.Updater} updater  アニメーションパラメータ更新管理
     * @param {mapray.animation.Curve}     curve  アニメーション関数
     *
     * @throws {@link mapray.animation.AnimationError}
     *         id が示すパラメータはアニメーションに対応していない
     *
     * @throws {@link mapray.animation.TypeMismatchError}
     *         id が示すパラメータの型と curve の型に互換性がないとき
     *
     * @see {@link mapray.animation.Binder}
     *
     * @abstract
     */

  }, {
    key: "bind",
    value: function bind(id, updater, curve) {
      this._override_error("bind");
    }
    /**
     * @summary パラメータの結合を解除
     *
     * @desc
     * <p>id が示すパラメータの結合を解除する。</p>
     * <p>ただし id が示すパラメータが結合されていないとき、またはアニメーションに対応していないときは何もしない。</p>
     *
     * @param {string} id  パラメータ ID
     *
     * @abstract
     */

  }, {
    key: "unbind",
    value: function unbind(id) {
      this._override_error("unbind");
    }
    /**
     * @summary すべてのパラメータの結合を解除
     *
     * @desc
     * <p>現在結合されているすべてのパラメータの結合を解除する。</p>
     *
     * @abstract
     */

  }, {
    key: "unbindAll",
    value: function unbindAll() {
      this._override_error("unbindAll");
    }
    /**
     * @summary すべてのパラメータの結合を解除 (子孫含む)
     *
     * @desc
     * <p>現在結合されているすべてのパラメータの結合を解除する。</p>
     * <p>もしパラメータを持つオブジェクトの子オブジェクトも BindingBlock
     *    インタフェースを持っていれば、子孫も含めて結合を解除する。</p>
     *
     * @abstract
     */

  }, {
    key: "unbindAllRecursively",
    value: function unbindAllRecursively() {
      this._override_error("unbindAllRecursively");
    }
    /**
     * @summary メソッドがオーバーライドされていない
     *
     * arguments.callee と Error#stack は互換性が低いので、関数名の取得に使わなかった
     *
     * @param {string} func_name
     *
     * @private
     */

  }, {
    key: "_override_error",
    value: function _override_error(func_name) {
      throw new Error("BindingBlock#" + func_name + "() method has not been overridden in " + this.constructor.name);
    }
  }]);

  return BindingBlock;
}();
/**
 * @summary アニメーション可能パラメータの情報
 *
 * @see {@link mapray.animation.BindingBlock#enumSupportedParameters}
 * @memberof mapray.animation.BindingBlock
 */


var Parameter =
/*#__PURE__*/
function () {
  /**
   * @param {string}                     id  パラメータ ID
   * @param {mapray.animation.Type[]} types  サポートする型のリスト
   */
  function Parameter(id, types) {
    _classCallCheck(this, Parameter);

    this._id = id;
    this._types = types.concat(); // 複製
  }
  /**
   * @summary パラメータ ID
   *
   * @type {string}
   *
   * @readonly
   */


  _createClass(Parameter, [{
    key: "id",
    get: function get() {
      return this._id;
    }
    /**
     * @summary サポートする型のリスト
     *
     * @desc
     * <p>パラメータに結合可能なアニメーション関数の型の配列である。</p>
     * <p>配列は 1 またはそれ以上の型を含む。</p>
     *
     * @type {mapray.animation.Type[]}
     *
     * @see {@link mapray.animation.Curve#isTypeSupported}
     *
     * @readonly
     */

  }, {
    key: "types",
    get: function get() {
      return this._types;
    }
  }]);

  return Parameter;
}();

BindingBlock.Parameter = Parameter;

/**
 * @summary アニメーションパラメータ設定のヘルパークラス
 *
 * @memberof mapray.animation
 * @extends mapray.animation.BindingBlock
 */

var EasyBindingBlock =
/*#__PURE__*/
function (_BindingBlock) {
  _inherits(EasyBindingBlock, _BindingBlock);

  /**
   */
  function EasyBindingBlock() {
    var _this;

    _classCallCheck(this, EasyBindingBlock);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(EasyBindingBlock).call(this));
    _this._entries = new Map(); // Map<id, Entry>

    _this._bounds = new Map(); // Map<id, Binder>

    _this._descendant_unbinders = []; // DescendantUnbinder[]

    return _this;
  }
  /**
   * @summary アニメーション可能パラメータを追加
   *
   * @desc
   * <p>識別子を id としてアニメーション可能なパラメータを登録する。</p>
   *
   * <p>types にはこのパラメータに結合可能なアニメーション関数の 1 つまたはそれ以上の型を配列で与える。</p>
   *
   * <p>types 2 つ以上の型が存在するときは type_solver に型を決定する関数を指定しなければならない。
   *    1 つしか型が存在しないとき type_solver は無視されるので null を与えてもよい。</p>
   *
   * <p>setter は実際のパラメータに値を設定する関数である。</p>
   *
   * <p>id に対応するパラメータがすでに結合されている場合はその結合が解除される。</p>
   *
   * @param {string}                             id  パラメータ ID
   * @param {mapray.animation.Type[]}         types  サポートする型のリスト
   * @param {?mapray.animation.EasyBindingBlock.TypeSolver} type_solver  型決定関数
   * @param {mapray.animation.Binder.Setter} setter  パラメータ設定関数
   *
   * @see {@link mapray.animation.BindingBlock.Parameter}
   */


  _createClass(EasyBindingBlock, [{
    key: "addEntry",
    value: function addEntry(id, types, type_solver, setter) {
      // 上書きで追加
      this._entries.set(id, new Entry(types, type_solver, setter)); // すでに結合されている場合は解除する


      var binder = this._bounds.get(id);

      if (binder !== undefined) {
        binder.unbind();

        this._bounds["delete"](id);
      }
    }
    /**
     * @summary 子孫の結合を解除するための関数を追加
     *
     * @param {mapray.animation.EasyBindingBlock.DescendantUnbinder} unbinder  子孫の結合を解除するための関数
     *
     * @see {@link mapray.animation.BindingBlock#unbindAllRecursively}
     */

  }, {
    key: "addDescendantUnbinder",
    value: function addDescendantUnbinder(unbinder) {
      this._descendant_unbinders.push(unbinder);
    }
    /**
     * @override
     */

  }, {
    key: "enumSupportedParameters",
    value: function enumSupportedParameters() {
      var parameters = [];
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this._entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var _step$value = _slicedToArray(_step.value, 2),
              id = _step$value[0],
              enrty = _step$value[1];

          parameters.push(new BindingBlock.Parameter(id, enrty.types));
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return parameters;
    }
    /**
     * @override
     */

  }, {
    key: "isBound",
    value: function isBound(id) {
      return this._bounds.has(id);
    }
    /**
     * @override
     */

  }, {
    key: "getBoundUpdater",
    value: function getBoundUpdater(id) {
      var binder = this._bounds.get(id);

      return binder !== undefined ? binder.updater : null;
    }
    /**
     * @override
     */

  }, {
    key: "getBoundCurve",
    value: function getBoundCurve(id) {
      var binder = this._bounds.get(id);

      return binder !== undefined ? binder.curve : null;
    }
    /**
     * @override
     */

  }, {
    key: "bind",
    value: function bind(id, updater, curve) {
      var entry = this._entries.get(id);

      if (entry === undefined) {
        // id のパラメータはアニメーションに非対応
        throw new AnimationError("unsupported parameter");
      } // すでに結合されている場合は先に解除


      this.unbind(id); // 型を決定

      var types = entry.types;
      var type = types.length == 1 ? types[0] : entry.type_solver(curve);

      if (type == null || !curve.isTypeSupported(type)) {
        // curve は id のパラメータが要求する型に対応できない
        throw new TypeMismatchError("type mismatch error");
      } // パラメータを結合


      this._bounds.set(id, new Binder(updater, curve, type, entry.setter));
    }
    /**
     * @override
     */

  }, {
    key: "unbind",
    value: function unbind(id) {
      var binder = this._bounds.get(id);

      if (binder !== undefined) {
        binder.unbind();
      }
    }
    /**
     * @override
     */

  }, {
    key: "unbindAll",
    value: function unbindAll() {
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this._bounds[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var _step2$value = _slicedToArray(_step2.value, 2),

          /*id*/
          binder = _step2$value[1];

          binder.unbind();
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
    }
    /**
     * @override
     */

  }, {
    key: "unbindAllRecursively",
    value: function unbindAllRecursively() {
      // 子孫
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = this._descendant_unbinders[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var unbinder = _step3.value;
          unbinder();
        } // 自身

      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }

      this.unbindAll();
    }
  }]);

  return EasyBindingBlock;
}(BindingBlock);
/**
 * @summary パラメータ情報
 *
 * @memberof mapray.animation.EasyBindingBlock
 * @private
 */


var Entry =
/**
 * @param {mapray.animation.Type[]}         types  サポートする型のリスト
 * @param {?mapray.animation.EasyBindingBlock.TypeSolver} type_solver  型決定関数
 * @param {mapray.animation.Binder.Setter} setter  パラメータ設定関数
 */
function Entry(types, type_solver, setter) {
  _classCallCheck(this, Entry);

  if (types.length < 1 || types.length >= 2 && !type_solver) {
    // 型は 1 つ以上で、2 つ以上のときは TypeSolver が必要
    // これは事前条件であるが、気付き用に投げる
    throw new AnimationError("bad parameter entry");
  }

  this.types = types.concat(); // 複製

  this.type_solver = type_solver;
  this.setter = setter;
};

/**
 * @summary 定数関数
 *
 * @classdesc
 * <p>すべての時刻で同じ値を返す任意型の関数である。</p>
 * <p>関数値の型は構築子のパラメータにより指定する。</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Curve
 */

var ConstantCurve =
/*#__PURE__*/
function (_Curve) {
  _inherits(ConstantCurve, _Curve);

  /**
   * @desc
   * <p>type 型の value を定数値とする定数関数を生成する。</p>
   * <p>type は任意の型を指定することができる。</p>
   * <p>value を省略したときは type 型の既定値を返す定数関数となる。</p>
   *
   * @param {mapray.animation.Type} type    関数値の型
   * @param {object}               [value]  初期定数値 (type 型)
   */
  function ConstantCurve(type, value) {
    var _this;

    _classCallCheck(this, ConstantCurve);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(ConstantCurve).call(this));
    _this._constant_type = type;
    _this._constant_value = type.getDefaultValue(); // 初期値が指定されているときは設定

    if (value !== undefined) {
      _this.setConstantValue(value);
    }

    return _this;
  }
  /**
   * @summary 定数値を設定
   *
   * @param {object} value  定数値 (関数値の型)
   */


  _createClass(ConstantCurve, [{
    key: "setConstantValue",
    value: function setConstantValue(value) {
      if (value == this._constant_value) {
        // 同じ値で変化なし
        // == 演算子で比較できない型は常に違う値と判断されることもある
        return;
      } // 定数値を変更


      this._constant_value = this._constant_type.getCloneValue(value); // 全時刻の値が変化

      this.notifyValueChange(Interval.UNIVERSAL);
    }
    /**
     * @override
     */

  }, {
    key: "isTypeSupported",
    value: function isTypeSupported(type) {
      var from_type = this._constant_type;
      return type.isConvertible(from_type);
    }
    /**
     * @override
     */

  }, {
    key: "getValue",
    value: function getValue(time, type) {
      var from_type = this._constant_type;
      var from_value = from_type.getCloneValue(this._constant_value);
      return type.convertValue(from_type, from_value);
    }
    /**
     * @override
     */

  }, {
    key: "getInvariance",
    value: function getInvariance(interval) {
      // 全時間で一定
      // (UNIVERSAL と非空区間は必ず交差するので interval の参照は不要)
      var invariance = new Invariance();
      return invariance.write(Interval.UNIVERSAL);
    }
  }]);

  return ConstantCurve;
}(Curve);

/**
 * @summary アニメーション実装者用のユーティリティ
 *
 * @hideconstructor
 * @memberof mapray.animation
 *
 * @private
 */

var AnimUtil =
/*#__PURE__*/
function () {
  function AnimUtil() {
    _classCallCheck(this, AnimUtil);
  }

  _createClass(AnimUtil, null, [{
    key: "getDimension",

    /**
     * @summary type の次元を取得
     *
     * @desc
     * <p>type が number のとき 1, vector2, vector3, vector4
     *    のときはベクトルの次数を返す。それ以外の型のときは 0 を返す。<p>
     *
     * @param {mapray.animation.Type} type
     *
     * @return {number}  type の次元、type が非対応のときは 0
     */
    value: function getDimension(type) {
      if (Type.find("number") === type) {
        // スカラーは 1
        return 1;
      } else if (Type.find("vector2") === type) {
        return 2;
      } else if (Type.find("vector3") === type) {
        return 3;
      } else if (Type.find("vector4") === type) {
        return 4;
      } else {
        // 非対応の型
        return 0;
      }
    }
    /**
     * @summary キーフレームのインデックスを検索
     *
     * @desc
     * <p>key_times の [lower, upper) の範囲に time より後の時刻が存在すれば、その中で最小のインデックスを返す。
     *    そのような時刻が存在しなければ upper を返す。</p>
     *
     * <p>返された値を i, key_times を k とすると time の位置は次のように解釈できる。</p>
     * <pre>
     *   i == lower のとき: time < k[i]
     *   i == upper のとき: k[i-1] <= time
     *   それ以外のとき: k[i-1] <= time < k[i]
     * </pre>
     *
     * <p>事前条件: upper - lower >= 1</p>
     *
     * <p>計算量: upper - lower を n とするとき、O(log n)</p>
     *
     * @param {mapray.animation.Time}   time       検索キー
     * @param {mapray.animation.Time[]} key_times  検索対象配列
     * @param {number}                  lower      下限インデックス
     * @param {number}                  upper      上限インデックス
     *
     * @return {number}  検索されたインデックス
     */

  }, {
    key: "findKeyFrameIndex",
    value: function findKeyFrameIndex(time, key_times, lower, upper) {
      var l_idx = lower;
      var u_idx = upper;

      for (;;) {
        if (u_idx - l_idx >= 2) {
          var m_idx = Math.floor((l_idx + u_idx) / 2); // 中間インデックス

          var m_time = key_times[m_idx];

          if (m_time.lessThan(time)) {
            // m_time < time なので [m_idx, u_idx) に存在するかもしれない
            l_idx = m_idx;
          } else if (time.lessThan(m_time)) {
            // m_time > time なので [l_idx, m_idx) を確認
            u_idx = m_idx;
          } else {
            // m_time == time なので m_idx の次が結果になる
            return m_idx + 1;
          }
        } else {
          // u_idx - l_idx == 1
          var l_time = key_times[l_idx];
          return time.lessThan(l_time) ? l_idx : u_idx;
        }
      }

      return 0; // 警告回避
    }
    /**
     * @summary 最初にサポートする型を検索
     *
     * @desc
     * <p>types の中で curve がサポートする最初の型を返す。</p>
     * <p>types に curve がサポートする型が存在しなければ null を返す。</p>
     *
     * @param {mapray.animation.Curve}           curve
     * @param {iterable.<mapray.animation.Type>} types
     *
     * @return {?mapray.animation.Type}
     */

  }, {
    key: "findFirstTypeSupported",
    value: function findFirstTypeSupported(curve, types) {
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = types[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var type = _step.value;

          if (curve.isTypeSupported(type)) {
            return type;
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return null;
    }
  }]);

  return AnimUtil;
}();

/**
 * @summary キーフレームによる線形関数
 *
 * @classdesc
 * <p>キーフレーム間を数値またはベクトルを線形に補間する関数である。</p>
 * <p>関数値の型は構築子のパラメータにより number, vector2, vector3 または vector4 を指定する。</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Curve
 */

var KFLinearCurve =
/*#__PURE__*/
function (_Curve) {
  _inherits(KFLinearCurve, _Curve);

  /**
   * <p>type 型の関数を keyframes により生成する。</p>
   * <p>type は number, vector2, vector3 または vector4 を指定することができる。</p>
   * <p>keyframes を省略したときは type 型の既定値を返す定数関数と同等になる。keyframes の形式に関しては
   *    {@link mapray.animation.KFLinearCurve#setKeyFrames setKeyFrames()} を参照のこと。</p>
   *
   * @param {mapray.animation.Type} type  関数値の型
   * @param {object[]}       [keyframes]  初期キーフレーム
   */
  function KFLinearCurve(type, keyframes) {
    var _this;

    _classCallCheck(this, KFLinearCurve);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(KFLinearCurve).call(this));
    var dimension = AnimUtil.getDimension(type);

    if (dimension == 0) {
      throw AnimationError("unsupported type");
    }

    _this._value_type = type; // number | vector2 | vector3 | vector4

    _this._dimension = dimension; // 1〜4

    _this._num_keyframes = undefined; // >= 2

    _this._key_times = undefined; // Time[]

    _this._key_values = undefined; // Float64Array

    if (keyframes !== undefined) {
      // 初期のキーフレームを設定
      _this.setKeyFrames(keyframes);
    } else {
      // 既定のキーフレームを設定
      var t0 = Time.fromNumber(0);
      var t1 = Time.fromNumber(1);
      var dv = type.getDefaultValue();

      _this.setKeyFrames([t0, dv, t1, dv]);
    }

    return _this;
  }
  /**
   * @summary キーフレーム設定
   *
   * @desc
   * <p>keyframes により、すべてのキーフレームを指定する。</p>
   *
   * <p>
   * 条件1: keyframes.length >= 4 (キーフレーム数 >= 2)<br>
   * 条件2: すべての i, j において、i < j ⇔ 時刻i < 時刻j<br>
   * 条件3: すべての i において、値i は構築子の type 引数で指定した型のインスタンス
   * </p>
   *
   * @param {object[]} keyframes  [時刻0, 値0, 時刻1, 値1, ...]
   */


  _createClass(KFLinearCurve, [{
    key: "setKeyFrames",
    value: function setKeyFrames(keyframes) {
      var dimension = this._dimension;
      this._num_keyframes = keyframes.length / 2;
      this._key_times = new Array(this._num_keyframes);
      this._key_values = new Float64Array(this._num_keyframes * dimension); // キーフレームを設定

      for (var ti = 0, vi = 0; ti < this._num_keyframes; ++ti, vi += dimension) {
        var time = keyframes[2 * ti];
        var value = keyframes[2 * ti + 1]; // 時刻を配列に設定

        this._key_times[ti] = time; // 値を配列に設定

        if (dimension == 1) {
          // スカラー
          this._key_values[vi] = value;
        } else {
          // ベクトル
          for (var j = 0; j < dimension; ++j) {
            this._key_values[vi + j] = value[j];
          }
        }
      } // 全時刻の値が変化


      this.notifyValueChange(Interval.UNIVERSAL);
    }
    /**
     * @override
     */

  }, {
    key: "isTypeSupported",
    value: function isTypeSupported(type) {
      var from_type = this._value_type;
      return type.isConvertible(from_type);
    }
    /**
     * @override
     */

  }, {
    key: "getValue",
    value: function getValue(time, type) {
      var from_type = this._value_type;

      var from_value = this._getInterpolatedValue(time);

      return type.convertValue(from_type, from_value);
    }
    /**
     * @override
     */

  }, {
    key: "getInvariance",
    value: function getInvariance(interval) {
      var first_time = this._key_times[0];
      var last_time = this._key_times[this._num_keyframes - 1];
      var ival_inner = new Interval(first_time, last_time, true, true); // 全体の不変性情報 (2区間程度なので毎回生成)

      var invr_full = new Invariance();
      invr_full.write(ival_inner.getPrecedings()); // 最初のキーの時刻とその前の区間

      invr_full.write(ival_inner.getFollowings()); // 最後のキーの時刻とその後の区間
      // interval 範囲に絞って返す

      return invr_full.getNarrowed(interval);
    }
    /**
     * @summary time での補間値を取得
     *
     * @param {mapray.animation.Time} time
     *
     * @return {object}  補間値 (this._value_type に適応した型)
     *
     * @private
     */

  }, {
    key: "_getInterpolatedValue",
    value: function _getInterpolatedValue(time) {
      // this._key_times に time より後の時刻が存在すれば、その中で最小のインデックス
      // そのような時刻が存在しなければ this._num_keyframes
      var index = AnimUtil.findKeyFrameIndex(time, this._key_times, 0, this._num_keyframes);

      if (index == 0) {
        // time が最初のキー時刻と同じか、その前のときは最初のキー値で一定
        return this._createKeyFrameValue(0);
      } else if (index == this._num_keyframes) {
        // time が最後のキー時刻と同じか、その後のときは最後のキー値で一定
        return this._createKeyFrameValue(index - 1);
      } else {
        // その他のときは前後のキー値で線形補間
        return this._createValueBy2Keys(index - 1, index, time);
      }
    }
    /**
     * @summary キーフレーム値を生成
     *
     * @param {number} index  キーフレームのインデックス
     *
     * @return {object}  キーフレーム値 (this._value_type に適応した型)
     *
     * @private
     */

  }, {
    key: "_createKeyFrameValue",
    value: function _createKeyFrameValue(index) {
      var dimension = this._dimension;
      var key_values = this._key_values;

      if (dimension == 1) {
        // スカラー
        return key_values[index];
      } else {
        // ベクトル
        var vi = dimension * index;
        var vec = new Float64Array(dimension);

        for (var i = 0; i < dimension; ++i) {
          vec[i] = key_values[vi + i];
        }

        return vec;
      }
    }
    /**
     * @summary キーフレーム間の補間値を生成
     *
     * @param {number} i0  先キーフレームのインデックス
     * @param {number} i1  後キーフレームのインデックス
     * @param {mapray.animation.Time} time
     *
     * @return {object}  補間値 (this._value_type に適応した型)
     *
     * @private
     */

  }, {
    key: "_createValueBy2Keys",
    value: function _createValueBy2Keys(i0, i1, time) {
      var x0 = this._key_times[i0].toNumber();

      var x1 = this._key_times[i1].toNumber();

      var r1 = (time.toNumber() - x0) / (x1 - x0);
      var r0 = 1 - r1;
      var dimension = this._dimension;
      var key_values = this._key_values;

      if (dimension == 1) {
        // スカラー
        return r0 * key_values[i0] + r1 * key_values[i1];
      } else {
        // ベクトル
        var vi0 = dimension * i0;
        var vi1 = dimension * i1;
        var vec = new Float64Array(dimension);

        for (var i = 0; i < dimension; ++i) {
          vec[i] = r0 * key_values[vi0 + i] + r1 * key_values[vi1 + i];
        }

        return vec;
      }
    }
  }]);

  return KFLinearCurve;
}(Curve);

/**
 * @summary キーフレームによる階段関数
 *
 * @classdesc
 * <p>あるキーフレームから次のキーフレームの直前まで一定の値を返す階段関数である。</p>
 * <p>構築子により任意の関数値の型を指定することができる。</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Curve
 */

var KFStepCurve =
/*#__PURE__*/
function (_Curve) {
  _inherits(KFStepCurve, _Curve);

  /**
   * @desc
   * <p>type 型の階段関数を keyframes により生成する。</p>
   * <p>type は任意の型を指定することができる。</p>
   * <p>keyframes を省略したときは type 型の既定値を返す定数関数と同等になる。keyframes の形式に関しては
   *    {@link mapray.animation.KFStepCurve#setKeyFrames setKeyFrames()} を参照のこと。</p>
   *
   * @param {mapray.animation.Type} type  関数値の型
   * @param {object[]}       [keyframes]  初期キーフレーム
   */
  function KFStepCurve(type, keyframes) {
    var _this;

    _classCallCheck(this, KFStepCurve);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(KFStepCurve).call(this));
    _this._value_type = type; // any type

    _this._num_keyframes = undefined; // >= 1

    _this._key_times = undefined; // Time[]

    _this._key_values = undefined; // object[]

    if (keyframes !== undefined) {
      // 初期のキーフレームを設定
      _this.setKeyFrames(keyframes);
    } else {
      // 既定のキーフレームを設定
      var t0 = Time.fromNumber(0);
      var dv = type.getDefaultValue();

      _this.setKeyFrames([t0, dv]);
    }

    return _this;
  }
  /**
   * @summary キーフレーム設定
   *
   * @desc
   * <p>keyframes により、すべてのキーフレームを指定する。</p>
   *
   * <p>
   * 条件1: keyframes.length >= 2 (キーフレーム数 >= 1)<br>
   * 条件2: すべての i, j において、i < j ⇔ 時刻i < 時刻j<br>
   * 条件3: すべての i において、値i は構築子の type 引数で指定した型のインスタンス
   * </p>
   *
   * @param {object[]} keyframes  [時刻0, 値0, 時刻1, 値1, ...]
   */


  _createClass(KFStepCurve, [{
    key: "setKeyFrames",
    value: function setKeyFrames(keyframes) {
      this._num_keyframes = keyframes.length / 2;
      this._key_times = new Array(this._num_keyframes);
      this._key_values = new Array(this._num_keyframes); // キーフレームを設定

      for (var i = 0; i < this._num_keyframes; ++i) {
        var time = keyframes[2 * i];
        var value = keyframes[2 * i + 1];
        this._key_times[i] = time;
        this._key_values[i] = this._value_type.getCloneValue(value);
      } // 全時刻の値が変化


      this.notifyValueChange(Interval.UNIVERSAL);
    }
    /**
     * @override
     */

  }, {
    key: "isTypeSupported",
    value: function isTypeSupported(type) {
      var from_type = this._value_type;
      return type.isConvertible(from_type);
    }
    /**
     * @override
     */

  }, {
    key: "getValue",
    value: function getValue(time, type) {
      var from_type = this._value_type;

      var from_value = this._getInterpolatedValue(time);

      return type.convertValue(from_type, from_value);
    }
    /**
     * @override
     */

  }, {
    key: "getInvariance",
    value: function getInvariance(interval) {
      if (this._num_keyframes == 1) {
        // キーフレームが 1 個のときは ConstantCurve と同じく、全時間で一定値
        // (UNIVERSAL と非空区間は必ず交差するので interval の参照は不要)
        return new Invariance().write(Interval.UNIVERSAL);
      } else {
        // assert: this._num_keyframes >= 2
        var invr = new Invariance(); // 最初から2番目のキー時刻より前は一定値

        var first = this._key_times[1];
        invr.write(new Interval(first, first).getPrecedings()); // 最後のキー時刻とその後は一定値

        var lastL = this._key_times[this._num_keyframes - 2];
        var lastU = this._key_times[this._num_keyframes - 1];
        invr.write(new Interval(lastL, lastU, false, true).getFollowings()); // interval 範囲に絞って返す

        return invr.getNarrowed(interval);
      }
    }
    /**
     * @summary time での補間値を取得
     *
     * @param {mapray.animation.Time} time
     *
     * @return {object}  補間値 (this._value_type に適応した型)
     *
     * @private
     */

  }, {
    key: "_getInterpolatedValue",
    value: function _getInterpolatedValue(time) {
      // this._key_times に time より後の時刻が存在すれば、その中で最小のインデックス
      // そのような時刻が存在しなければ this._num_keyframes
      var found = AnimUtil.findKeyFrameIndex(time, this._key_times, 0, this._num_keyframes); // キー値のインデックス

      var index = found > 0 ? found - 1 : 0; // 補間値を生成

      return this._value_type.getCloneValue(this._key_values[index]);
    }
  }]);

  return KFStepCurve;
}(Curve);

var $map$1 = arrayIteration.map;
var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('map'); // FF49- issue

var USES_TO_LENGTH$3 = arrayMethodUsesToLength('map'); // `Array.prototype.map` method
// https://tc39.github.io/ecma262/#sec-array.prototype.map
// with adding support of @@species

_export({
  target: 'Array',
  proto: true,
  forced: !HAS_SPECIES_SUPPORT || !USES_TO_LENGTH$3
}, {
  map: function map(callbackfn
  /* , thisArg */
  ) {
    return $map$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
  }
});

/**
 * @summary 複合ベクトル関数
 *
 * @classdesc
 * <p>複数の数値関数から構成されるベクトル関数である。</p>
 * <p>関数値の型は構築子のパラメータにより vector2, vector3 または vector4 を指定する。</p>
 * <p>子関数は number または number へ変換可能な型でなければならない。</p>
 *
 * @memberof mapray.animation
 * @extends mapray.animation.Curve
 */

var ComboVectorCurve =
/*#__PURE__*/
function (_Curve) {
  _inherits(ComboVectorCurve, _Curve);

  /**
   * @desc
   * <p>type 型のベクトル関数を生成する。ベクトルの各要素の値は子関数の値になる。</p>
   *
   * <p>children を省略したときは、ベクトルの全要素が 0 となる定数関数と同等になる。children の形式に関しては
   *    {@link mapray.animation.ComboVectorCurve#setChildren setChildren()} を参照のこと。</p>
   *
   * @param {mapray.animation.Type}       type     関数値の型 (ベクトル型)
   * @param {mapray.animation.Curve[]} [children]  初期の全子関数
   *
   * @throws {@link mapray.animation.TypeMismatchError}  type または children に非対応の型が存在するとき
   */
  function ComboVectorCurve(type, children) {
    var _this;

    _classCallCheck(this, ComboVectorCurve);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(ComboVectorCurve).call(this));
    var dimension = AnimUtil.getDimension(type);

    if (dimension < 2 && dimension > 4) {
      // type はベクトル型ではない
      throw new TypeMismatchError("unexpected type");
    }

    _this._vector_type = type;
    _this._dimension = dimension; // 2〜4

    _this._children = new Array(dimension); // 子関数の配列

    _this._listeners = new Array(dimension); // 子関数に対応した ValueChangeListener

    _this._setupInitialChildren(); // 初期値が指定されているときは設定


    if (children !== undefined) {
      _this.setChildren(children);
    }

    return _this;
  }
  /**
   * @summary 子関数を設定 (個別)
   *
   * @desc
   * <p>index の要素のみの子関数を設定する。その他の要素は変更されない。</p>
   *
   * @param {number}                 index  要素インデックス
   * @param {mapray.animation.Curve} curve  子関数
   *
   * @throws {@link mapray.animation.TypeMismatchError}  curve が非対応の型のとき
   */


  _createClass(ComboVectorCurve, [{
    key: "setChild",
    value: function setChild(index, curve) {
      this._setChildCommon(index, curve); // curve が未知なので全時刻の値が変化したことにする


      this.notifyValueChange(Interval.UNIVERSAL);
    }
    /**
     * @summary 子関数を設定 (一括)
     *
     * @desc
     * <p>curves にすべての子関数を指定する。curves の要素数はベクトルの次数と同数である。</p>
     *
     * @param {mapray.animation.Curve[]} curves  全子関数
     *
     * @throws {@link mapray.animation.TypeMismatchError}  curves に非対応の型が存在するとき
     */

  }, {
    key: "setChildren",
    value: function setChildren(curves) {
      for (var i = 0; i < this._dimension; ++i) {
        this._setChildCommon(i, curves[i]);
      } // curves が未知なので全時刻の値が変化したことにする


      this.notifyValueChange(Interval.UNIVERSAL);
    }
    /**
     * @override
     */

  }, {
    key: "isTypeSupported",
    value: function isTypeSupported(type) {
      var from_type = this._vector_type;
      return type.isConvertible(from_type);
    }
    /**
     * @override
     */

  }, {
    key: "getValue",
    value: function getValue(time, type) {
      var from_type = this._vector_type;

      var from_value = this._getCompoundValue(time);

      return type.convertValue(from_type, from_value);
    }
    /**
     * @override
     */

  }, {
    key: "getInvariance",
    value: function getInvariance(interval) {
      // すべての子関数の不変性情報の交差
      var invariances = this._children.map(function (child) {
        return child.getInvariance(interval);
      });

      return Invariance.merge(invariances);
    }
    /**
     * 初期の子関数とリスナーを設定
     *
     * @private
     */

  }, {
    key: "_setupInitialChildren",
    value: function _setupInitialChildren() {
      var _this2 = this;

      var init_child = new ConstantCurve(vec_compo_type);

      for (var i = 0; i < this._dimension; ++i) {
        var listener = function listener(interval) {
          _this2.notifyValueChange(interval);
        };

        init_child.addValueChangeListener(listener);
        this._children[i] = init_child;
        this._listeners[i] = listener;
      }
    }
    /**
     * @summary 子要素を設定 (共通ルーチン)
     *
     * @param {number}                 index
     * @param {mapray.animation.Curve} curve
     *
     * @throws {@link mapray.animation.TypeMismatchError}
     *
     * @private
     */

  }, {
    key: "_setChildCommon",
    value: function _setChildCommon(index, curve) {
      var _this3 = this;

      if (!curve.isTypeSupported(vec_compo_type)) {
        // curve の型をベクトルの要素の型に変換できない
        throw new TypeMismatchError("type mismatch error");
      } // 以前の子のリスナーを解除


      var old_child = this._children[index];
      var old_listener = this._listeners[index];
      old_child.removeValueChangeListener(old_listener); // 新しい子のリスナーを設定

      var listener = function listener(interval) {
        _this3.notifyValueChange(interval);
      };

      curve.addValueChangeListener(listener); // 新しい子を設定

      this._children[index] = curve;
      this._listeners[index] = listener;
    }
    /**
     * @summary time での複合値を取得
     *
     * @param {mapray.animation.Time} time
     *
     * @return {number[]}  複合値 (this._vector_type に適応した型)
     *
     * @private
     */

  }, {
    key: "_getCompoundValue",
    value: function _getCompoundValue(time) {
      var dimension = this._dimension;
      var vec = new Float64Array(dimension);

      for (var i = 0; i < dimension; ++i) {
        vec[i] = this._children[i].getValue(time, vec_compo_type);
      }

      return vec;
    }
  }]);

  return ComboVectorCurve;
}(Curve);
/**
 * ベクトルの要素型
 * @private
 */


var vec_compo_type = Type.find("number");

/**
 * アニメーション関連の機能全体が含まれる名前空間
 *
 * @namespace animation
 * @memberof mapray
 */

var animation = {
  AnimationError: AnimationError,
  Time: Time,
  Interval: Interval,
  Invariance: Invariance,
  Type: Type,
  Curve: Curve,
  Updater: Updater,
  Binder: Binder,
  TypeMismatchError: TypeMismatchError,
  BindingBlock: BindingBlock,
  EasyBindingBlock: EasyBindingBlock,
  ConstantCurve: ConstantCurve,
  KFLinearCurve: KFLinearCurve,
  KFStepCurve: KFStepCurve,
  ComboVectorCurve: ComboVectorCurve
};

/**
 * @summary 始点と方向
 * @classdesc
 * <p>始点と方向で表現される半直線である。</p>
 * @memberof mapray
 * @see mapray.Viewer#getRayIntersection
 * @see mapray.Camera#getCanvasRay
 */

var Ray =
/**
 * @desc
 * <p>pos の参照を {@link mapray.Ray#position}, dir の参照を {@link mapray.Ray#direction} に代入する。</p>
 * <p>ただし引数を省略したとき、対応するメンバーには新たに生成されたベクトルが代入される。</p>
 * @param {mapray.Vector3} [pos]  レイの始点
 * @param {mapray.Vector3} [dir]  レイの方向
 */
function Ray(pos, dir) {
  _classCallCheck(this, Ray);

  /**
   *  @summary レイの始点
   *  @member mapray.Ray#position
   *  @type {mapray.Vector3}
   *  @default [0, 0, 0]
   */
  this.position = pos || GeoMath.createVector3();
  /**
   *  @summary レイの方向
   *  @desc
   *  <p>非零ベクトルでなければならない。</p>
   *  @member mapray.Ray#direction
   *  @type {mapray.Vector3}
   *  @default [0, 0, -1]
   */

  this.direction = dir || GeoMath.createVector3([0, 0, -1]);
};

/**
 * @summary 視点を表現するカメラ
 *
 * @classdesc
 * <p>視点を表現するカメラである。</p>
 * <p>インスタンスは {@link mapray.Viewer#camera} から得ることができる。</p>
 *
 * @hideconstructor
 * @memberof mapray
 * @see mapray.Viewer
 */

var Camera =
/*#__PURE__*/
function () {
  /**
   * @param {Element} canvas  レンダリング先 Canvas
   * @package
   */
  function Camera(canvas) {
    _classCallCheck(this, Camera);

    this._canvas = canvas;
    /**
     *  @summary カメラの画角 (Degrees)
     *  @member mapray.Camera#fov
     *  @type {number}
     *  @default 46
     */

    this.fov = 46;
    /**
     *  @summary 近接平面距離 (Meters)
     *  @member mapray.Camera#near
     *  @type {number}
     *  @default 1
     */

    this.near = 1;
    /**
     *  @summary 遠方平面距離 (Meters)
     *  @member mapray.Camera#far
     *  @type {number}
     *  @default 1000
     */

    this.far = 1000;
    /**
     *  @summary 視点空間から GOCS への変換行列
     *  @member mapray.Camera#view_to_gocs
     *  @type {mapray.Matrix}
     *  @default 恒等行列
     */

    this.view_to_gocs = GeoMath.createMatrix();
    GeoMath.setIdentity(this.view_to_gocs);
  }
  /**
   * @summary 変換行列 canvas_to_view を取得
   * @desc
   * <p>キャンバス座標系から視点座標系へ座標を変換するための変換行列を取得する。</p>
   * <p>結果は omat に設定するが、omat を省略した場合は新規に生成した行列オブジェクトを使用する。</p>
   * <p>キャンバスの幅または高さが 0 のときは結果は不定値となる。</p>
   * @param  {mapray.Matrix} [omat]  結果を設定する行列オブジェクト
   * @return {mapray.Matrix}         omat または新規に生成した行列
   */


  _createClass(Camera, [{
    key: "getCanvasToView",
    value: function getCanvasToView(omat) {
      var dst = omat || GeoMath.createMatrix(); // キャンバス画素数 -> sx, sy

      var sx = this._canvas.width;
      var sy = this._canvas.height; // 近接遠方平面距離 -> n, f

      var n = this.near;
      var f = this.far; // n 勾配 (対角線画角を想定) -> gx, gy

      var hfov = this.fov * GeoMath.DEGREE / 2;
      var aspect = sy / sx;
      var gx = n * Math.tan(hfov) / Math.sqrt(1 + aspect * aspect);
      var gy = gx * aspect; // 行列の要素を設定

      dst[0] = 2 * gx / (n * sx);
      dst[1] = 0;
      dst[2] = 0;
      dst[3] = 0;
      dst[4] = 0;
      dst[5] = -2 * gy / (n * sy);
      dst[6] = 0;
      dst[7] = 0;
      dst[8] = 0;
      dst[9] = 0;
      dst[10] = 0;
      dst[11] = (n - f) / (n * f);
      dst[12] = -gx / n;
      dst[13] = gy / n;
      dst[14] = -1;
      dst[15] = 1 / n;
      return dst;
    }
    /**
     * @summary 変換行列 canvas_to_gocs を取得
     * @desc
     * <p>キャンバス座標系から地心座標系 (GOCS) へ座標を変換するための変換行列を取得する。</p>
     * <p>結果は omat に設定するが、omat を省略した場合は新規に生成した行列オブジェクトを使用する。</p>
     * <p>キャンバスの幅または高さが 0 のときは結果は不定値となる。</p>
     * @param  {mapray.Matrix} [omat]  結果を設定する行列オブジェクト
     * @return {mapray.Matrix}         omat または新規に生成した行列
     */

  }, {
    key: "getCanvasToGocs",
    value: function getCanvasToGocs(omat) {
      /*==  canvas_to_view  ==*/
      var nMat = this.getCanvasToView(omat);
      var n00 = nMat[0]; //  n10 = 0
      //  n20 = 0
      //  n30 = 0
      //  n01 = 0

      var n11 = nMat[5]; //  n21 = 0
      //  n31 = 0
      //  n03 = 0
      //  n13 = 0
      //  n23 = 0

      var n32 = nMat[11];
      var n03 = nMat[12];
      var n13 = nMat[13]; //  n23 = -1

      var n33 = nMat[15];
      /*==  view_to_gocs  ==*/

      var mMat = this.view_to_gocs;
      var m00 = mMat[0];
      var m10 = mMat[1];
      var m20 = mMat[2]; //  m30 = 0

      var m01 = mMat[4];
      var m11 = mMat[5];
      var m21 = mMat[6]; //  m31 = 0

      var m02 = mMat[8];
      var m12 = mMat[9];
      var m22 = mMat[10]; //  m32 = 0

      var m03 = mMat[12];
      var m13 = mMat[13];
      var m23 = mMat[14]; //  m33 = 1

      /*==  dst = view_to_gocs * canvas_to_view  ==*/

      var dst = nMat;
      dst[0] = m00 * n00;
      dst[1] = m10 * n00;
      dst[2] = m20 * n00; // dst[ 3] = 0

      dst[4] = m01 * n11;
      dst[5] = m11 * n11;
      dst[6] = m21 * n11; // dst[ 7] = 0

      dst[8] = m03 * n32;
      dst[9] = m13 * n32;
      dst[10] = m23 * n32; // dst[ 11] = n32

      dst[12] = m00 * n03 + m01 * n13 - m02 + m03 * n33;
      dst[13] = m10 * n03 + m11 * n13 - m12 + m13 * n33;
      dst[14] = m20 * n03 + m21 * n13 - m22 + m23 * n33; // dst[ 12] = n33

      return dst;
    }
    /**
     * @summary 変換行列 view_to_canvas を取得
     * @desc
     * <p>視点座標系からキャンバス座標系へ座標を変換するための変換行列を取得する。</p>
     * <p>結果は omat に設定するが、omat を省略した場合は新規に生成した行列オブジェクトを使用する。</p>
     * <p>キャンバスの幅または高さが 0 のときは結果は不定値となる。</p>
     * @param  {mapray.Matrix} [omat]  結果を設定する行列オブジェクト
     * @return {mapray.Matrix}         omat または新規に生成した行列
     */

  }, {
    key: "getViewToCanvas",
    value: function getViewToCanvas(omat) {
      var dst = omat || GeoMath.createMatrix(); // キャンバス画素数 -> sx, sy

      var sx = this._canvas.width;
      var sy = this._canvas.height; // 近接遠方平面距離 -> n, f

      var n = this.near;
      var f = this.far; // n 勾配 (対角線画角を想定) -> gx, gy

      var hfov = this.fov * GeoMath.DEGREE / 2;
      var aspect = sy / sx;
      var gx = n * Math.tan(hfov) / Math.sqrt(1 + aspect * aspect);
      var gy = gx * aspect; // 行列の要素を設定

      dst[0] = n * sx / (2 * gx);
      dst[1] = 0;
      dst[2] = 0;
      dst[3] = 0;
      dst[4] = 0;
      dst[5] = -n * sy / (2 * gy);
      dst[6] = 0;
      dst[7] = 0;
      dst[8] = -sx / 2;
      dst[9] = -sy / 2;
      dst[10] = f / (n - f);
      dst[11] = -1;
      dst[12] = 0;
      dst[13] = 0;
      dst[14] = n * f / (n - f);
      dst[15] = 0;
      return dst;
    }
    /**
     * @summary キャンバス座標に対応するレイを取得
     * @desc
     * <p>キャンバス上の cpos で示した点に対応するレイを取得する。</p>
     * <p>始点は近接平面上に置き、方向は長さ 1 に正規化される。</p>
     * <p>返されるレイの座標系は GOCS である。</p>
     * @param  {mapray.Vector2} cpos    キャンバス上の位置
     * @param  {mapray.Ray}     [oray]  結果を設定する Ray オブジェクト
     * @return {mapray.Ray}             oray または新規に生成した Ray
     */

  }, {
    key: "getCanvasRay",
    value: function getCanvasRay(cpos, oray) {
      var x = cpos[0];
      var y = cpos[1];
      var dst = oray || new Ray(); // Q = Mr (x, y, 0, 1)^t

      var mr = this.getCanvasToGocs(Camera._temp_mat);
      var qx = x * mr[0] + y * mr[4] + mr[12];
      var qy = x * mr[1] + y * mr[5] + mr[13];
      var qz = x * mr[2] + y * mr[6] + mr[14];
      var qw = x * mr[3] + y * mr[7] + mr[15]; // Q を通常の座標に変換

      var pos = dst.position;
      pos[0] = qx / qw;
      pos[1] = qy / qw;
      pos[2] = qz / qw; // Vr = pos - Mg (0, 0, 0)^t

      var mg = this.view_to_gocs;
      var dir = dst.direction;
      dir[0] = pos[0] - mg[12];
      dir[1] = pos[1] - mg[13];
      dir[2] = pos[2] - mg[14];
      GeoMath.normalize3(dir, dir);
      return dst;
    }
    /**
     * @summary レンダリング情報を生成
     * @return {mapray.Camera.RenderInfo}
     * @package
     */

  }, {
    key: "createRenderInfo",
    value: function createRenderInfo() {
      var canvas = this._canvas;
      return new RenderInfo(this, canvas.width, canvas.height);
    }
  }]);

  return Camera;
}();

Camera._temp_mat = GeoMath.createMatrix();
/**
 * @summary カメラから得るレンダリング情報
 * @memberof mapray.Camera
 * @private
 */

var RenderInfo =
/*#__PURE__*/
function () {
  /**
   * @param camera {mapray.Camera}  対象カメラ
   * @param width  {number}         ビューポートの幅
   * @param height {number}         ビューポートの高さ
   */
  function RenderInfo(camera, width, height) {
    _classCallCheck(this, RenderInfo);

    // オブジェクトを生成
    this._view_to_clip = GeoMath.createMatrix();
    this._volume_planes = [];

    for (var i = 0; i < 6; ++i) {
      this._volume_planes.push(GeoMath.createVector4());
    }

    this._pixel_step = 0; // オブジェクトを設定

    this._setup_view_to_clip(camera, width, height);

    this._setup_volume_planes();

    this._setup_pixel_step(width, height);
  }
  /**
   * @summary 視点空間からクリップ同次空間への変換行列
   * @type {mapray.Matrix}
   * @readonly
   */


  _createClass(RenderInfo, [{
    key: "_setup_view_to_clip",

    /**
     * @private
     */
    value: function _setup_view_to_clip(camera, width, height) {
      var hfov = camera.fov * GeoMath.DEGREE / 2;
      var aspect = height / width;
      var horiz = camera.near * Math.tan(hfov) / Math.sqrt(1 + aspect * aspect); // 対角線画角を想定して水平位置を計算

      var left = -horiz;
      var right = horiz;
      var bottom = -horiz * aspect;
      var top = horiz * aspect;
      GeoMath.frustum_matrix(left, right, bottom, top, camera.near, camera.far, this._view_to_clip);
    }
    /**
     * @private
     */

  }, {
    key: "_setup_volume_planes",
    value: function _setup_volume_planes() {
      var matrix = this._view_to_clip;
      var plane = this._volume_planes; // 視体積の内側を向いた平面を取得
      // これらの式は任意の射影行列に対して有効

      this._add_matrix_rows(matrix, 3, 2, plane[0]); //   near = m3 + m2


      this._sub_matrix_rows(matrix, 3, 2, plane[1]); //    far = m3 - m2


      this._add_matrix_rows(matrix, 3, 0, plane[2]); //   left = m3 + m0


      this._sub_matrix_rows(matrix, 3, 0, plane[3]); //  right = m3 - m0


      this._add_matrix_rows(matrix, 3, 1, plane[4]); // bottom = m3 + m1


      this._sub_matrix_rows(matrix, 3, 1, plane[5]); //    top = m3 - m1
      // 法線を正規化


      for (var i = 0; i < 6; ++i) {
        var p = plane[i];
        var x = p[0];
        var y = p[1];
        var z = p[2];
        var ilen = 1 / Math.sqrt(x * x + y * y + z * z); // 長さの逆数

        p[0] *= ilen;
        p[1] *= ilen;
        p[2] *= ilen;
        p[3] *= ilen;
      }
    }
    /**
     * @private
     */

  }, {
    key: "_setup_pixel_step",
    value: function _setup_pixel_step(width, height) {
      // mIJ は view_to_clip の I 行 J 列の成分
      //
      //         2 (m33 - m32)
      //   dx = ---------------
      //           m00 width
      //
      //         2 (m33 - m32)
      //   dy = ---------------
      //          m11 height
      var mat = this._view_to_clip;
      var m00 = mat[0];
      var m11 = mat[5];
      var m32 = mat[11];
      var m33 = mat[15];
      var n = 2 * (m33 - m32);
      var dx = n / (m00 * width);
      var dy = n / (m11 * height);
      this._pixel_step = Math.sqrt(dx * dx + dy * dy) * Math.SQRT1_2;
    }
    /**
     * @private
     */

  }, {
    key: "_add_matrix_rows",
    value: function _add_matrix_rows(mat, row1, row2, dst) {
      dst[0] = mat[row1] + mat[row2];
      dst[1] = mat[row1 + 4] + mat[row2 + 4];
      dst[2] = mat[row1 + 8] + mat[row2 + 8];
      dst[3] = mat[row1 + 12] + mat[row2 + 12];
      return dst;
    }
    /**
     * @private
     */

  }, {
    key: "_sub_matrix_rows",
    value: function _sub_matrix_rows(mat, row1, row2, dst) {
      dst[0] = mat[row1] - mat[row2];
      dst[1] = mat[row1 + 4] - mat[row2 + 4];
      dst[2] = mat[row1 + 8] - mat[row2 + 8];
      dst[3] = mat[row1 + 12] - mat[row2 + 12];
      return dst;
    }
  }, {
    key: "view_to_clip",
    get: function get() {
      return this._view_to_clip;
    }
    /**
     * @summary 視体積の平面ベクトル配列
     * @desc
     * <p>以下の順序で 6 枚の平面ベクトルが格納されている。</p>
     *
     * <pre>
     * [near, far, left, right, bottom, top]
     * </pre>
     *
     * <p>各平面の x, y, z は長さ 1 に正規化されている。</p>
     *
     * @type {mapray.Vector4[]}
     * @readonly
     */

  }, {
    key: "volume_planes",
    get: function get() {
      return this._volume_planes;
    }
    /**
     * @summary 視点空間での画素の変化量
     * @desc
     * <p>ビューポートの画素に対応する視点空間の Z = -1 平面での変化量を返す。</p>
     *
     * @type {number}
     * @readonly
     */

  }, {
    key: "pixel_step",
    get: function get() {
      return this._pixel_step;
    }
  }]);

  return RenderInfo;
}();

/**
 * @summary WebGL の環境
 * @desc
 * WebGL レンダリングコンテキストを生成し、そのコンテキストに関連する情報を提供する。
 * @memberof mapray
 * @private
 */
var GLEnv =
/*#__PURE__*/
function () {
  /**
   * @param canvas {HTMLCanvasElement}  レンダリングターゲットとするキャンバス
   */
  function GLEnv(canvas) {
    _classCallCheck(this, GLEnv);

    var ctx_attribs = {
      depth: true,
      antialias: true
    };

    var context = this._getContextWebGL(canvas, ctx_attribs);

    if (!context) {
      throw new Error("It doesn't appear your computer can support WebGL.");
    }

    this._canvas = canvas;
    this._context = context;

    this._setupExtensions(context);
  }
  /**
   * @summary WebGL コンテキストを取得
   * @param  {HTMLCanvasElement}      canvas       Canvas 要素
   * @param  {WebGLContextAttributes} ctx_attribs  生成属性 (省略可能)
   * @return {WebGLRenderingContext}               取得された WebGL コンテキスト (コンテキストを持たないときは null)
   * @private
   *
   * @see https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2
   */


  _createClass(GLEnv, [{
    key: "_getContextWebGL",
    value: function _getContextWebGL(canvas, ctx_attribs) {
      var contextTypes = ["webgl", "experimental-webgl"];

      for (var i = 0; i < contextTypes.length; ++i) {
        var context = canvas.getContext(contextTypes[i], ctx_attribs);

        if (context) {
          return context;
        }
      }

      return null;
    }
    /**
     * @summary 既知の WebGL 拡張を設定
     * @param  {WebGLRenderingContext} gl  WebGL コンテキスト
     * @private
     * @see https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14
     */

  }, {
    key: "_setupExtensions",
    value: function _setupExtensions(gl) {
      // OES_element_index_uint
      this.OES_element_index_uint = gl.getExtension("OES_element_index_uint"); // EXT_texture_filter_anisotropic

      this.EXT_texture_filter_anisotropic = gl.getExtension("EXT_texture_filter_anisotropic") || gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic") || gl.getExtension("MOZ_EXT_texture_filter_anisotropic");
    }
    /**
     * @summary レンダリングターゲットとするキャンバス
     * @type {HTMLCanvasElement}
     * @readonly
     */

  }, {
    key: "canvas",
    get: function get() {
      return this._canvas;
    }
    /**
     * @summary WebGL レンダリングコンテキスト
     * @type {WebGLRenderingContext}
     * @readonly
     */

  }, {
    key: "context",
    get: function get() {
      return this._context;
    }
  }]);

  return GLEnv;
}();

var $forEach$2 = arrayIteration.forEach;
var STRICT_METHOD$1 = arrayMethodIsStrict('forEach');
var USES_TO_LENGTH$4 = arrayMethodUsesToLength('forEach'); // `Array.prototype.forEach` method implementation
// https://tc39.github.io/ecma262/#sec-array.prototype.foreach

var arrayForEach = !STRICT_METHOD$1 || !USES_TO_LENGTH$4 ? function forEach(callbackfn
/* , thisArg */
) {
  return $forEach$2(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
} : [].forEach;

// https://tc39.github.io/ecma262/#sec-array.prototype.foreach


_export({
  target: 'Array',
  proto: true,
  forced: [].forEach != arrayForEach
}, {
  forEach: arrayForEach
});

var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('slice');
var USES_TO_LENGTH$5 = arrayMethodUsesToLength('slice', {
  ACCESSORS: true,
  0: 0,
  1: 2
});
var SPECIES$4 = wellKnownSymbol('species');
var nativeSlice = [].slice;
var max$1 = Math.max; // `Array.prototype.slice` method
// https://tc39.github.io/ecma262/#sec-array.prototype.slice
// fallback for not array-like ES3 strings and DOM objects

_export({
  target: 'Array',
  proto: true,
  forced: !HAS_SPECIES_SUPPORT$1 || !USES_TO_LENGTH$5
}, {
  slice: function slice(start, end) {
    var O = toIndexedObject(this);
    var length = toLength(O.length);
    var k = toAbsoluteIndex(start, length);
    var fin = toAbsoluteIndex(end === undefined ? length : end, length); // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible

    var Constructor, result, n;

    if (isArray(O)) {
      Constructor = O.constructor; // cross-realm fallback

      if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
        Constructor = undefined;
      } else if (isObject(Constructor)) {
        Constructor = Constructor[SPECIES$4];
        if (Constructor === null) Constructor = undefined;
      }

      if (Constructor === Array || Constructor === undefined) {
        return nativeSlice.call(O, k, fin);
      }
    }

    result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0));

    for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);

    result.length = n;
    return result;
  }
});

var test$1 = [];
var nativeSort = test$1.sort; // IE8-

var FAILS_ON_UNDEFINED = fails(function () {
  test$1.sort(undefined);
}); // V8 bug

var FAILS_ON_NULL = fails(function () {
  test$1.sort(null);
}); // Old WebKit

var STRICT_METHOD$2 = arrayMethodIsStrict('sort');
var FORCED$5 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$2; // `Array.prototype.sort` method
// https://tc39.github.io/ecma262/#sec-array.prototype.sort

_export({
  target: 'Array',
  proto: true,
  forced: FORCED$5
}, {
  sort: function sort(comparefn) {
    return comparefn === undefined ? nativeSort.call(toObject(this)) : nativeSort.call(toObject(this), aFunction$1(comparefn));
  }
});

var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('splice');
var USES_TO_LENGTH$6 = arrayMethodUsesToLength('splice', {
  ACCESSORS: true,
  0: 0,
  1: 2
});
var max$2 = Math.max;
var min$4 = Math.min;
var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded'; // `Array.prototype.splice` method
// https://tc39.github.io/ecma262/#sec-array.prototype.splice
// with adding support of @@species

_export({
  target: 'Array',
  proto: true,
  forced: !HAS_SPECIES_SUPPORT$2 || !USES_TO_LENGTH$6
}, {
  splice: function splice(start, deleteCount
  /* , ...items */
  ) {
    var O = toObject(this);
    var len = toLength(O.length);
    var actualStart = toAbsoluteIndex(start, len);
    var argumentsLength = arguments.length;
    var insertCount, actualDeleteCount, A, k, from, to;

    if (argumentsLength === 0) {
      insertCount = actualDeleteCount = 0;
    } else if (argumentsLength === 1) {
      insertCount = 0;
      actualDeleteCount = len - actualStart;
    } else {
      insertCount = argumentsLength - 2;
      actualDeleteCount = min$4(max$2(toInteger(deleteCount), 0), len - actualStart);
    }

    if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) {
      throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
    }

    A = arraySpeciesCreate(O, actualDeleteCount);

    for (k = 0; k < actualDeleteCount; k++) {
      from = actualStart + k;
      if (from in O) createProperty(A, k, O[from]);
    }

    A.length = actualDeleteCount;

    if (insertCount < actualDeleteCount) {
      for (k = actualStart; k < len - actualDeleteCount; k++) {
        from = k + actualDeleteCount;
        to = k + insertCount;
        if (from in O) O[to] = O[from];else delete O[to];
      }

      for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
    } else if (insertCount > actualDeleteCount) {
      for (k = len - actualDeleteCount; k > actualStart; k--) {
        from = k + actualDeleteCount - 1;
        to = k + insertCount - 1;
        if (from in O) O[to] = O[from];else delete O[to];
      }
    }

    for (k = 0; k < insertCount; k++) {
      O[k + actualStart] = arguments[k + 2];
    }

    O.length = len - actualDeleteCount + insertCount;
    return A;
  }
});

var nativeExpm1 = Math.expm1;
var exp = Math.exp; // `Math.expm1` method implementation
// https://tc39.github.io/ecma262/#sec-math.expm1

var mathExpm1 = !nativeExpm1 // Old FF bug
|| nativeExpm1(10) > 22025.465794806719 || nativeExpm1(10) < 22025.4657948067165168 // Tor Browser bug
|| nativeExpm1(-2e-17) != -2e-17 ? function expm1(x) {
  return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : exp(x) - 1;
} : nativeExpm1;

var nativeCosh = Math.cosh;
var abs$1 = Math.abs;
var E = Math.E; // `Math.cosh` method
// https://tc39.github.io/ecma262/#sec-math.cosh

_export({
  target: 'Math',
  stat: true,
  forced: !nativeCosh || nativeCosh(710) === Infinity
}, {
  cosh: function cosh(x) {
    var t = mathExpm1(abs$1(x) - 1) + 1;
    return (t + 1 / (t * E * E)) * (E / 2);
  }
});

// https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags


var regexpFlags = function () {
  var that = anObject(this);
  var result = '';
  if (that.global) result += 'g';
  if (that.ignoreCase) result += 'i';
  if (that.multiline) result += 'm';
  if (that.dotAll) result += 's';
  if (that.unicode) result += 'u';
  if (that.sticky) result += 'y';
  return result;
};

// so we use an intermediate function.


function RE(s, f) {
  return RegExp(s, f);
}

var UNSUPPORTED_Y = fails(function () {
  // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError
  var re = RE('a', 'y');
  re.lastIndex = 2;
  return re.exec('abcd') != null;
});
var BROKEN_CARET = fails(function () {
  // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
  var re = RE('^r', 'gy');
  re.lastIndex = 2;
  return re.exec('str') != null;
});
var regexpStickyHelpers = {
  UNSUPPORTED_Y: UNSUPPORTED_Y,
  BROKEN_CARET: BROKEN_CARET
};

var nativeExec = RegExp.prototype.exec; // This always refers to the native implementation, because the
// String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
// which loads this file before patching the method.

var nativeReplace = String.prototype.replace;
var patchedExec = nativeExec;

var UPDATES_LAST_INDEX_WRONG = function () {
  var re1 = /a/;
  var re2 = /b*/g;
  nativeExec.call(re1, 'a');
  nativeExec.call(re2, 'a');
  return re1.lastIndex !== 0 || re2.lastIndex !== 0;
}();

var UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y || regexpStickyHelpers.BROKEN_CARET; // nonparticipating capturing group, copied from es5-shim's String#split patch.

var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$1;

if (PATCH) {
  patchedExec = function exec(str) {
    var re = this;
    var lastIndex, reCopy, match, i;
    var sticky = UNSUPPORTED_Y$1 && re.sticky;
    var flags = regexpFlags.call(re);
    var source = re.source;
    var charsAdded = 0;
    var strCopy = str;

    if (sticky) {
      flags = flags.replace('y', '');

      if (flags.indexOf('g') === -1) {
        flags += 'g';
      }

      strCopy = String(str).slice(re.lastIndex); // Support anchored sticky behavior.

      if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) {
        source = '(?: ' + source + ')';
        strCopy = ' ' + strCopy;
        charsAdded++;
      } // ^(? + rx + ) is needed, in combination with some str slicing, to
      // simulate the 'y' flag.


      reCopy = new RegExp('^(?:' + source + ')', flags);
    }

    if (NPCG_INCLUDED) {
      reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
    }

    if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
    match = nativeExec.call(sticky ? reCopy : re, strCopy);

    if (sticky) {
      if (match) {
        match.input = match.input.slice(charsAdded);
        match[0] = match[0].slice(charsAdded);
        match.index = re.lastIndex;
        re.lastIndex += match[0].length;
      } else re.lastIndex = 0;
    } else if (UPDATES_LAST_INDEX_WRONG && match) {
      re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
    }

    if (NPCG_INCLUDED && match && match.length > 1) {
      // Fix browsers whose `exec` methods don't consistently return `undefined`
      // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
      nativeReplace.call(match[0], reCopy, function () {
        for (i = 1; i < arguments.length - 2; i++) {
          if (arguments[i] === undefined) match[i] = undefined;
        }
      });
    }

    return match;
  };
}

var regexpExec = patchedExec;

_export({
  target: 'RegExp',
  proto: true,
  forced: /./.exec !== regexpExec
}, {
  exec: regexpExec
});

var SPECIES$5 = wellKnownSymbol('species');
var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
  // #replace needs built-in support for named groups.
  // #match works fine because it just return the exec results, even if it has
  // a "grops" property.
  var re = /./;

  re.exec = function () {
    var result = [];
    result.groups = {
      a: '7'
    };
    return result;
  };

  return ''.replace(re, '$<a>') !== '7';
}); // IE <= 11 replaces $0 with the whole match, as if it was $&
// https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0

var REPLACE_KEEPS_$0 = function () {
  return 'a'.replace(/./, '$0') === '$0';
}();

var REPLACE = wellKnownSymbol('replace'); // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string

var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = function () {
  if (/./[REPLACE]) {
    return /./[REPLACE]('a', '$0') === '';
  }

  return false;
}(); // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
// Weex JS has frozen built-in prototypes, so use try / catch wrapper


var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
  var re = /(?:)/;
  var originalExec = re.exec;

  re.exec = function () {
    return originalExec.apply(this, arguments);
  };

  var result = 'ab'.split(re);
  return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
});

var fixRegexpWellKnownSymbolLogic = function (KEY, length, exec, sham) {
  var SYMBOL = wellKnownSymbol(KEY);
  var DELEGATES_TO_SYMBOL = !fails(function () {
    // String methods call symbol-named RegEp methods
    var O = {};

    O[SYMBOL] = function () {
      return 7;
    };

    return ''[KEY](O) != 7;
  });
  var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
    // Symbol-named RegExp methods call .exec
    var execCalled = false;
    var re = /a/;

    if (KEY === 'split') {
      // We can't use real regex here since it causes deoptimization
      // and serious performance degradation in V8
      // https://github.com/zloirock/core-js/issues/306
      re = {}; // RegExp[@@split] doesn't call the regex's exec method, but first creates
      // a new one. We need to return the patched regex when creating the new one.

      re.constructor = {};

      re.constructor[SPECIES$5] = function () {
        return re;
      };

      re.flags = '';
      re[SYMBOL] = /./[SYMBOL];
    }

    re.exec = function () {
      execCalled = true;
      return null;
    };

    re[SYMBOL]('');
    return !execCalled;
  });

  if (!DELEGATES_TO_SYMBOL || !DELEGATES_TO_EXEC || KEY === 'replace' && !(REPLACE_SUPPORTS_NAMED_GROUPS && REPLACE_KEEPS_$0 && !REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE) || KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC) {
    var nativeRegExpMethod = /./[SYMBOL];
    var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
      if (regexp.exec === regexpExec) {
        if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
          // The native String method already delegates to @@method (this
          // polyfilled function), leasing to infinite recursion.
          // We avoid it by directly calling the native @@method method.
          return {
            done: true,
            value: nativeRegExpMethod.call(regexp, str, arg2)
          };
        }

        return {
          done: true,
          value: nativeMethod.call(str, regexp, arg2)
        };
      }

      return {
        done: false
      };
    }, {
      REPLACE_KEEPS_$0: REPLACE_KEEPS_$0,
      REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE: REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
    });
    var stringMethod = methods[0];
    var regexMethod = methods[1];
    redefine(String.prototype, KEY, stringMethod);
    redefine(RegExp.prototype, SYMBOL, length == 2 // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
    // 21.2.5.11 RegExp.prototype[@@split](string, limit)
    ? function (string, arg) {
      return regexMethod.call(string, this, arg);
    } // 21.2.5.6 RegExp.prototype[@@match](string)
    // 21.2.5.9 RegExp.prototype[@@search](string)
    : function (string) {
      return regexMethod.call(string, this);
    });
  }

  if (sham) createNonEnumerableProperty(RegExp.prototype[SYMBOL], 'sham', true);
};

var charAt$1 = stringMultibyte.charAt; // `AdvanceStringIndex` abstract operation
// https://tc39.github.io/ecma262/#sec-advancestringindex

var advanceStringIndex = function (S, index, unicode) {
  return index + (unicode ? charAt$1(S, index).length : 1);
};

// https://tc39.github.io/ecma262/#sec-regexpexec

var regexpExecAbstract = function (R, S) {
  var exec = R.exec;

  if (typeof exec === 'function') {
    var result = exec.call(R, S);

    if (typeof result !== 'object') {
      throw TypeError('RegExp exec method returned something other than an Object or null');
    }

    return result;
  }

  if (classofRaw(R) !== 'RegExp') {
    throw TypeError('RegExp#exec called on incompatible receiver');
  }

  return regexpExec.call(R, S);
};

fixRegexpWellKnownSymbolLogic('match', 1, function (MATCH, nativeMatch, maybeCallNative) {
  return [// `String.prototype.match` method
  // https://tc39.github.io/ecma262/#sec-string.prototype.match
  function match(regexp) {
    var O = requireObjectCoercible(this);
    var matcher = regexp == undefined ? undefined : regexp[MATCH];
    return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
  }, // `RegExp.prototype[@@match]` method
  // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@match
  function (regexp) {
    var res = maybeCallNative(nativeMatch, regexp, this);
    if (res.done) return res.value;
    var rx = anObject(regexp);
    var S = String(this);
    if (!rx.global) return regexpExecAbstract(rx, S);
    var fullUnicode = rx.unicode;
    rx.lastIndex = 0;
    var A = [];
    var n = 0;
    var result;

    while ((result = regexpExecAbstract(rx, S)) !== null) {
      var matchStr = String(result[0]);
      A[n] = matchStr;
      if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
      n++;
    }

    return n === 0 ? null : A;
  }];
});

for (var COLLECTION_NAME$1 in domIterables) {
  var Collection$1 = global_1[COLLECTION_NAME$1];
  var CollectionPrototype$1 = Collection$1 && Collection$1.prototype; // some Chrome versions have non-configurable methods on DOMTokenList

  if (CollectionPrototype$1 && CollectionPrototype$1.forEach !== arrayForEach) try {
    createNonEnumerableProperty(CollectionPrototype$1, 'forEach', arrayForEach);
  } catch (error) {
    CollectionPrototype$1.forEach = arrayForEach;
  }
}

// https://tc39.github.io/ecma262/#sec-dataview-constructor

_export({
  global: true,
  forced: !arrayBufferNative
}, {
  DataView: arrayBuffer.DataView
});

/**
 * @summary DEM サンプラー
 *
 * @desc
 * <p>DEM バイナリーのデータをサンプルするために使用する。<p>
 * <p>インスタンスは [DemBinary#newSampler()]{@link mapray.DemBinary#newSampler} により作成する。<p>
 *
 * @memberof mapray
 * @private
 * @see mapray.DemBinary
 * @see mapray.DemSamplerLinear
 * @see mapray.DemSamplerNearest
 */
var DemSampler =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Area} area  DEM 領域
   * @param {number}      ρ    DEM バイナリの解像度の指数
   * @param {DataView}    body  DEM 配列データの標高データ部分
   */
  function DemSampler(area, ρ, body) {
    _classCallCheck(this, DemSampler);

    var FLT_BYTES = 4;
    var p = Math.pow(2, area.z - 1); // 2^(ze-1)

    var c = 1 << ρ; // 画素数

    this._sx = p / Math.PI * c;
    this._sy = -this._sx;
    this._ox = (p - area.x) * c;
    this._oy = (p - area.y) * c;
    this._body = body;
    this._pitch = FLT_BYTES * (c + 1);
    this._max = c;
  }
  /**
   * @summary 標高値をサンプル
   * @param  {number}  x  X 座標 (単位球メルカトル座標系)
   * @param  {number}  y  Y 座標 (単位球メルカトル座標系)
   * @return {number}     標高値 (メートル)
   * @abstract
   */


  _createClass(DemSampler, [{
    key: "sample",
    value: function sample(x, y) {
      return 0;
    }
  }]);

  return DemSampler;
}();

/**
 * @summary 線形 DEM サンプラー
 * @memberof mapray
 * @private
 * @extends mapray.DemSampler
 */

var DemSamplerLinear =
/*#__PURE__*/
function (_DemSampler) {
  _inherits(DemSamplerLinear, _DemSampler);

  function DemSamplerLinear(area, ρ, body) {
    _classCallCheck(this, DemSamplerLinear);

    return _possibleConstructorReturn(this, _getPrototypeOf(DemSamplerLinear).call(this, area, ρ, body));
  }
  /**
   * @override
   */


  _createClass(DemSamplerLinear, [{
    key: "sample",
    value: function sample(x, y) {
      var u = this._sx * x + this._ox;
      var u0 = Math.floor(u); // 右位置

      var u1 = u0 + 1; // 左位置

      var v = this._sy * y + this._oy;
      var v0 = Math.floor(v); // 上位置

      var v1 = v0 + 1; // 下位置

      var h00 = this._sampleInt(u0, v0); // 左上標高


      var h10 = this._sampleInt(u1, v0); // 右上標高


      var h01 = this._sampleInt(u0, v1); // 左下標高


      var h11 = this._sampleInt(u1, v1); // 右下標高
      // 標高値を補間


      var fu = u - u0; // 水平小数部

      var fv = v - v0; // 垂直小数部

      return (h00 * (1 - fu) + h10 * fu) * (1 - fv) + (h01 * (1 - fu) + h11 * fu) * fv;
    }
  }, {
    key: "_sampleInt",
    value: function _sampleInt(u, v) {
      var FLT_BYTES = 4;
      var cu = GeoMath.clamp(u, 0, this._max);
      var cv = GeoMath.clamp(v, 0, this._max);
      var offset = this._pitch * cv + FLT_BYTES * cu;
      return this._body.getFloat32(offset, true);
    }
  }]);

  return DemSamplerLinear;
}(DemSampler);

/**
 * @summary 最近傍 DEM サンプラー
 * @memberof mapray
 * @private
 * @extends mapray.DemSampler
 */

var DemSamplerNearest =
/*#__PURE__*/
function (_DemSampler) {
  _inherits(DemSamplerNearest, _DemSampler);

  function DemSamplerNearest(area, ρ, body) {
    _classCallCheck(this, DemSamplerNearest);

    return _possibleConstructorReturn(this, _getPrototypeOf(DemSamplerNearest).call(this, area, ρ, body));
  }
  /**
   * @override
   */


  _createClass(DemSamplerNearest, [{
    key: "sample",
    value: function sample(x, y) {
      var FLT_BYTES = 4;
      var u = Math.round(this._sx * x + this._ox);
      var v = Math.round(this._sy * y + this._oy);
      var offset = this._pitch * v + FLT_BYTES * u;
      return this._body.getFloat32(offset, true);
    }
  }]);

  return DemSamplerNearest;
}(DemSampler);

/**
 * @summary 平均標高マップ
 * @memberof mapray
 * @private
 * @see mapray.DemBinary
 * @see mapray.DemBinaryCache
 */
var AvgHeightMaps =
/*#__PURE__*/
function () {
  /**
   * @param {number}   ρ    解像度の指数
   * @param {DataView} body  DEM 配列データの標高データ部分
   */
  function AvgHeightMaps(ρ, body) {
    _classCallCheck(this, AvgHeightMaps);

    this._ρ = ρ;
    this._maps = []; // Level: -1, -2, ..., -ρ

    if (ρ >= 1) {
      // Level: -1
      var first_map = this._create_first_map(body);

      this._maps.push(first_map); // Level: -2 .. -ρ


      var src_map = first_map;

      for (var lv = -2; lv >= -ρ; --lv) {
        var next_map = this._create_next_map(lv, src_map);

        this._maps.push(next_map);

        src_map = next_map;
      }
    }
  }
  /**
   * レベル -1 の平均標高マップを生成
   * @param  {DataView}     src  DEM 配列データの標高データ部分
   * @return {Float32Array}      レベル -1 の平均標高マップ
   * @private
   */


  _createClass(AvgHeightMaps, [{
    key: "_create_first_map",
    value: function _create_first_map(src) {
      var FLT_BYTES = 4;
      var size = 1 << this._ρ - 1;
      var dst = new Float32Array(size * size);
      var src_pitch = (2 * size + 1) * FLT_BYTES;
      var dst_pitch = size;

      for (var j = 0; j < size; ++j) {
        var src_index = 2 * j * src_pitch;
        var dst_index = j * dst_pitch;

        for (var i = 0; i < size; ++i) {
          // 標高データを取り出す
          var h00 = src.getFloat32(src_index, true);
          var h10 = src.getFloat32(src_index + FLT_BYTES, true);
          var h20 = src.getFloat32(src_index + 2 * FLT_BYTES, true);
          var h01 = src.getFloat32(src_index + src_pitch, true);
          var h11 = src.getFloat32(src_index + src_pitch + FLT_BYTES, true);
          var h21 = src.getFloat32(src_index + src_pitch + 2 * FLT_BYTES, true);
          var h02 = src.getFloat32(src_index + 2 * src_pitch, true);
          var h12 = src.getFloat32(src_index + 2 * src_pitch + FLT_BYTES, true);
          var h22 = src.getFloat32(src_index + 2 * (src_pitch + FLT_BYTES), true); // 平均標高を書き込む

          dst[dst_index] = (h00 + 2 * h10 + h20 + 2 * h01 + 4 * h11 + 2 * h21 + h02 + 2 * h12 + h22) / 16;
          src_index += 2 * FLT_BYTES;
          dst_index += 1;
        }
      }

      return dst;
    }
    /**
     * レベル -2 .. -ρ の平均標高マップを生成
     * @param  {number}       lv   生成するマップのレベル
     * @param  {Float32Array} src  元となる平均標高マップ (レベル lv + 1)
     * @return {Float32Array}      レベル lv の平均標高マップ
     * @private
     */

  }, {
    key: "_create_next_map",
    value: function _create_next_map(lv, src) {
      var size = 1 << this._ρ + lv;
      var dst = new Float32Array(size * size);
      var src_pitch = 2 * size;
      var dst_pitch = size;

      for (var j = 0; j < size; ++j) {
        var src_index = 2 * j * src_pitch;
        var dst_index = j * dst_pitch;

        for (var i = 0; i < size; ++i) {
          // 標高データを取り出す
          var h00 = src[src_index];
          var h10 = src[src_index + 1];
          var h01 = src[src_index + src_pitch];
          var h11 = src[src_index + src_pitch + 1]; // 平均標高を書き込む

          dst[dst_index] = (h00 + h10 + h01 + h11) / 4;
          src_index += 2;
          dst_index += 1;
        }
      }

      return dst;
    }
    /**
     * @summary 平均標高を取得
     * @desc
     * <p>地表断片 <zg, xg, yg> の平均標高を取得する。</p>
     * @param  {number} zg  地表断片分割レベル (0 <= zg < ρ)
     * @param  {number} xg  地表断片 X 座標
     * @param  {number} yg  地表断片 Y 座標
     * @return {number}     平均標高
     */

  }, {
    key: "sample",
    value: function sample(zg, xg, yg) {
      var map = this._maps[this._ρ - zg - 1];
      var size = 1 << zg;
      return map[yg * size + xg];
    }
  }]);

  return AvgHeightMaps;
}();

/**
 * @summary DEM バイナリーデータ
 * @memberof mapray
 * @private
 * @see mapray.DemSampler
 */

var DemBinary =
/*#__PURE__*/
function () {
  /**
   * @param {number}      z      ズームレベル
   * @param {number}      x      X タイル座標
   * @param {number}      y      Y タイル座標
   * @param {number}      ρ     解像度の指数
   * @param {ArrayBuffer} array  DEM 配列データ
   */
  function DemBinary(z, x, y, ρ, array) {
    _classCallCheck(this, DemBinary);

    this._z = z;
    this._x = x;
    this._y = y;
    this._ρ = ρ; // ヘッダー情報を取得

    var header = new DataView(array);
    this._qlevels = [header.getUint8(DemBinary.OFFSET_QLEVEL_00), // 四分存在レベル (左上)
    header.getUint8(DemBinary.OFFSET_QLEVEL_10), // 四分存在レベル (右上)
    header.getUint8(DemBinary.OFFSET_QLEVEL_01), // 四分存在レベル (左下)
    header.getUint8(DemBinary.OFFSET_QLEVEL_11) // 四分存在レベル (右下)
    ];
    this._hmin = header.getFloat32(DemBinary.OFFSET_HMIN, true); // 最小標高

    this._hmax = header.getFloat32(DemBinary.OFFSET_HMAX, true); // 最大標高

    this._ω = this._createωArray(header); // 複雑度
    // 標高配列への参照を取得

    this._body = new DataView(array, DemBinary.HEADER_BYTES); // 標高配列の 1 行の標高数

    this._size = (1 << ρ) + 1;
  }
  /**
   * @summary ズームレベル
   * @type {number}
   * @readonly
   */


  _createClass(DemBinary, [{
    key: "isLeaf",

    /**
     * @summary 地表断片に対して葉タイルか?
     * @desc
     * <p>地表断片 [zg, xg, yg] に対して、this はサーバー内で最も詳細な DEM データであるかどうかを返す。</p>
     * <p>制約: [zg, xg, yg] の領域は this と同じまたは包含されていること。</p>
     * @param  {number}   zg  分割レベル
     * @param  {number}   xg  X 座標
     * @param  {number}   yg  Y 座標
     * @return {boolean}      葉タイルのとき true, それ以外は false
     */
    value: function isLeaf(zg, xg, yg) {
      if (zg > this._z) {
        return this.getQuadLevel(zg, xg, yg) == 0;
      } else {
        var q = this._qlevels;
        return q[0] == 0 || q[1] == 0 || q[2] == 0 || q[3] == 0;
      }
    }
    /**
     * @summary 四分存在レベルを取得
     * @desc
     * <p>制約: zg > this.z かつ [zg, xg, yg] の領域は this に包含されていること。</p>
     * @param  {number}   zg  分割レベル
     * @param  {number}   xg  X 座標
     * @param  {number}   yg  Y 座標
     * @return {number}       四分存在レベル
     */

  }, {
    key: "getQuadLevel",
    value: function getQuadLevel(zg, xg, yg) {
      var pow = Math.pow(2, this._z - zg);
      var u = Math.floor(2 * ((xg + 0.5) * pow - this._x));
      var v = Math.floor(2 * ((yg + 0.5) * pow - this._y));
      return this._qlevels[2 * v + u];
    }
    /**
     * @summary 四分存在レベルを取得
     * @desc
     * <p>基底タイル座標 (左上(0, 0)、右下(1, 1)) [xt, yt] を含む領域の四分存在レベルを取得する。</p>
     * <p>制約: [xt, yt] の領域は this に包含されていること。</p>
     * @param  {number} xt  X 座標
     * @param  {number} yt  Y 座標
     * @return {number}     四分存在レベル
     */

  }, {
    key: "getQuadLevelDirect",
    value: function getQuadLevelDirect(xt, yt) {
      var pow = Math.round(Math.pow(2, this._z + 1));
      var u = GeoMath.clamp(Math.floor(xt * pow), 0, pow - 1) % 2;
      var v = GeoMath.clamp(Math.floor(yt * pow), 0, pow - 1) % 2;
      return this._qlevels[2 * v + u];
    }
    /**
     * @summary 標高点正方形の4隅の標高を取得
     * @desc
     * <p>注意: 次の呼び出しで、結果配列は上書きされる。</p>
     * @param  {number} u  水平方向の標高点正方形位置
     * @param  {number} v  垂直方向の標高点正方形位置
     * @return {array}     4隅の標高の配列 [左上, 右上, 左下, 右下]
     */

  }, {
    key: "getHeights",
    value: function getHeights(u, v) {
      var FLT_BYTES = 4;
      var origin = FLT_BYTES * (v * this._size + u);
      var pitch = FLT_BYTES * this._size;
      var h = DemBinary._getHeights_result;
      h[0] = this._body.getFloat32(origin, true);
      h[1] = this._body.getFloat32(origin + FLT_BYTES, true);
      h[2] = this._body.getFloat32(origin + pitch, true);
      h[3] = this._body.getFloat32(origin + pitch + FLT_BYTES, true);
      return h;
    }
    /**
     * @summary 地表断片の分割指数を取得
     * @desc
     * <p>注意: 次の呼び出しで、結果配列は上書きされる。</p>
     *
     * @param  {mapray.Area} flake_area  地表断片の領域
     * @param  {number}      lod         地表詳細レベル (LOD)
     * @param  {number}      cu          水平球面分割レベル
     * @param  {number}      cv          垂直球面分割レベル
     *
     * @return {array}  [水平分割指数, 垂直分割指数]
     */

  }, {
    key: "getDivisionPowers",
    value: function getDivisionPowers(flake_area, lod, cu, cv) {
      var zg = flake_area.z;
      var ze = this._z;
      var b = GeoMath.LOG2PI - this._ρ + 1; // b = log2π - ρ + 1

      var ω = this._getComplexity(zg, flake_area.x, flake_area.y); // {gu, gv} = max( {cu, cv}, min( ze + ρ, round( lod + b + ω ) ) − zg )


      var arg = Math.min(ze + this._ρ, Math.round(lod + b + ω)) - zg;
      var result = DemBinary._getDivisionPowers_result;
      result[0] = Math.max(cu, arg); // 水平分割指数

      result[1] = Math.max(cv, arg); // 垂直分割指数

      return result;
    }
    /**
     * @summary DEM サンプラーを生成
     *
     * @param {mapray.Area} flake_area  地表断片の領域
     *
     * @return {mapray.DemSampler}  DEM サンプラー
     */

  }, {
    key: "newSampler",
    value: function newSampler(flake_area) {
      // 今のところ、地表断片が 1 標高点またはそれ以上のとき、最近傍サンプラーでも結果が
      // 変わらないので、最適化のためにサンプラーを別けている
      var samplerClass = flake_area.z - this._z > this._ρ ? DemSamplerLinear : DemSamplerNearest;
      return new samplerClass(this, this._ρ, this._body);
    }
    /**
     * @summary 線形 DEM サンプラーを生成
     *
     * @return {mapray.DemSamplerLinear}  DEM サンプラー
     */

  }, {
    key: "newLinearSampler",
    value: function newLinearSampler() {
      return new DemSamplerLinear(this, this._ρ, this._body);
    }
    /**
     * @summary 平均標高マップを生成
     * @return {mapray.AvgHeightMaps}  平均標高マップ
     */

  }, {
    key: "newAvgHeightMaps",
    value: function newAvgHeightMaps() {
      return new AvgHeightMaps(this._ρ, this._body);
    }
    /**
     * @private
     */

  }, {
    key: "_create\u03C9Array",
    value: function _createArray(header) {
      var FLT_BYTES = 4;
      var ωs = [];
      var offset = 0;

      for (var down = 0; down < 3; ++down) {
        var count = 1 << 2 * down;
        var array = new Float32Array(count);

        for (var i = 0; i < count; ++i) {
          array[i] = header.getFloat32(DemBinary.OFFSET_ω + offset, true);
          offset += FLT_BYTES;
        }

        ωs.push(array);
      }

      return ωs;
    }
    /**
     * @summary 複雑度を取得
     * @desc
     * <p>this 上の地表断片 (zg, xg, yg) の複雑度 (ω) を取得する。</p>
     * @param  {number}  zg  分割レベル
     * @param  {number}  xg  X 座標
     * @param  {number}  yg  Y 座標
     * @return {number}      複雑度
     * @private
     */

  }, {
    key: "_getComplexity",
    value: function _getComplexity(zg, xg, yg) {
      var d = zg - this._z;
      var p = Math.round(Math.pow(2, d));
      var dmax = 2; // this._ω.length - 1

      var smax = 4; // 2^c

      var u;
      var v;

      if (d <= dmax) {
        u = xg - p * this._x;
        v = yg - p * this._y;
      } else {
        u = Math.floor(smax * ((xg + 0.5) / p - this._x));
        v = Math.floor(smax * ((yg + 0.5) / p - this._y));
      }

      var index = Math.min(d, dmax);
      var array = this._ω[index];
      return Math.min(array[v * (1 << index) + u], DemBinary.ω_limit);
    }
  }, {
    key: "z",
    get: function get() {
      return this._z;
    }
    /**
     * @summary X タイル座標
     * @type {number}
     * @readonly
     */

  }, {
    key: "x",
    get: function get() {
      return this._x;
    }
    /**
     * @summary Y タイル座標
     * @type {number}
     * @readonly
     */

  }, {
    key: "y",
    get: function get() {
      return this._y;
    }
    /**
     * @summary 最小標高
     * @desc
     * <p>このタイルに対応する地表の領域で最も低い点の標高を返す。</p>
     * <p>この値は this の葉タイルのデータに基づいているので、this の個々のサンプル値の最小値よりも小さい値の可能性があることに注意されたい。</p>
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_min",
    get: function get() {
      return this._hmin;
    }
    /**
     * @summary 最大標高
     * <p>このタイルに対応する地表の領域で最も高い点の標高を返す。</p>
     * <p>この値は this の葉タイルのデータに基づいているので、this の個々のサンプル値の最大値よりも大きい値の可能性があることに注意されたい。</p>
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_max",
    get: function get() {
      return this._hmax;
    }
  }]);

  return DemBinary;
}();

DemBinary.OFFSET_QLEVEL_00 = 0;
DemBinary.OFFSET_QLEVEL_10 = 1;
DemBinary.OFFSET_QLEVEL_01 = 2;
DemBinary.OFFSET_QLEVEL_11 = 3;
DemBinary.OFFSET_HMIN = 4;
DemBinary.OFFSET_HMAX = 8;
DemBinary.OFFSET_ω = 12;
DemBinary.HEADER_BYTES = 96;
DemBinary.ω_limit = 6;
DemBinary._getHeights_result = new Array(4);
DemBinary._getDivisionPowers_result = new Array(2);

// https://tc39.github.io/ecma262/#sec-typedarray-objects

typedArrayConstructor('Int16', function (init) {
  return function Int16Array(data, byteOffset, length) {
    return init(this, data, byteOffset, length);
  };
});

// https://tc39.github.io/ecma262/#sec-typedarray-objects

typedArrayConstructor('Int32', function (init) {
  return function Int32Array(data, byteOffset, length) {
    return init(this, data, byteOffset, length);
  };
});

/**
 * @summary 地表領域ユーティリティー
 *
 * @hideconstructor
 * @memberof mapray
 * @private
 */

var AreaUtil =
/*#__PURE__*/
function () {
  function AreaUtil() {
    _classCallCheck(this, AreaUtil);
  }

  _createClass(AreaUtil, null, [{
    key: "getCenter",

    /**
     * @summary 地表領域の中心位置を GOCS で取得
     *
     * @desc
     * <p>領域 area の中心位置 (GOCS) を dst に格納する。</p>
     *
     * @param {mapray.Area}    area  地表領域
     * @param {mapray.Vector3} dst   結果を格納するオブジェクト (GOCS)
     *
     * @return {mapray.Vector3} dst
     */
    value: function getCenter(area, dst) {
      switch (area.z) {
        case 0:
          return getCenter_0(dst);

        case 1:
          return getCenter_1(area.x, area.y, dst);

        default:
          return getCenter_N(area.z, area.x, area.y, dst);
      }
    }
  }]);

  return AreaUtil;
}();
/**
 * @summary 地表の ZXY 領域を表現
 *
 * @desc
 * <p>このクラスは便宜的なものであり実在しない。</p>
 * <p>z, x, y プロパティから地表の領域を表す ZXY 座標を読み出せるオブジェクトは、このクラスのインスタンスと解釈する。</p>
 *
 * @class mapray.Area
 * @private
 *
 * @see mapray.AreaUtil
 */
// AreaUtil.getCenter() の一部


function getCenter_0(dst) {
  dst[0] = 0;
  dst[1] = 0;
  dst[2] = 0;
  return dst;
} // AreaUtil.getCenter() の一部


function getCenter_1(x, y, dst) {
  var r = GeoMath.EARTH_RADIUS;
  dst[0] = 0;
  dst[1] = r * (x - 0.5);
  dst[2] = r * (0.5 - y);
  return dst;
} // AreaUtil.getCenter() の一部


function getCenter_N(z, x, y, dst) {
  var pi = Math.PI; // 座標範囲 (単位球メルカトル座標系)

  var msize = Math.pow(2, 1 - z) * pi;
  var mx_min = -pi + x * msize;
  var mx_max = -pi + (x + 1) * msize;
  var my_min = pi - (y + 1) * msize;
  var my_max = pi - y * msize; // 事前計算変数

  var λmin = mx_min;
  var λmax = mx_max;
  var emin = Math.exp(my_min); // Exp[my_min]

  var emax = Math.exp(my_max); // Exp[my_max]

  var e2min = emin * emin; // Exp[my_min]^2

  var e2max = emax * emax; // Exp[my_max]^2
  // 座標範囲 (地心直交座標系)
  //
  // z >= 2 のとき、λとφの範囲は以下の区間のどれかに入る
  //   φ:                (-π/2, 0] [0, π/2)
  //   λ:   [-π, -π/2] [-π/2, 0] [0, π/2] [π/2, π]
  //
  // 区間ごとの関数の変化 (各区間で単調増加または単調減少)
  //   Sin[φ]:            (-1 → 0] [0 → 1)
  //   Cos[φ]:            ( 0 → 1] [1 → 0)
  //   Sin[λ]: [ 0 → -1] [-1 → 0] [0 → 1] [1 →  0]
  //   Cos[λ]: [-1 →  0] [ 0 → 1] [1 → 0] [0 → -1]

  var rh = GeoMath.EARTH_RADIUS / 2;
  var cosφmin = 2 * emin / (e2min + 1);
  var cosφmax = 2 * emax / (e2max + 1); // gx = r Cos[φ] Cos[λ]
  // gy = r Cos[φ] Sin[λ]

  if (my_min + my_max < 0) {
    //     φ : (-π/2, 0]
    // Cos[φ]: ( 0 →  1]
    if (λmin + λmax < -pi) {
      //     λ : [-π, -π/2]
      // Cos[λ]: [-1  →   0]
      // Sin[λ]: [ 0  →  -1]
      dst[0] = rh * (cosφmax * Math.cos(λmin) + cosφmin * Math.cos(λmax));
      dst[1] = rh * (cosφmax * Math.sin(λmax) + cosφmin * Math.sin(λmin));
    } else if (λmin + λmax < 0) {
      //     λ : [-π/2, 0]
      // Cos[λ]: [ 0  → 1]
      // Sin[λ]: [-1  → 0]
      dst[0] = rh * (cosφmin * Math.cos(λmin) + cosφmax * Math.cos(λmax));
      dst[1] = rh * (cosφmax * Math.sin(λmin) + cosφmin * Math.sin(λmax));
    } else if (λmin + λmax < pi) {
      //     λ : [0, π/2]
      // Cos[λ]: [1  → 0]
      // Sin[λ]: [0  → 1]
      dst[0] = rh * (cosφmin * Math.cos(λmax) + cosφmax * Math.cos(λmin));
      dst[1] = rh * (cosφmin * Math.sin(λmin) + cosφmax * Math.sin(λmax));
    } else {
      //     λ : [π/2, π]
      // Cos[λ]: [0  → -1]
      // Sin[λ]: [1  →  0]
      dst[0] = rh * (cosφmax * Math.cos(λmax) + cosφmin * Math.cos(λmin));
      dst[1] = rh * (cosφmin * Math.sin(λmax) + cosφmax * Math.sin(λmin));
    }
  } else {
    //     φ : [0, π/2)
    // Cos[φ]: [1  → 0)
    if (λmin + λmax < -pi) {
      //     λ : [-π, -π/2]
      // Cos[λ]: [-1  →   0]
      // Sin[λ]: [ 0  →  -1]
      dst[0] = rh * (cosφmin * Math.cos(λmin) + cosφmax * Math.cos(λmax));
      dst[1] = rh * (cosφmin * Math.sin(λmax) + cosφmax * Math.sin(λmin));
    } else if (λmin + λmax < 0) {
      //     λ : [-π/2, 0]
      // Cos[λ]: [ 0  → 1]
      // Sin[λ]: [-1  → 0]
      dst[0] = rh * (cosφmax * Math.cos(λmin) + cosφmin * Math.cos(λmax));
      dst[1] = rh * (cosφmin * Math.sin(λmin) + cosφmax * Math.sin(λmax));
    } else if (λmin + λmax < pi) {
      //     λ : [0, π/2]
      // Cos[λ]: [1  → 0]
      // Sin[λ]: [0  → 1]
      dst[0] = rh * (cosφmax * Math.cos(λmax) + cosφmin * Math.cos(λmin));
      dst[1] = rh * (cosφmax * Math.sin(λmin) + cosφmin * Math.sin(λmax));
    } else {
      //     λ : [π/2, π]
      // Cos[λ]: [0  → -1]
      // Sin[λ]: [1  →  0]
      dst[0] = rh * (cosφmin * Math.cos(λmax) + cosφmax * Math.cos(λmin));
      dst[1] = rh * (cosφmax * Math.sin(λmax) + cosφmin * Math.sin(λmin));
    }
  } // rh * (Sin[φmin] + Sin[φmax])


  dst[2] = rh * 2 * (e2max / (e2max + 1) - 1 / (e2min + 1));
  return dst;
}

/**
 * @summary 地表断片メッシュ
 * @memberof mapray
 * @private
 */

var FlakeMesh =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv}     glenv  WebGL 環境
   * @param {mapray.Area}      area   地表断片の領域
   * @param {number[]}         dpows  地表断片の分割指数
   * @param {mapray.DemBinary} dem    DEM バイナリ
   */
  function FlakeMesh(glenv, area, dpows, dem) {
    _classCallCheck(this, FlakeMesh);

    var gl = glenv.context; // オブジェクト座標系の中心位置 (GOCS)

    this._center = this._createCenter(area); // 頂点バッファ

    this._vertices = null; // 頂点数

    this._num_vertices = 0; // 頂点属性辞書

    this._vertex_attribs = {}; // XY グリッドサイズ

    this._num_quads_x = 0;
    this._num_quads_y = 0; // 頂点データを生成

    this._createVertices(gl, area, dpows, dem); // 頂点属性辞書を設定


    this._setupVertexAttribs(gl); // インデックス型


    this._index_type = this._num_vertices < 65536 ? gl.UNSIGNED_SHORT : gl.UNSIGNED_INT; // インデックス (GL_TRIANGLES)

    this._indices = null;
    this._num_indices = 0; // インデックス (GL_LINES)

    this._wire_indices = null;
    this._num_wire_indices = 0;
    this._gl = gl;
  }
  /**
   * @summary 中心位置を生成
   *
   * @param {mapray.Area} area  地表断片の領域
   *
   * @return {mapray.Vector3}  中心位置 (GOCS)
   *
   * @private
   */


  _createClass(FlakeMesh, [{
    key: "_createCenter",
    value: function _createCenter(area) {
      return AreaUtil.getCenter(area, GeoMath.createVector3());
    }
  }, {
    key: "_createVertices",
    value: function _createVertices(gl, area, dpows, dem) {
      var target = gl.ARRAY_BUFFER;
      var vbo = gl.createBuffer();

      var data = this._createVerticesData(area, dpows, dem);

      gl.bindBuffer(target, vbo);
      gl.bufferData(target, data.array, gl.STATIC_DRAW);
      gl.bindBuffer(target, null);
      this._vertices = vbo;
      this._num_vertices = data.num_vertices;
      this._num_quads_x = data.num_quads_x;
      this._num_quads_y = data.num_quads_y;
    }
  }, {
    key: "_createVerticesData",
    value: function _createVerticesData(area, dpows, dem) {
      // 開始位置 (単位球メルカトル座標系)
      var msize = Math.pow(2, 1 - area.z) * Math.PI;
      var mx_min = area.x * msize - Math.PI;
      var my_min = Math.PI - (area.y + 1) * msize; // 分割数

      var u_count = 1 << dpows[0];
      var v_count = 1 << dpows[1]; // 刻み幅

      var u_step = 1 / u_count;
      var v_step = 1 / v_count;
      var mx_step = msize / u_count;
      var my_step = msize / v_count;
      var center = this._center;
      var demSampler = dem.newSampler(area);
      var num_vertices = (u_count + 1) * (v_count + 1);
      var array = new Float32Array(FlakeMesh.VERTEX_SIZE * num_vertices);
      var index = 0;

      for (var iv = 0, my = my_min; iv < v_count + 1; ++iv, my += my_step) {
        var ey = Math.exp(my);
        var ey2 = ey * ey;
        var sinφ = (ey2 - 1) / (ey2 + 1);
        var cosφ = 2 * ey / (ey2 + 1);

        for (var iu = 0, mx = mx_min; iu < u_count + 1; ++iu, mx += mx_step) {
          var sinλ = Math.sin(mx);
          var cosλ = Math.cos(mx);
          var height = demSampler.sample(mx, my);
          var radius = GeoMath.EARTH_RADIUS + height; // 法線 (GOCS)

          var nx = cosφ * cosλ;
          var ny = cosφ * sinλ;
          var nz = sinφ; // 位置 (GOCS)

          var gx = radius * nx;
          var gy = radius * ny;
          var gz = radius * nz;
          array[index++] = gx - center[0]; // x

          array[index++] = gy - center[1]; // y

          array[index++] = gz - center[2]; // z

          array[index++] = nx; // nx

          array[index++] = ny; // ny

          array[index++] = nz; // nz

          array[index++] = iu * u_step; // mu

          array[index++] = iv * v_step; // mv
        }
      }

      return {
        array: array,
        num_vertices: num_vertices,
        num_quads_x: u_count,
        num_quads_y: v_count
      };
    }
    /**
     * @summary 頂点属性の辞書を設定
     * @desc
     * <p>this._vertex_attribs に Mesh.AttribData の辞書を設定する。</p>
     *
     * @param {WebGLRenderingContext} gl
     * @private
     */

  }, {
    key: "_setupVertexAttribs",
    value: function _setupVertexAttribs(gl) {
      var type = gl.FLOAT;
      var stride = FlakeMesh.VERTEX_BYTES; // Mesh.AttribData の辞書

      this._vertex_attribs = {
        "a_position": {
          buffer: this._vertices,
          num_components: 3,
          component_type: type,
          normalized: false,
          byte_stride: stride,
          byte_offset: FlakeMesh.OFFSET_P
        },
        "a_normal": {
          buffer: this._vertices,
          num_components: 3,
          component_type: type,
          normalized: false,
          byte_stride: stride,
          byte_offset: FlakeMesh.OFFSET_N
        },
        "a_uv": {
          buffer: this._vertices,
          num_components: 2,
          component_type: type,
          normalized: false,
          byte_stride: stride,
          byte_offset: FlakeMesh.OFFSET_UV
        }
      };
    }
  }, {
    key: "_createIndices",
    value: function _createIndices() {
      var gl = this._gl;
      var num_quads = this._num_quads_x * this._num_quads_y;
      var num_indices = 6 * num_quads;
      var typedArray = this._index_type === gl.UNSIGNED_INT ? Int32Array : Int16Array;
      var array = new typedArray(num_indices);
      var index = 0;

      for (var y = 0; y < this._num_quads_y; ++y) {
        for (var x = 0; x < this._num_quads_x; ++x) {
          var i00 = (this._num_quads_x + 1) * y + x; // 左下頂点

          var i10 = i00 + 1; // 右下頂点

          var i01 = i00 + this._num_quads_x + 1; // 左上頂点

          var i11 = i01 + 1; // 右上頂点
          // 左下三角形

          array[index++] = i00;
          array[index++] = i10;
          array[index++] = i01; // 右上三角形

          array[index++] = i01;
          array[index++] = i10;
          array[index++] = i11;
        }
      }

      var target = gl.ELEMENT_ARRAY_BUFFER;
      var vbo = gl.createBuffer();
      gl.bindBuffer(target, vbo);
      gl.bufferData(target, array, gl.STATIC_DRAW);
      gl.bindBuffer(target, null);
      this._indices = vbo;
      this._num_indices = num_indices;
    }
  }, {
    key: "_createWireIndices",
    value: function _createWireIndices() {
      var gl = this._gl;
      var typedArray = this._index_type === gl.UNSIGNED_INT ? Int32Array : Int16Array;
      var num_indices = 2 * (2 * this._num_quads_x * this._num_quads_y + this._num_quads_x + this._num_quads_y);
      var array = new typedArray(num_indices);
      var index = 0; // 水平線

      for (var y = 0; y < this._num_quads_y + 1; ++y) {
        for (var x = 0; x < this._num_quads_x; ++x) {
          var i00 = (this._num_quads_x + 1) * y + x; // 左下頂点

          var i10 = i00 + 1; // 右下頂点
          // 下水平線

          array[index++] = i00;
          array[index++] = i10;
        }
      } // 垂直線


      for (x = 0; x < this._num_quads_x + 1; ++x) {
        for (y = 0; y < this._num_quads_y; ++y) {
          var j00 = (this._num_quads_x + 1) * y + x; // 左下頂点

          var j01 = j00 + this._num_quads_x + 1; // 左上頂点
          // 左垂直線

          array[index++] = j00;
          array[index++] = j01;
        }
      }

      var target = gl.ELEMENT_ARRAY_BUFFER;
      var vbo = gl.createBuffer();
      gl.bindBuffer(target, vbo);
      gl.bufferData(target, array, gl.STATIC_DRAW);
      gl.bindBuffer(target, null);
      this._wire_indices = vbo;
      this._num_wire_indices = num_indices;
    }
    /**
     *  @summary 頂点数
     *  @type {number}
     *  @readonly
     */

  }, {
    key: "dispose",

    /**
     * @summary リソースを破棄
     */
    value: function dispose() {
      var gl = this._gl;
      this._vertex_attribs = {};
      gl.deleteBuffer(this._vertices);
      this._vertices = null;

      if (this._indices) {
        gl.deleteBuffer(this._indices);
        this._indices = null;
      }

      if (this._wire_indices) {
        gl.deleteBuffer(this._wire_indices);
        this._wire_indices = null;
      }
    }
    /**
     * @summary 変換行列を計算
     * @desc
     * mat に地表断片座標系から GOCS への変換行列を掛ける。
     * @param  {mapray.Matrix} mat  行列
     * @param  {mapray.Matrix} dst  結果
     * @return {mapray.Matrix}      dst
     */

  }, {
    key: "mul_flake_to_gocs",
    value: function mul_flake_to_gocs(mat, dst) {
      var m00 = mat[0],
          m01 = mat[4],
          m02 = mat[8],
          m03 = mat[12],
          m10 = mat[1],
          m11 = mat[5],
          m12 = mat[9],
          m13 = mat[13],
          m20 = mat[2],
          m21 = mat[6],
          m22 = mat[10],
          m23 = mat[14],
          m30 = mat[3],
          m31 = mat[7],
          m32 = mat[11],
          m33 = mat[15];
      var t03 = this._center[0],
          t13 = this._center[1],
          t23 = this._center[2];
      dst[0] = m00;
      dst[1] = m10;
      dst[2] = m20;
      dst[3] = m30;
      dst[4] = m01;
      dst[5] = m11;
      dst[6] = m21;
      dst[7] = m31;
      dst[8] = m02;
      dst[9] = m12;
      dst[10] = m22;
      dst[11] = m32;
      dst[12] = m00 * t03 + m01 * t13 + m02 * t23 + m03;
      dst[13] = m10 * t03 + m11 * t13 + m12 * t23 + m13;
      dst[14] = m20 * t03 + m21 * t13 + m22 * t23 + m23;
      dst[15] = m30 * t03 + m31 * t13 + m32 * t23 + m33;
      return dst;
    }
    /**
     * @summary メッシュを描画
     * @desc
     * <p>事前に material.bindProgram() すること。</p>
     * @param  {mapray.RenderStage.FlakeMaterial} material  マテリアル
     */

  }, {
    key: "draw",
    value: function draw(material) {
      var gl = this._gl;
      var isWire = material.isWireframe(); // 頂点属性のバインド

      material.bindVertexAttribs(this._vertex_attribs); // インデックスのバインド

      var indices = isWire ? this.wire_indices : this.indices;
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices); // 描画処理

      var mode = isWire ? gl.LINES : gl.TRIANGLES;
      var num_indices = isWire ? this.num_wire_indices : this.num_indices;
      gl.drawElements(mode, num_indices, this._index_type, 0);
    }
  }, {
    key: "num_vertices",
    get: function get() {
      return this._num_vertices;
    }
    /**
     *  @summary インデックス (GL_TRIANGLES)
     *  @type {WebGLBuffer}
     *  @readonly
     */

  }, {
    key: "indices",
    get: function get() {
      if (this._indices === null) {
        this._createIndices();
      }

      return this._indices;
    }
    /**
     *  @summary インデックス数 (GL_TRIANGLES)
     *  @type {number}
     *  @readonly
     */

  }, {
    key: "num_indices",
    get: function get() {
      if (this._indices === null) {
        this._createIndices();
      }

      return this._num_indices;
    }
    /**
     *  @summary インデックス (GL_LINES)
     *  @type {WebGLBuffer}
     *  @readonly
     */

  }, {
    key: "wire_indices",
    get: function get() {
      if (this._wire_indices === null) {
        this._createWireIndices();
      }

      return this._wire_indices;
    }
    /**
     *  @summary インデックス数 (GL_LINES)
     *  @type {number}
     *  @readonly
     */

  }, {
    key: "num_wire_indices",
    get: function get() {
      if (this._wire_indices === null) {
        this._createWireIndices();
      }

      return this._num_wire_indices;
    }
  }]);

  return FlakeMesh;
}(); // クラス定数の定義


{
  FlakeMesh.VERTEX_SIZE = 8; // 1頂点の float 数

  /**
   * @summary 1頂点のバイト数
   * @member mapray.FlakeMesh.VERTEX_BYTES
   * @type {number}
   * @static
   * @constant
   */

  FlakeMesh.VERTEX_BYTES = 4 * FlakeMesh.VERTEX_SIZE;
  /**
   * @summary 位置座標のオフセット
   * @member mapray.FlakeMesh.OFFSET_P
   * @type {number}
   * @static
   * @constant
   */

  FlakeMesh.OFFSET_P = 0;
  /**
   * @summary 法線座標のオフセット
   * @member mapray.FlakeMesh.OFFSET_N
   * @type {number}
   * @static
   * @constant
   */

  FlakeMesh.OFFSET_N = 12;
  /**
   * @summary UV 座標のオフセット
   * @member mapray.FlakeMesh.OFFSET_UV
   * @type {number}
   * @static
   * @constant
   */

  FlakeMesh.OFFSET_UV = 24;
}

/**
 * @summary 描画プリミティブ
 * @memberof mapray
 * @private
 * @see mapray.PropSet
 * @see mapray.Entity#getPrimitives
 */

var Primitive =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv}          glenv      WebGL 環境
   * @param {mapray.Mesh}           mesh       メッシュ
   * @param {mapray.EntityMaterial} material   マテリアル
   * @param {mapray.Matrix}         transform  変換行列
   */
  function Primitive(glenv, mesh, material, transform) {
    _classCallCheck(this, Primitive);

    this._glenv = glenv;
    /**
     * @summary 描画されるメッシュ
     * @desc
     * <p>構築子の mesh 引数が設定されている。</p>
     * @member mapray.Primitive#mesh
     * @type {mapray.Mesh}
     */

    this.mesh = mesh;
    /**
     * @summary 描画に使用するマテリアル
     * @desc
     * <p>構築子の material 引数が設定されている。</p>
     * @member mapray.Primitive#material
     * @type {mapray.EntityMaterial}
     */

    this.material = material;
    /**
     * @summary モデル座標系から GOCS への変換行列
     * @desc
     * <p>構築子の transform 引数が設定されている。</p>
     * @member mapray.Primitive#transform
     * @type {mapray.Matrix}
     */

    this.transform = transform;
    /**
     * @summary 中心点 (モデル座標系)
     * @desc
     * <p>null のときは零ベクトルと見なす。</p>
     * @member mapray.Primitive#pivot
     * @type {?mapray.Vector3}
     * @default null
     */

    this.pivot = null;
    /**
     * @summary 境界箱 (モデル座標系)
     * @desc
     * <p>bbox[0] は座標の最小値、bbox[1] は座標の最大値とする。</p>
     * <p>null のときは無限大の境界箱と見なす。</p>
     * @member mapray.Primitive#bbox
     * @type {?Array.<mapray.Vector3>}
     * @default null
     */

    this.bbox = null;
    /**
     * @summary プロパティ集合
     * @desc
     * <p>null のときは空集合と見なす。</p>
     * @member mapray.Primitive#properties
     * @type {?mapray.PropSet}
     * @default null
     */

    this.properties = null;
    /**
     * @summary ソート深度
     * @member mapray.Primitive#sort_z
     * @type {number}
     * @readonly
     * @package
     */

    this.sort_z = undefined;
  }
  /**
   * @summary インスタンスの複製を返す
   *
   * @desc
   * <p>公開プロパティが this と同じインスタンスを生成して返す。</p>
   * <p>ただしプロパティ mesh, material, properties は参照コピーで、それ以外は深いコピーとなる。</p>
   *
   * @return {mapray.Primitive}  インスタンスの複製
   */


  _createClass(Primitive, [{
    key: "fastClone",
    value: function fastClone() {
      var clone = new Primitive(this._glenv, this.mesh, this.material, GeoMath.createMatrix(this.transform));

      if (this.pivot) {
        clone.pivot = GeoMath.createVector3(this.pivot);
      }

      if (this.bbox) {
        clone.bbox = this.bbox.map(function (v) {
          return GeoMath.createVector3(v);
        });
      }

      clone.properties = this.properties;
      return clone;
    }
    /**
     * @summary プリミティブが見えるか?
     * @desc
     * <p>true を返したときはソート深度 this.sort_z が設定される。</p>
     * @param  {mapray.RenderStage} stage  レンダリングステージ
     * @return {boolean}                   プリミティブの一部が視体積に含まれるとき true, それ以外のとき false
     * @package
     */

  }, {
    key: "isVisible",
    value: function isVisible(stage) {
      // obj_to_view = stage._gocs_to_view * this.transform
      var matrix = Primitive._obj_to_view;
      GeoMath.mul_AA(stage._gocs_to_view, this.transform, matrix);
      var bbox = this.bbox;

      if (bbox) {
        // 境界箱の頂点座標を変換 (視点空間) -> bbox_points
        Primitive._transformBBox(bbox, matrix); // 視体積平面と比較


        var planes = stage._volume_planes;

        for (var i = 0; i < planes.length; ++i) {
          if (Primitive._isBBoxBackSide(planes[i])) {
            // 完全に視体積に含まれない
            return false;
          }
        }
      } // ソート深度を設定


      var pivot = this.pivot;

      if (pivot) {
        this.sort_z = matrix[2] * pivot[0] + matrix[6] * pivot[1] + matrix[10] * pivot[2] + matrix[14];
      } else {
        this.sort_z = matrix[14];
      }

      return true;
    }
    /**
     * @summary 背景との混合が必要か?
     * @param  {mapray.RenderStage} stage  レンダリングステージ
     * @return {boolean}                   背景との混合が必要なとき true, それ以外のとき false
     * @package
     */

  }, {
    key: "isTranslucent",
    value: function isTranslucent(stage) {
      return this.material.isTranslucent(stage, this);
    }
    /**
     * @summary プリミティブを描画
     * @param {mapray.RenderStage} stage  レンダリングステージ
     */

  }, {
    key: "draw",
    value: function draw(stage) {
      var material = this.material;
      material.bindProgram();
      material.setParameters(stage, this);
      this.mesh.draw(material);
    }
    /**
     * 境界箱の頂点座標を変換 (視点空間) -> bbox_points
     * @private
     */

  }], [{
    key: "_transformBBox",
    value: function _transformBBox(bbox, matrix) {
      for (var iz = 0; iz < 2; ++iz) {
        var zm = bbox[iz][2];

        for (var iy = 0; iy < 2; ++iy) {
          var ym = bbox[iy][1];

          for (var ix = 0; ix < 2; ++ix) {
            var xm = bbox[ix][0];
            var bbox_point = Primitive._bbox_points[ix + 2 * iy + 4 * iz];
            bbox_point[0] = matrix[0] * xm + matrix[4] * ym + matrix[8] * zm + matrix[12];
            bbox_point[1] = matrix[1] * xm + matrix[5] * ym + matrix[9] * zm + matrix[13];
            bbox_point[2] = matrix[2] * xm + matrix[6] * ym + matrix[10] * zm + matrix[14];
          }
        }
      }
    }
    /**
     * bbox_points はすべて plane の裏側か?
     * @private
     */

  }, {
    key: "_isBBoxBackSide",
    value: function _isBBoxBackSide(plane) {
      var bbox_points = Primitive._bbox_points;

      for (var i = 0; i < bbox_points.length; ++i) {
        var point = bbox_points[i];
        var dist = point[0] * plane[0] + point[1] * plane[1] + point[2] * plane[2] + plane[3];

        if (dist >= 0) {
          // 表側に頂点が存在
          return false;
        }
      }

      return true; // すべての頂点が裏側
    }
  }]);

  return Primitive;
}(); // クラス定数の定義


{
  // 一時領域
  Primitive._obj_to_view = GeoMath.createMatrix(); // モデル空間から視点空間への変換行列

  Primitive._bbox_points = []; // 境界箱の頂点座標 (視点空間)

  for (var i = 0; i < 8; ++i) {
    Primitive._bbox_points.push(GeoMath.createVector3());
  }
}

/**
 * @summary 地表断片レンダリングためのオブジェクト
 *
 * @memberof mapray
 * @private
 */

var FlakeRenderObject =
/*#__PURE__*/
function () {
  /**
   * @param {mapary.Area}      area       地表断片の領域
   * @param {mapary.GLEnv}     glenv      WebGL 環境
   * @param {mapray.FlakeMesh} base_mesh  地表断片の基本メッシュ
   */
  function FlakeRenderObject(area, glenv, base_mesh) {
    _classCallCheck(this, FlakeRenderObject);

    /**
     * @summary 地表分割レベル
     * @member mapray.FlakeRenderObject#z
     * @type {number}
     */
    this.z = area.z;
    /**
     * @summary 地表タイル X 座標
     * @member mapray.FlakeRenderObject#x
     * @type {number}
     */

    this.x = area.x;
    /**
     * @summary 地表タイル Y 座標
     * @member mapray.FlakeRenderObject#y
     * @type {number}
     */

    this.y = area.y;
    this._glenv = glenv;
    this._base_mesh = base_mesh;
    this._edata_list = []; //  { mesh: Mesh, producer: FlakePrimitiveProducer }

    this._transform = null;
  }
  /**
   * @summary エンティティ・データを追加
   *
   * @param {mapray.Mesh} mesh
   * @param {mapray.Entity.FlakePrimitiveProducer} producer
   */


  _createClass(FlakeRenderObject, [{
    key: "addEntityData",
    value: function addEntityData(mesh, producer) {
      var edata = {
        mesh: mesh,
        producer: producer
      };

      this._edata_list.push(edata);
    }
    /**
     * @summary 地表断片上のエンティティ数
     *
     * @type {number}
     * @readonly
     */

  }, {
    key: "getBaseMesh",

    /**
     * @summary 地表断片の基本メッシュを取得
     *
     * @return {mapray.FlakeMesh}
     */
    value: function getBaseMesh() {
      return this._base_mesh;
    }
    /**
     * @summary エンティティのプリミティブを取得
     *
     * @param {number}             index  エンティティのインデックス
     * @param {mapray.RenderStage} stage  レンダリングステージ
     *
     * @return {mapray.Primitive}
     */

  }, {
    key: "getEntityPrimitive",
    value: function getEntityPrimitive(index, stage) {
      var edata = this._edata_list[index];

      var _edata$producer$getMa = edata.producer.getMaterialAndProperties(stage),
          material = _edata$producer$getMa.material,
          properties = _edata$producer$getMa.properties; // this._transform を設定


      if (this._transform === null) {
        this._transform = GeoMath.setIdentity(GeoMath.createMatrix());
        var pos = AreaUtil.getCenter(this, GeoMath.createVector3());
        this._transform[12] = pos[0];
        this._transform[13] = pos[1];
        this._transform[14] = pos[2];
      }

      var primitive = new Primitive(this._glenv, edata.mesh, material, this._transform);
      primitive.properties = properties;
      return primitive;
    }
  }, {
    key: "num_entities",
    get: function get() {
      return this._edata_list.length;
    }
  }]);

  return FlakeRenderObject;
}();

// https://tc39.github.io/ecma262/#sec-array.prototype.fill

_export({
  target: 'Array',
  proto: true
}, {
  fill: arrayFill
}); // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables

addToUnscopables('fill');

// https://tc39.github.io/ecma262/#sec-typedarray-objects

typedArrayConstructor('Uint8', function (init) {
  return function Uint8Array(data, byteOffset, length) {
    return init(this, data, byteOffset, length);
  };
});

/**
 * @summary 更新されたタイル領域
 *
 * @memberof mapray
 * @private
 */
var UpdatedTileArea =
/*#__PURE__*/
function () {
  /**
   */
  function UpdatedTileArea() {
    _classCallCheck(this, UpdatedTileArea);

    this._area_list = [];
    this._flat_area_list = null;
  }
  /**
   * @summary 更新された領域は空か?
   *
   * @return {boolean}  更新領域が存在するとき false, それ以外のとき true
   */


  _createClass(UpdatedTileArea, [{
    key: "isEmpty",
    value: function isEmpty() {
      return this._area_list.length == 0;
    }
    /**
     * @summary 更新領域を空にする
     */

  }, {
    key: "clear",
    value: function clear() {
      this._area_list.length = 0;
      this._flat_area_list = null;
    }
    /**
     * @summary 更新領域を追加
     *
     * @param {object} area    領域
     * @param {number} area.z  レベル
     * @param {number} area.x  X タイル座標
     * @param {number} area.y  Y タイル座標
     */

  }, {
    key: "addTileArea",
    value: function addTileArea(area) {
      this._area_list.push({
        z: area.z,
        x: area.x,
        y: area.y
      });

      this._flat_area_list = null;
    }
    /**
     * @summary フラット領域配列を取得
     *
     * @desc
     * <p>フラット領域配列の各領域は、同じ配列内に祖先領域を含まない。</p>
     * <p>各領域は子領域の索引の配列として表す。</p>
     *
     * @return {Uint8Array[]}
     */

  }, {
    key: "getFlatAreaList",
    value: function getFlatAreaList() {
      if (this._flat_area_list === null) {
        this._flat_area_list = this._createFlatAreaList();
      }

      return this._flat_area_list;
    }
    /**
     * @summary フラット領域配列を生成
     *
     * @return {Uint8Array[]}
     *
     * @private
     */

  }, {
    key: "_createFlatAreaList",
    value: function _createFlatAreaList() {
      var root_node = new Node();

      for (var i = 0; i < this._area_list.length; ++i) {
        var area = this._area_list[i];
        root_node.addDescendant(area.z, area.x, area.y);
      }

      root_node.reduceTree();
      return root_node.collectFlatAreas(0, new Uint8Array(64), []);
    }
  }]);

  return UpdatedTileArea;
}();
/**
 * @summary UpdatedTileArea のノード
 *
 * @memberof mapray.UpdatedTileArea
 * @private
 */


var Node =
/*#__PURE__*/
function () {
  /**
   */
  function Node() {
    _classCallCheck(this, Node);

    this.present = false;
    this.children = new Array(4).fill(null);
  }
  /**
   * @summary 子孫ノード (自身可) を追加
   *
   * @param {number} z
   * @param {number} x
   * @param {number} y
   */


  _createClass(Node, [{
    key: "addDescendant",
    value: function addDescendant(z, x, y) {
      if (this.present === true) {
        // this はすでに決定しているので子孫は追加しない
        return;
      }

      if (z == 0) {
        this.present = true;
        this.children.fill(null); // すでに存在する子孫を取り消す
      } else {
        // z >= 1
        var p = Math.round(Math.pow(2, z - 1)); // 2^(z - 1)

        var u = Math.floor(x / p);
        var v = Math.floor(y / p);
        var i = u + 2 * v;

        if (this.children[i] === null) {
          this.children[i] = new Node();
        }

        this.children[i].addDescendant(z - 1, x % p, y % p);
      }
    }
    /**
     * @summary ツリーを最適化
     *
     * @return {number}  this が末端なら 1, それ以外なら 0
     */

  }, {
    key: "reduceTree",
    value: function reduceTree() {
      if (this.present === true) {
        return 1;
      } // 末端の子供の数


      var count = 0;

      for (var i = 0; i < 4; ++i) {
        var child = this.children[i];

        if (child !== null) {
          count += child.reduceTree();
        }
      }

      if (count == 4) {
        // すべての子供が存在し、それらがすべて末端なら this を末端化
        this.present = true;
        this.children.fill(null);
        return 1;
      } else {
        // this を末端化しない
        return 0;
      }
    }
    /**
     * @summary 末端ノードを収集
     *
     * @param  {number}       z        レベル
     * @param  {Uint8Array}   indices  領域を表す索引配列
     * @param  {Uint8Array[]} olist    収集結果を格納する配列
     * @return {Uint8Array[]}          olist
     */

  }, {
    key: "collectFlatAreas",
    value: function collectFlatAreas(z, indices, olist) {
      if (this.present === true) {
        olist.push(new Uint8Array(indices.slice(0, z)));
      } else {
        for (var i = 0; i < 4; ++i) {
          var child = this.children[i];

          if (child !== null) {
            indices[z] = i;
            child.collectFlatAreas(z + 1, indices, olist);
          }
        }
      }

      return olist;
    }
  }]);

  return Node;
}();

// https://tc39.github.io/ecma262/#sec-array.isarray

_export({
  target: 'Array',
  stat: true
}, {
  isArray: isArray
});

var ARRAY_BUFFER$1 = 'ArrayBuffer';
var ArrayBuffer$3 = arrayBuffer[ARRAY_BUFFER$1];
var NativeArrayBuffer$1 = global_1[ARRAY_BUFFER$1]; // `ArrayBuffer` constructor
// https://tc39.github.io/ecma262/#sec-arraybuffer-constructor

_export({
  global: true,
  forced: NativeArrayBuffer$1 !== ArrayBuffer$3
}, {
  ArrayBuffer: ArrayBuffer$3
});
setSpecies(ARRAY_BUFFER$1);

// https://tc39.github.io/ecma262/#sec-typedarray-objects

typedArrayConstructor('Uint16', function (init) {
  return function Uint16Array(data, byteOffset, length) {
    return init(this, data, byteOffset, length);
  };
});

// https://tc39.github.io/ecma262/#sec-typedarray-objects

typedArrayConstructor('Uint32', function (init) {
  return function Uint32Array(data, byteOffset, length) {
    return init(this, data, byteOffset, length);
  };
});

/**
 * @summary メッシュ用のバッファ
 * @memberof mapray
 * @package
 */
var MeshBuffer =
/*#__PURE__*/
function () {
  /**
   * <p>注意: ARRAY_BUFFER へのバインドは null に設定される。</p>
   *
   * @param {mapray.GLEnv}                glenv
   * @param {ArrayBuffer|ArrayBufferView} src    元データ
   * @param {object}                      [options]                          オプション
   * @param {mapray.MeshBuffer.Target}    [options.target=Target.ATTRIBUTE]  使用目的
   */
  function MeshBuffer(glenv, src, options) {
    _classCallCheck(this, MeshBuffer);

    this._glenv = glenv;
    var opts = options || {}; // VBO を生成

    var gl = glenv.context;

    var target = MeshBuffer._getBindingPoint(gl, opts.target);

    var vbo = gl.createBuffer();
    gl.bindBuffer(target, vbo);
    gl.bufferData(target, src, gl.STATIC_DRAW);
    gl.bindBuffer(target, null);
    this._handle = vbo;
  }
  /**
   * @summary バッファのハンドル
   * @type {WebGLBuffer}
   * @readonly
   */


  _createClass(MeshBuffer, [{
    key: "dispose",

    /**
     * @summary リソースを破棄
     */
    value: function dispose() {
      var gl = this._glenv.context;
      gl.deleteBuffer(this._handle);
      this._handle = null;
    }
    /**
     * @private
     */

  }, {
    key: "handle",
    get: function get() {
      return this._handle;
    }
  }], [{
    key: "_getBindingPoint",
    value: function _getBindingPoint(gl, target) {
      switch (target) {
        default:
        case Target.ATTRIBUTE:
          return gl.ARRAY_BUFFER;

        case Target.INDEX:
          return gl.ELEMENT_ARRAY_BUFFER;
      }
    }
  }]);

  return MeshBuffer;
}();
/**
 * @summary バッファの使用目的
 *
 * @enum {object}
 * @memberof mapray.MeshBuffer
 * @constant
 */


var Target = {
  /**
   * 頂点属性
   */
  ATTRIBUTE: {
    id: "ATTRIBUTE"
  },

  /**
   * インデックス
   */
  INDEX: {
    id: "INDEX"
  }
};
MeshBuffer.Target = Target;

/**
 * @summary モデルメッシュ
 * @memberof mapray
 * @package
 */

var Mesh =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv}       glenv
   * @param {mapray.Mesh.Initializer|ArrayBuffer|object} data   メッシュデータ
   */
  function Mesh(glenv, data) {
    _classCallCheck(this, Mesh);

    this._glenv = glenv;
    this._draw_mode = undefined;
    this._num_vertices = 0;
    this._attrib_data = {};
    this._index_data = null;

    if (data instanceof Initializer) {
      // Mesh.Initializer
      this._initByInitializer(data);
    } else if (data instanceof ArrayBuffer) {
      // メッシュバイナリ
      this._initByInitializer(new BinaryInit(glenv, data).initializer);
    } else {
      // JSON オブジェクト
      this._initByInitializer(new JsonInit(glenv, data).initializer);
    }
  }
  /**
   * @summary Initializer による初期化
   *
   * @param {mapray.Mesh.Initializer} init  初期化データ
   * @private
   */


  _createClass(Mesh, [{
    key: "_initByInitializer",
    value: function _initByInitializer(init) {
      this._draw_mode = this._convertDrawMode(init.draw_mode);
      this._num_vertices = init.num_vertices; // this._attrib_data

      var src_attrib_data = init.attribute_data; // Mesh.Initializer#addAttribute() を参照

      for (var i = 0; i < src_attrib_data.length; ++i) {
        var sad = src_attrib_data[i];
        this._attrib_data[sad.id] = {
          mesh_buffer: sad.buffer,
          buffer: sad.buffer.handle,
          num_components: sad.num_components,
          component_type: this._convertComponentType(sad.component_type),
          normalized: sad.normalized,
          byte_stride: sad.byte_stride,
          byte_offset: sad.byte_offset
        };
      } // this._index_data


      if (init.index_data) {
        var src_index_data = init.index_data; // Mesh.Initializer#addIndex() を参照

        this._index_data = {
          mesh_buffer: src_index_data.buffer,
          buffer: src_index_data.buffer.handle,
          num_indices: src_index_data.num_indices,
          type: this._convertComponentType(src_index_data.type),
          byte_offset: src_index_data.byte_offset
        };
      }
    }
    /**
     * @summary DrawMode 型から GL 描画モードへ変換
     *
     * @param  {mapray.Mesh.DrawMode} mode  描画モード
     * @return {number}                     GL 描画モード
     * @private
     */

  }, {
    key: "_convertDrawMode",
    value: function _convertDrawMode(mode) {
      var gl = this._glenv.context;

      switch (mode) {
        case DrawMode.POINTS:
          return gl.POINTS;

        case DrawMode.LINES:
          return gl.LINES;

        case DrawMode.TRIANGLES:
          return gl.TRIANGLES;

        case DrawMode.LINE_LOOP:
          return gl.LINE_LOOP;

        case DrawMode.LINE_STRIP:
          return gl.LINE_STRIP;

        case DrawMode.TRIANGLE_STRIP:
          return gl.TRIANGLE_STRIP;

        case DrawMode.TRIANGLE_FAN:
          return gl.TRIANGLE_FAN;

        default:
          throw new Error("mapray: invalid Mesh.DrawMode: " + mode);
      }
    }
    /**
     * @summary ComponentType 型から GL 要素型へ変換
     *
     * @param  {mapray.Mesh.ComponentType} type  要素型
     * @return {number}                          GL 要素型
     * @private
     */

  }, {
    key: "_convertComponentType",
    value: function _convertComponentType(type) {
      var gl = this._glenv.context;

      switch (type) {
        case ComponentType.BYTE:
          return gl.BYTE;

        case ComponentType.UNSIGNED_BYTE:
          return gl.UNSIGNED_BYTE;

        case ComponentType.SHORT:
          return gl.SHORT;

        case ComponentType.UNSIGNED_SHORT:
          return gl.UNSIGNED_SHORT;

        case ComponentType.UNSIGNED_INT:
          return gl.UNSIGNED_INT;

        case ComponentType.FLOAT:
          return gl.FLOAT;

        default:
          throw new Error("mapray: invalid Mesh.ComponentType: " + type);
      }
    }
    /**
     * @summary リソースを破棄
     */

  }, {
    key: "dispose",
    value: function dispose() {
      this._attrib_data = {};
      this._index_data = null;
    }
    /**
     * @summary メッシュを描画
     *
     * @desc
     * <p>事前に material.bindProgram(), material.setParameters() すること。</p>
     *
     * @param {mapray.EntityMaterial} material  マテリアル
     */

  }, {
    key: "draw",
    value: function draw(material) {
      var gl = this._glenv.context; // 頂点属性のバインド

      material.bindVertexAttribs(this._attrib_data);
      var index_data = this._index_data;

      if (index_data !== null) {
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_data.buffer);
        gl.drawElements(this._draw_mode, index_data.num_indices, index_data.type, index_data.byte_offset);
      } else {
        gl.drawArrays(this._draw_mode, 0, this._num_vertices);
      }
    }
  }]);

  return Mesh;
}();
/**
 * @summary メッシュの初期化オブジェクト
 *
 * @memberof mapray.Mesh
 * @package
*/


var Initializer =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Mesh.DrawMode} draw_mode     描画モード
   * @param {number}               num_vertices  頂点数
   */
  function Initializer(draw_mode, num_vertices) {
    _classCallCheck(this, Initializer);

    this.draw_mode = draw_mode;
    this.num_vertices = num_vertices;
    this.index_data = null;
    this.attribute_data = [];
  }
  /**
   * @summary インデックスデータを追加
   *
   * @param {mapray.MeshBuffer}         buffer       バッファ
   * @param {number}                    num_indices  インデックス数
   * @param {mapray.Mesh.ComponentType} type         インデックス型 (UNSIGNED_BYTE | UNSIGNED_SHORT | UNSIGNED_INT)
   * @param {object}                    [options]                オプション
   * @param {number}                    [options.byte_offset=0]  バッファ先頭からのバイトオフセット
   */


  _createClass(Initializer, [{
    key: "addIndex",
    value: function addIndex(buffer, num_indices, type, options) {
      var opts = options || {};
      this.index_data = {
        buffer: buffer,
        num_indices: num_indices,
        type: type,
        byte_offset: opts.byte_offset !== undefined ? opts.byte_offset : 0
      };
    }
    /**
     * @summary 頂点属性データを追加
     *
     * @param {string}                    id              属性名
     * @param {mapray.MeshBuffer}         buffer          バッファ
     * @param {number}                    num_components  要素数
     * @param {mapray.Mesh.ComponentType} component_type  要素型
     * @param {object}                    [options]                   オプション
     * @param {boolean}                   [options.normalized=false]  正規化するか?
     * @param {number}                    [options.byte_stride=0]     頂点間のバイトストライド
     * @param {number}                    [options.byte_offset=0]     バッファ先頭からのバイトオフセット
     */

  }, {
    key: "addAttribute",
    value: function addAttribute(id, buffer, num_components, component_type, options) {
      var opts = options || {};
      var data = {
        id: id,
        buffer: buffer,
        num_components: num_components,
        component_type: component_type,
        normalized: opts.normalized !== undefined ? opts.normalized : false,
        byte_stride: opts.byte_stride !== undefined ? opts.byte_stride : 0,
        byte_offset: opts.byte_offset !== undefined ? opts.byte_offset : 0
      };
      this.attribute_data.push(data);
    }
  }]);

  return Initializer;
}();
/**
 * @summary 描画モードの列挙型
 * @enum {object}
 * @memberof mapray.Mesh
 * @constant
 */


var DrawMode = {
  /**
   * 点リスト
   */
  POINTS: {
    id: "POINTS"
  },

  /**
   * 線分リスト
   */
  LINES: {
    id: "LINES"
  },

  /**
   * 三角形リスト
   */
  TRIANGLES: {
    id: "TRIANGLES"
  },

  /**
   * 線分ループ
   */
  LINE_LOOP: {
    id: "LINE_LOOP"
  },

  /**
   * 線分ストリップ
   */
  LINE_STRIP: {
    id: "LINE_STRIP"
  },

  /**
   * 三角形ストリップ
   */
  TRIANGLE_STRIP: {
    id: "TRIANGLE_STRIP"
  },

  /**
   * 三角形ファン
   */
  TRIANGLE_FAN: {
    id: "TRIANGLE_FAN"
  }
};
/**
 * @summary 要素型の列挙型
 * @enum {object}
 * @memberof mapray.Mesh
 * @constant
 */

var ComponentType = {
  /**
   * 符号付き 8 ビット整数型
   */
  BYTE: {
    id: "BYTE"
  },

  /**
   * 符号なし 8 ビット整数型
   */
  UNSIGNED_BYTE: {
    id: "UNSIGNED_BYTE"
  },

  /**
   * 符号付き 16 ビット整数型
   */
  SHORT: {
    id: "SHORT"
  },

  /**
   * 符号なし 16 ビット整数型
   */
  UNSIGNED_SHORT: {
    id: "UNSIGNED_SHORT"
  },

  /**
   * 符号なし 32 ビット整数型
   */
  UNSIGNED_INT: {
    id: "UNSIGNED_INT"
  },

  /**
   * 32 ビット浮動小数点数型
   */
  FLOAT: {
    id: "FLOAT"
  }
};
/**
 * @summary JSON オブジェクトを Mesh.Initializer に変換
 *
 * @memberof mapray.Mesh
 * @private
 */

var JsonInit =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv} glenv
   * @param {object}       data   メッシュデータ
   */
  function JsonInit(glenv, data) {
    _classCallCheck(this, JsonInit);

    var vinfo = InitHelper.createVertexInfo(data.vtype);
    var num_vcompos = InitHelper.numVertexComponents(vinfo);
    var num_vertices = data.vertices.length / num_vcompos;
    this._initializer = new Initializer(JsonInit._toDrawMode(data), num_vertices);

    this._addIndex(glenv, data.indices, num_vertices);

    var FLT_BYTES = 4;
    var buffer = new MeshBuffer(glenv, InitHelper.toTypedArray(data.vertices, ComponentType.FLOAT));
    var byteStride = num_vcompos * FLT_BYTES;
    var byteOffset = 0;

    for (var i = 0; i < vinfo.length; ++i) {
      var num_compos = vinfo[i].size;

      this._initializer.addAttribute(vinfo[i].name, buffer, num_compos, ComponentType.FLOAT, {
        byte_stride: byteStride,
        byte_offset: byteOffset
      });

      byteOffset += num_compos * FLT_BYTES;
    }
  }
  /**
   * @summary Mesh.Initializer インスタンスを取得
   * @type {Mesh.Initializer}
   * @readonly
   */


  _createClass(JsonInit, [{
    key: "_addIndex",

    /**
     * @summary インデックスデータを追加
     *
     * @param {mapray.GLEnv} glenv
     * @param {object}       indices       インデックス配列
     * @param {number}       num_vertices  頂点数
     */
    value: function _addIndex(glenv, indices, num_vertices) {
      // インデックスの型は頂点数により自動的に決める
      var type = num_vertices < 65536 ? ComponentType.UNSIGNED_SHORT : ComponentType.UNSIGNED_INT;
      var buffer = new MeshBuffer(glenv, InitHelper.toTypedArray(indices, type), {
        target: MeshBuffer.Target.INDEX
      });

      this._initializer.addIndex(buffer, indices.length, type);
    }
    /**
     * @summary Mesh.DrawMode に変換
     *
     * @param  {object} data           メッシュデータ
     * @return {mapray.Mesh.DrawMode}  描画モード
     * @private
     */

  }, {
    key: "initializer",
    get: function get() {
      return this._initializer;
    }
  }], [{
    key: "_toDrawMode",
    value: function _toDrawMode(data) {
      // ptype?: ("triangles" | "lines") = "triangles"
      switch (data.ptype) {
        case "triangles":
          return DrawMode.TRIANGLES;

        case "lines":
          return DrawMode.LINES;

        default:
          return DrawMode.TRIANGLES;
      }
    }
  }]);

  return JsonInit;
}();
/**
 * @summary メッシュバイナリを Mesh.Initializer に変換
 *
 * @memberof mapray.Mesh
 * @private
 */


var BinaryInit =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv} glenv
   * @param {ArrayBuffer}  data   メッシュデータ
   */
  function BinaryInit(glenv, data) {
    _classCallCheck(this, BinaryInit);

    var header = new DataView(data, 0);
    var vtype = header.getUint8(BinaryInit.OFFSET_VTYPE);
    var itype = header.getUint8(BinaryInit.OFFSET_ITYPE);
    var ptype = header.getUint8(BinaryInit.OFFSET_PTYPE);
    var num_vertices = header.getUint32(BinaryInit.OFFSET_NUM_VERTICES, true);
    var num_indices = header.getUint32(BinaryInit.OFFSET_NUM_INDICES, true);
    this._initializer = new Initializer(BinaryInit._toDrawMode(ptype), num_vertices);
    var vinfo = InitHelper.createVertexInfo(vtype);

    var indices = this._createIndexArray(glenv, data, itype, num_indices, vinfo, num_vertices);

    this._addIndex(glenv, itype, indices);

    var FLT_BYTES = 4;
    var buffer = new MeshBuffer(glenv, this._createVertexArray(data, vinfo, num_vertices));
    var byteStride = InitHelper.numVertexComponents(vinfo) * FLT_BYTES;
    var byteOffset = 0;

    for (var i = 0; i < vinfo.length; ++i) {
      var num_compos = vinfo[i].size;

      this._initializer.addAttribute(vinfo[i].name, buffer, num_compos, ComponentType.FLOAT, {
        byte_stride: byteStride,
        byte_offset: byteOffset
      });

      byteOffset += num_compos * FLT_BYTES;
    }
  }
  /**
   * @summary Mesh.Initializer インスタンスを取得
   * @type {Mesh.Initializer}
   * @readonly
   */


  _createClass(BinaryInit, [{
    key: "_createIndexArray",

    /**
     * @summary インデックスバッファを作成 (バイナリデータから)
     *
     * @param  {mapray.GLEnv} glenv
     * @param  {ArrayBuffer}  src_buffer   バイナリデータ
     * @param  {number}       itype        インデックス型 (ENUM_ITYPE_UINT16 | ENUM_ITYPE_UINT32)
     * @param  {number}       num_indices  インデックス数
     * @param  {array}        vinfo        頂点情報
     * @param  {number}       num_vertices 頂点数
     * @return {Uint16Array|Uint32Array}   インデックス配列
     * @private
     */
    value: function _createIndexArray(glenv, src_buffer, itype, num_indices, vinfo, num_vertices) {
      // 入力配列を作成
      var FLT_BYTES = 4;
      var vertices_bytes = InitHelper.numVertexComponents(vinfo) * num_vertices * FLT_BYTES;
      var src_view = new DataView(src_buffer, BinaryInit.OFFSET_BODY + vertices_bytes);
      var i;
      var dst_array;
      var index_bytes;

      switch (itype) {
        case BinaryInit.ENUM_ITYPE_UINT16:
          dst_array = new Uint16Array(num_indices);
          index_bytes = 2;

          for (i = 0; i < num_indices; ++i) {
            dst_array[i] = src_view.getUint16(index_bytes * i, true);
          }

          break;

        case BinaryInit.ENUM_ITYPE_UINT32:
          dst_array = new Uint32Array(num_indices);
          index_bytes = 4;

          for (i = 0; i < num_indices; ++i) {
            dst_array[i] = src_view.getUint32(index_bytes * i, true);
          }

          break;

        default:
          throw new Error("mapray: unknown itype: " + itype);
      }

      return dst_array;
    }
    /**
     * @summary 頂点バッファを作成 (バイナリデータから)
     *
     * @param  {ArrayBuffer} src_buffer    バイナリデータ
     * @param  {array}       vinfo         頂点情報
     * @param  {number}      num_vertices  頂点数
     * @return {Float32Array}              頂点データを格納した配列
     * @private
     */

  }, {
    key: "_createVertexArray",
    value: function _createVertexArray(src_buffer, vinfo, num_vertices) {
      var FLT_BYTES = 4; // 入力配列を作成

      var num_elements = InitHelper.numVertexComponents(vinfo) * num_vertices;
      var src_view = new DataView(src_buffer, BinaryInit.OFFSET_BODY);
      var dst_array = new Float32Array(num_elements);

      for (var i = 0; i < num_elements; ++i) {
        dst_array[i] = src_view.getFloat32(i * FLT_BYTES, true);
      }

      return dst_array;
    }
    /**
     * @summary インデックスデータを追加
     *
     * @param {mapray.GLEnv}            glenv
     * @param {number}                  itype    インデックス型 (ENUM_ITYPE_UINT16 | ENUM_ITYPE_UINT32)
     * @param {Uint16Array|Uint32Array} indices  インデックス配列
     * @private
     */

  }, {
    key: "_addIndex",
    value: function _addIndex(glenv, itype, indices) {
      var buffer = new MeshBuffer(glenv, indices, {
        target: MeshBuffer.Target.INDEX
      });

      var type = BinaryInit._indexTypeToComponentType(itype);

      this._initializer.addIndex(buffer, indices.length, type);
    }
    /**
     * @summary Mesh.DrawMode に変換
     *
     * @param  {number} ptype          プリミティブタイプ
     * @return {mapray.Mesh.DrawMode}  描画モード
     * @private
     */

  }, {
    key: "initializer",
    get: function get() {
      return this._initializer;
    }
  }], [{
    key: "_toDrawMode",
    value: function _toDrawMode(ptype) {
      switch (ptype) {
        case BinaryInit.ENUM_PTYPE_TRIANGLES:
          return DrawMode.TRIANGLES;

        case BinaryInit.ENUM_PTYPE_LINES:
          return DrawMode.LINES;

        default:
          throw new Error("mapray: invalid ptype: " + ptype);
      }
    }
    /**
     * @summary インデックス型から要素型へ変換
     *
     * @param  {number} itype               インデックス型 (ENUM_ITYPE_UINT16 | ENUM_ITYPE_UINT32)
     * @return {mapray.Mesh.ComponentType}  要素型 (UNSIGNED_SHORT | UNSIGNED_INT)
     * @private
     */

  }, {
    key: "_indexTypeToComponentType",
    value: function _indexTypeToComponentType(itype) {
      switch (itype) {
        case BinaryInit.ENUM_ITYPE_UINT16:
          return ComponentType.UNSIGNED_SHORT;

        case BinaryInit.ENUM_ITYPE_UINT32:
        default:
          return ComponentType.UNSIGNED_INT;
      }
    }
  }]);

  return BinaryInit;
}();

{
  // バイナリデータのオフセット
  BinaryInit.OFFSET_VTYPE = 0;
  BinaryInit.OFFSET_ITYPE = 1;
  BinaryInit.OFFSET_PTYPE = 2;
  BinaryInit.OFFSET_NUM_VERTICES = 4;
  BinaryInit.OFFSET_NUM_INDICES = 8;
  BinaryInit.OFFSET_BODY = 12; // ITYPE 列挙値

  BinaryInit.ENUM_ITYPE_UINT16 = 0;
  BinaryInit.ENUM_ITYPE_UINT32 = 1; // PTYPE 列挙値

  BinaryInit.ENUM_PTYPE_TRIANGLES = 0;
  BinaryInit.ENUM_PTYPE_LINES = 1;
}
/**
 * @summary 初期化ヘルパー
 *
 * @memberof mapray.Mesh
 * @private
 */

var InitHelper =
/*#__PURE__*/
function () {
  function InitHelper() {
    _classCallCheck(this, InitHelper);
  }

  _createClass(InitHelper, null, [{
    key: "createVertexInfo",

    /**
     * @summary 頂点情報を生成
     * @desc
     * <p>vtype を以下の形式に変換して返す。ただし vtype が配列なら vtype を返す。</p>
     * <pre>
     *   [ { name: 頂点属性名, size: 要素数 }, ... ]
     * </pre>
     * @param  {string|number|array} vtype  頂点タイプまたは頂点情報
     * @return {array}                      頂点情報
     */
    value: function createVertexInfo(vtype) {
      if (Array.isArray(vtype)) {
        // vtype は最初から頂点情報
        return vtype;
      }

      var vinfo = null; // vtype: ("P" | "PN" | "PT" | "PNT")

      switch (vtype) {
        case "P":
        case InitHelper.ENUM_VTYPE_P:
          vinfo = [{
            name: InitHelper.ANAME_P,
            size: InitHelper.FSIZE_P
          }];
          break;

        case "PN":
        case InitHelper.ENUM_VTYPE_PN:
          vinfo = [{
            name: InitHelper.ANAME_P,
            size: InitHelper.FSIZE_P
          }, {
            name: InitHelper.ANAME_N,
            size: InitHelper.FSIZE_N
          }];
          break;

        case "PT":
        case InitHelper.ENUM_VTYPE_PT:
          vinfo = [{
            name: InitHelper.ANAME_P,
            size: InitHelper.FSIZE_P
          }, {
            name: InitHelper.ANAME_T,
            size: InitHelper.FSIZE_T
          }];
          break;

        case "PNT":
        case InitHelper.ENUM_VTYPE_PNT:
          vinfo = [{
            name: InitHelper.ANAME_P,
            size: InitHelper.FSIZE_P
          }, {
            name: InitHelper.ANAME_N,
            size: InitHelper.FSIZE_N
          }, {
            name: InitHelper.ANAME_T,
            size: InitHelper.FSIZE_T
          }];
          break;

        default:
          throw new Error("mapray: unknown vtype: " + vtype);
      }

      return vinfo;
    }
    /**
     * @summary 頂点データの要素数を取得
     *
     * @param  {object[]} vinfo  頂点情報
     * @return {number}          頂点データの要素数
     */

  }, {
    key: "numVertexComponents",
    value: function numVertexComponents(vinfo) {
      var length = vinfo.length;
      var num_compos = 0;

      for (var i = 0; i < length; ++i) {
        num_compos += vinfo[i].size;
      }

      return num_compos;
    }
    /**
     * @summary 型配列に変換
     *
     * @param  {object}                    array  入力配列
     * @param  {mapray.Mesh.ComponentType} type   変換先の要素型
     * @return {TypedArray}                       変換された配列
     */

  }, {
    key: "toTypedArray",
    value: function toTypedArray(array, type) {
      switch (type) {
        case ComponentType.UNSIGNED_SHORT:
          return array instanceof Uint16Array ? array : new Uint16Array(array);

        case ComponentType.UNSIGNED_INT:
          return array instanceof Uint32Array ? array : new Uint32Array(array);

        case ComponentType.FLOAT:
          return array instanceof Float32Array ? array : new Float32Array(array);

        default:
          throw new Error("mapray: invalid component type: " + type);
      }
    }
  }]);

  return InitHelper;
}();

{
  // VTYPE 列挙値
  InitHelper.ENUM_VTYPE_P = 0;
  InitHelper.ENUM_VTYPE_PN = 1;
  InitHelper.ENUM_VTYPE_PT = 2;
  InitHelper.ENUM_VTYPE_PNT = 3; // 頂点属性名

  InitHelper.ANAME_P = "a_position";
  InitHelper.ANAME_N = "a_normal";
  InitHelper.ANAME_T = "a_texcoord"; // 要素のサイズ (要素数)

  InitHelper.FSIZE_P = 3;
  InitHelper.FSIZE_N = 3;
  InitHelper.FSIZE_T = 2;
}
Mesh.Initializer = Initializer;
Mesh.DrawMode = DrawMode;
Mesh.ComponentType = ComponentType;

/**
 * @summary 高度モード
 *
 * @desc
 * <p>{@link mapray.GeoPoint} などの高度値をどのように解釈するかを指定する列挙値の型である。<p>
 *
 * @enum {object}
 * @memberof mapray
 * @constant
 * @see mapray.Entity
 */
var AltitudeMode = {
  /**
   * 絶対値
   */
  ABSOLUTE: {
    id: "ABSOLUTE"
  },

  /**
   * 地表からの相対値
   */
  RELATIVE: {
    id: "RELATIVE"
  },

  /**
   * 地表と同じ高さ (高度値を無視)
   */
  CLAMP: {
    id: "CLAMP"
  }
};

/**
 * @summary シーン・エンティティ
 * @classdesc
 * <p>シーン・エンティティの基底クラスである。</p>
 * @memberof mapray
 * @see mapray.Scene
 * @protected
 * @abstract
 */

var Entity =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>インスタンス生成後に、それを scene に追加することができる。</p>
   *
   * @param {mapray.Scene} scene  所属可能シーン
   * @param {object} [opts]       オプション集合
   * @param {object} [opts.json]  生成情報
   * @param {object} [opts.refs]  参照辞書
   */
  function Entity(scene, opts) {
    _classCallCheck(this, Entity);

    /**
     * @summary 所属可能シーン
     * @member mapray.Entity#scene
     * @type {mapray.Scene}
     * @readonly
     */
    this.scene = scene; // 高度モード

    this._altitude_mode = AltitudeMode.ABSOLUTE;
    this._need_to_create_regions = false; // animation.BindingBlock
    //   今のところ Entity (基底クラス) 自体のアニメーション可能パラメータと
    //   子孫は存在しないので animation には何も追加しない

    this._animation = new EasyBindingBlock(); // 生成情報から設定

    if (opts && opts.json) {
      this._setupEntityByJson(opts.json);
    }
  }
  /**
   * @summary アニメーションパラメータ設定
   *
   * @type {mapray.animation.BindingBlock}
   * @readonly
   */


  _createClass(Entity, [{
    key: "onChangeAltitudeMode",

    /**
     * @summary 高度モードが変更された後の通知
     *
     * @desc
     * <p>this.altitude_mode が変更されたときに呼び出される。</p>
     * <p>既定の実装は何もしない。</p>
     *
     * @param {mapray.AltitudeMode} prev_mode  直前のモード
     *
     * @abstract
     * @private
     */
    value: function onChangeAltitudeMode(prev_mode) {}
    /**
     * @summary PrimitiveProducer インタフェースを取得
     *
     * @desc
     * <p>PrimitiveProducer インタフェースを取得するためにシーンレンダラーが呼び出す。
     *    PrimitiveProducer インタフェースが実装されていなければ null を返す。</p>
     * <p>既定の実装は null を返す。</p>
     *
     * @return {?mapray.Entity.PrimitiveProducer}  PrimitiveProducer インタフェース
     *
     * @abstract
     * @package
     */

  }, {
    key: "getPrimitiveProducer",
    value: function getPrimitiveProducer() {
      return null;
    }
    /**
     * @summary FlakePrimitiveProducer インタフェースを取得
     *
     * @desc
     * <p>FlakePrimitiveProducer インタフェースを取得するためにシーンレンダラーが呼び出す。
     *    FlakePrimitiveProducer インタフェースが実装されていなければ null を返す。</p>
     * <p>既定の実装は null を返す。</p>
     *
     * @return {?mapray.Entity.FlakePrimitiveProducer}  FlakePrimitiveProducer インタフェース
     *
     * @abstract
     * @package
     */

  }, {
    key: "getFlakePrimitiveProducer",
    value: function getFlakePrimitiveProducer() {
      return null;
    }
    /**
     * JSON データによる Entity 共通の初期化
     * @private
     */

  }, {
    key: "_setupEntityByJson",
    value: function _setupEntityByJson(json) {
      // 高度モード
      if (json.altitude_mode) {
        switch (json.altitude_mode) {
          case "absolute":
            this._altitude_mode = AltitudeMode.ABSOLUTE;
            break;

          case "relative":
            this._altitude_mode = AltitudeMode.RELATIVE;
            break;

          case "clamp":
            this._altitude_mode = AltitudeMode.CLAMP;
            break;

          default:
            console.error("unrecognized altitude_mode: " + json.altitude_mode);
        }
      }
    }
  }, {
    key: "animation",
    get: function get() {
      return this._animation;
    }
    /**
     * @summary 高度モード
     * @type {mapray.AltitudeMode}
     */

  }, {
    key: "altitude_mode",
    set: function set(value) {
      if (this._altitude_mode !== value) {
        var prev_mode = this._altitude_mode;
        this._altitude_mode = value;
        this.onChangeAltitudeMode(prev_mode);
      }
    },
    get: function get() {
      return this._altitude_mode;
    }
  }]);

  return Entity;
}();
/**
 * @summary エンティティのプリミティブを生産
 *
 * @classdesc
 * <p>シーンレンダラーにエンティティのプリミティブを与える。</p>
 *
 * @memberof mapray.Entity
 * @private
 * @abstract
 */


var PrimitiveProducer =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Entity} entity  PrimitiveProducer に対応するエンティティ
   */
  function PrimitiveProducer(entity) {
    _classCallCheck(this, PrimitiveProducer);

    this._entity = entity;
    this._need_to_create_regions = false;
  }
  /**
   * @summary エンティティ
   *
   * @type {mapray.Entity}
   * @readonly
   */


  _createClass(PrimitiveProducer, [{
    key: "needToCreateRegions",

    /**
     * @summary 領域が更新されたとき呼び出す
     *
     * @desc
     * <p>領域を変更したい場合に PrimitiveProducer の実装者が呼び出す必要がある。</p>
     */
    value: function needToCreateRegions() {
      this._need_to_create_regions = true;
    }
    /**
     * @summary need_to_create_regions を取得
     *
     * @desc
     * <p>エンティティの領域を変更する (createRegions() を呼び出す) 必要があるかどうかを確認するためにシーンレンダラーが呼び出す。</p>
     *
     * @return {boolean}  領域を変更する必要があるとき true, それ以外のとき false
     *
     * @see needToCreateRegions()
     */

  }, {
    key: "checkToCreateRegions",
    value: function checkToCreateRegions() {
      var result = this._need_to_create_regions;
      this._need_to_create_regions = false;
      return result;
    }
    /**
     * @summary エンティティに標高値は必要か?
     *
     * @desc
     * <p>エンティティが標高値を必要としているかどうかを確認するためレンダラーが呼び出す。<p>
     * <p>既定の実装では entity.altitude_mode が AltitudeMode.ABSOLUTE なら false, それ以外なら true を返す。</p>
     *
     * @return {boolean}  エンティティに標高値が必要なら true, それ以外なら false
     *
     * @abstract
     */

  }, {
    key: "needsElevation",
    value: function needsElevation() {
      return this._entity._altitude_mode !== AltitudeMode.ABSOLUTE;
    }
    /**
     * @summary エンティティ領域を生成
     *
     * @desc
     * <p>エンティティの領域を確認するためレンダラーが呼び出す。<p>
     * <p>既定の実装では [] を返す。</p>
     *
     * @return {mapray.EntityRegion[]}  エンティティ領域の配列
     *
     * @abstract
     */

  }, {
    key: "createRegions",
    value: function createRegions() {
      return [];
    }
    /**
     * @summary 更新されたエンティティ領域の通知
     *
     * @desc
     * <p>エンティティの領域の標高が変化したことを通知するためレンダラーが呼び出す。regions は標高が更新されたエンティティ領域を含む配列である。</p>
     * <p>既定の実装では何もしない。</p>
     *
     * @param {mapray.EntityRegion[]} regions  エンティティ領域の配列
     *
     * @abstract
     */

  }, {
    key: "onChangeElevation",
    value: function onChangeElevation(regions) {}
    /**
     * @summary プリミティブ配列を取得
     *
     * @desc
     * <p>レンダリング時にこのエンティティを描画するための 0 個以上のプリミティブを含む配列を返す。</p>
     * <p>このメソッドが呼び出されたフレームのレンダリングが終了するまで、返した配列とそれに含まれるプリミティブは変更してはならない。</p>
     *
     * @param  {mapray.RenderStage} stage  レンダリングステージ
     * @return {Array.<mapray.Primitive>}  プリミティブ配列
     *
     * @abstract
     */

  }, {
    key: "getPrimitives",
    value: function getPrimitives(stage) {
      throw new Error("mapray.Entity.PrimitiveProducer#getPrimitives() method has not been overridden.");
    }
  }, {
    key: "entity",
    get: function get() {
      return this._entity;
    }
  }]);

  return PrimitiveProducer;
}();
/**
 * @summary 地表断片エンティティのプリミティブを生産
 *
 * @classdesc
 * <p>シーンレンダラーに地表断片エンティティのプリミティブを与える。</p>
 *
 * @memberof mapray.Entity
 * @private
 * @abstract
 */


var FlakePrimitiveProducer =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Entity} entity  FlakePrimitiveProducer に対応するエンティティ
   */
  function FlakePrimitiveProducer(entity) {
    _classCallCheck(this, FlakePrimitiveProducer);

    this._entity = entity;
    this._updated = false;
  }
  /**
   * @summary エンティティ
   *
   * @type {mapray.Entity}
   * @readonly
   */


  _createClass(FlakePrimitiveProducer, [{
    key: "notifyForUpdate",

    /**
     * @summary 位置や形状の変化を通知
     */
    value: function notifyForUpdate() {
      this._updated = true;
    }
    /**
     * @summary 領域状態を取得
     *
     * @desc
     * <p>area が示す領域の状態を取得する。</p>
     *
     * @param {mapray.Area} area  確認する領域
     *
     * @return {mapray.Entity.AreaStatus}  領域の状態
     *
     * @abstract
     */

  }, {
    key: "getAreaStatus",
    value: function getAreaStatus(area) {
      return AreaStatus.EMPTY;
    }
    /**
     * @summary メッシュを生成
     *
     * @desc
     * <p>area の領域に対応するメッシュを取得する。</p>
     * <p>area に形状がないときは null を返す。</p>
     *
     * @param {mapray.Area}     area  メッシュの領域
     * @param {number[]}       dpows  領域の分割指数
     * @param {mapray.DemBinary} dem  DEM バイナリ
     *
     * @return {?mapray.Mesh}
     *
     * @abstract
     */

  }, {
    key: "createMesh",
    value: function createMesh(area, dpows, dem) {
      return null;
    }
    /**
     * @summary マテリアルとプロパティを取得
     *
     * @param {mapray.RenderStage} stage  レンダリングステージ
     *
     * @return {object}  { material: mapray.EntityMaterial, properties: mapray.PropSet }
     *
     * @abstract
     */

  }, {
    key: "getMaterialAndProperties",
    value: function getMaterialAndProperties(stage) {
      throw new Error("mapray.Entity.FlakePrimitiveProducer#getMaterialAndProperties() method has not been overridden.");
    }
    /**
     * @summary 更新状態を確認
     *
     * @desc
     * <p>レンダラーが呼び出す。</p>
     * <p>更新状態を返してから、更新なし状態に設定する。</p>
     *
     * @return {boolean}  更新ありのとき true, それ以外のとき false
     *
     * @package
     */

  }, {
    key: "checkForUpdate",
    value: function checkForUpdate() {
      var updated = this._updated;
      this._updated = false;
      return updated;
    }
  }, {
    key: "entity",
    get: function get() {
      return this._entity;
    }
  }]);

  return FlakePrimitiveProducer;
}();
/**
 * @summary 領域状態の列挙型
 *
 * @enum {object}
 * @memberof mapray.Entity
 * @constant
 * @private
 */


var AreaStatus = {
  /**
   * 何もない領域
   */
  EMPTY: {
    id: "EMPTY"
  },

  /**
   * 完全に満たされた領域
   */
  FULL: {
    id: "FULL"
  },

  /**
   * 部分領域または領域不明
   */
  PARTIAL: {
    id: "PARTIAL"
  }
};
Entity.PrimitiveProducer = PrimitiveProducer;
Entity.FlakePrimitiveProducer = FlakePrimitiveProducer;
Entity.AreaStatus = AreaStatus;

/**
 * @summary 地表形状の管理
 * @memberof mapray
 * @private
 */

var Globe =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv}       glenv         WebGL 環境
   * @param {mapray.DemProvider} dem_provider  DEM プロバイダ
   */
  function Globe(glenv, dem_provider) {
    _classCallCheck(this, Globe);

    this._glenv = glenv;
    this._dem_provider = dem_provider;
    this._status = Status.NOT_READY;
    this._dem_area_updated = new UpdatedTileArea();
    this._prev_producers = new Set();
    this._ρ = dem_provider.getResolutionPower();
    this._dem_zbias = GeoMath.LOG2PI - this._ρ + 1; // b = log2(π) - ρ + 1

    this._hist_stats = new HistStats();
    this._flake_reduce_thresh = 1.5; // Flake 削減比率閾値

    this._flake_reduce_factor = 1.2; // Flake 削減比率係数

    this._num_cache_flakes = 0; // キャッシュ内の Flake 数 (_root_flake と子孫の数)

    this._num_touch_flakes = 0; // 現行フレームでのアクセス Flake 数

    this._mesh_reduce_lower = 300; // Mesh 削減下限値

    this._mesh_reduce_thresh = 1.5; // Mesh 削減比率閾値

    this._mesh_reduce_factor = 1.2; // Mesh 削減比率係数

    this._num_cache_meshes = 0; // キャッシュ内の Mesh 数

    this._num_touch_meshes = 0; // 現行フレームでのアクセス Mesh 数

    this._max_dem_requesteds = 10; // 最大 REQUESTED 数

    this._num_dem_requesteds = 0; // 現在の REQUESTED 状態の数

    this._frame_counter = 0; // 現行フレーム番号

    this._root_flake = null;
    this._avg_height = null;
    this._root_cancel_id = null;

    this._requestRoot();
  }
  /**
   * すべてのリクエストを取り消す
   */


  _createClass(Globe, [{
    key: "cancel",
    value: function cancel() {
      if (this._status === Status.READY) {
        // root の真子孫を破棄 (リクエストをキャンセル)
        var children = this._root_flake._children;

        for (var i = 0; i < 4; ++i) {
          children[i].dispose();
        }
      } else if (this._status === Status.NOT_READY) {
        // リクエスト中の root をキャンセル
        this._dem_provider.cancelRequest(this._root_cancel_id);

        this._root_cancel_id = null;
      } // assert: this._num_dem_requesteds == 0

    }
    /**
     * WebGL 環境
     * @type {mapray.GLEnv}
     * @readonly
     */

  }, {
    key: "putNextEntityProducers",

    /**
     * @summary エンティティ情報を更新
     *
     * <p>getRenderObject() の前にエンティティの情報を更新する。</p>
     *
     * @param {iterable.<mapray.Entity.FlakePrimitiveProducer>} producers
     */
    value: function putNextEntityProducers(producers) {
      var next_producers = new Set(); // 追加、削除、更新のリストを作成

      var added_producers = [];
      var updated_producers = [];
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = producers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var prod = _step.value;
          var updated = prod.checkForUpdate(); // 更新チェックとクリア

          if (this._prev_producers.has(prod)) {
            if (updated) {
              // 更新された
              updated_producers.push(prod);
            }

            this._prev_producers["delete"](prod);
          } else {
            // 新規追加
            added_producers.push(prod);
          }

          next_producers.add(prod);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      var removed_producers = this._prev_producers; // ツリーを更新

      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = removed_producers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var _prod = _step2.value;

          this._root_flake.removeEntityProducer(_prod);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      for (var _i = 0, _added_producers = added_producers; _i < _added_producers.length; _i++) {
        var _prod2 = _added_producers[_i];

        this._root_flake.addEntityProducer(_prod2);
      }

      for (var _i2 = 0, _updated_producers = updated_producers; _i2 < _updated_producers.length; _i2++) {
        var _prod3 = _updated_producers[_i2];

        this._root_flake.updateEntityProducer(_prod3);
      } // 次の prev_producers を設定


      this._prev_producers = next_producers;
    }
    /**
     * @summary リクエスト待ちの DEM タイルの個数を取得
     *
     * @return {number}  リクエスト待ちの DEM タイルの個数
     */

  }, {
    key: "getNumDemWaitingRequests",
    value: function getNumDemWaitingRequests() {
      return this._num_dem_requesteds;
    }
    /**
     * @summary 正確度が最も高い DEM タイルデータを検索
     * @desc
     * <p>基底タイル座標 (左上(0, 0)、右下(1, 1)) [xt, yt] の標高データを取得することができる、正確度が最も高い DEM タイルデータを検索する。</p>
     * <p>サーバーにさらに正確度が高い DEM タイルデータが存在すれば、それをリクエストする。</p>
     * @param  {number}         xt  X 座標 (基底タイル座標系)
     * @param  {number}         yt  Y 座標 (基底タイル座標系)
     * @return {?mapray.DemBinary}  DEM タイルデータ (存在しなければ null)
     */

  }, {
    key: "findHighestAccuracy",
    value: function findHighestAccuracy(xt, yt) {
      var flake = this._root_flake;

      if (flake === null) {
        // まだ基底タイルが読み込まれていない
        return null;
      }

      var size = 2; // 2^(flake.z + 1)

      var xf = size * xt;
      var yf = size * yt;
      var dem_flake = flake; // DEM を持った地表断片

      for (;;) {
        var u = GeoMath.clamp(Math.floor(xf), 0, size - 1) % 2;
        var v = GeoMath.clamp(Math.floor(yf), 0, size - 1) % 2;
        var child = flake._children[u + 2 * v];
        flake.touch();

        if (child === null) {
          // これ以上のレベルは存在しない
          break;
        } else if (flake._dem_state === DemState.LOADED) {
          // より正確度が高い DEM を持つ地表断片に更新
          dem_flake = flake;
        }

        flake = child;
        size *= 2;
        xf *= 2;
        yf *= 2;
      }

      dem_flake._requestHighestAccuracy(xt, yt);

      return dem_flake._dem_data;
    }
    /**
     * @summary 現行の標高 (複数) を取得
     *
     * @desc
     * <p>現在メモリーにある最高精度の標高値を一括で取得する。</p>
     * <p>まだ DEM データが存在しない、または経度, 緯度が範囲外の場所は標高を 0 とする。</p>
     *
     * <p>このメソッドは DEM のリクエストは発生しない。また DEM のキャッシュには影響を与えない。</p>
     *
     * <p>一般的に画面に表示されていない場所は標高の精度が低い。</p>
     *
     * @param  {number}   num_points  入出力データ数
     * @param  {number[]} src_array   入力配列 (経度, 緯度, ...)
     * @param  {number}   src_offset  入力データの先頭インデックス
     * @param  {number}   src_stride  入力データのストライド
     * @param  {number[]} dst_array   出力配列 (標高, ...)
     * @param  {number}   dst_offset  出力データの先頭インデックス
     * @param  {number}   dst_stride  出力データのストライド
     * @return {number[]}             dst_array
     *
     * @see mapray.Viewer#getExistingElevations
     */

  }, {
    key: "getExistingElevations",
    value: function getExistingElevations(num_points, src_array, src_offset, src_stride, dst_array, dst_offset, dst_stride) {
      var dPI = 2 * Math.PI;
      var demSize = 1 << this._ρ; // 2^ρ

      var src_index = src_offset;
      var dst_index = dst_offset;

      for (var i = 0; i < num_points; ++i) {
        // 経緯度 (Degrees)
        var lon = src_array[src_index];
        var lat = src_array[src_index + 1]; // 正規化経緯度 (Degrees)

        var _lon = lon + 180 * Math.floor((90 - lat) / 360 + Math.floor((90 + lat) / 360));

        var nlon = _lon - 360 - 360 * Math.floor((_lon - 180) / 360); // 正規化経度 [-180,180)

        var nlat = 90 - Math.abs(90 - lat + 360 * Math.floor((90 + lat) / 360)); // 正規化緯度 [-90,90]
        // 単位球メルカトル座標

        var xm = nlon * GeoMath.DEGREE;
        var ym = GeoMath.invGudermannian(nlat * GeoMath.DEGREE); // 基底タイル座標 (左上(0, 0)、右下(1, 1))

        var xt = xm / dPI + 0.5;
        var yt = 0.5 - ym / dPI;

        if (yt >= 0 && yt <= 1) {
          // 通常範囲のとき
          var dem = this._findHighestAccuracy2(xt, yt);

          if (dem !== null) {
            var pow = Math.pow(2, dem.z); // 2^ze

            var uf = demSize * (pow * xt - dem.x);
            var vf = demSize * (pow * yt - dem.y);
            var ui = GeoMath.clamp(Math.floor(uf), 0, demSize - 1);
            var vi = GeoMath.clamp(Math.floor(vf), 0, demSize - 1);
            var heights = dem.getHeights(ui, vi);
            var h00 = heights[0];
            var h10 = heights[1];
            var h01 = heights[2];
            var h11 = heights[3]; // 標高を補間

            var s = uf - ui;
            var t = vf - vi;
            dst_array[dst_index] = (h00 * (1 - s) + h10 * s) * (1 - t) + (h01 * (1 - s) + h11 * s) * t;
          } else {
            // まだ標高を取得することができない
            dst_array[dst_index] = 0;
          }
        } else {
          // 緯度が Web メルカトルの範囲外 (極に近い)
          dst_array[dst_index] = 0;
        }

        src_index += src_stride;
        dst_index += dst_stride;
      }

      return dst_array;
    }
    /**
     * @summary 正確度が最も高い DEM タイルデータを検索
     *
     * @desc
     * <p>基底タイル座標 (左上(0, 0)、右下(1, 1)) [xt, yt] の標高データを取得することができる、正確度が最も高い DEM タイルデータを検索する。</p>
     *
     * @param  {number}         xt  X 座標 (基底タイル座標系)
     * @param  {number}         yt  Y 座標 (基底タイル座標系)
     * @return {?mapray.DemBinary}  DEM タイルデータ (存在しなければ null)
     *
     * @private
     */

  }, {
    key: "_findHighestAccuracy2",
    value: function _findHighestAccuracy2(xt, yt) {
      var flake = this._root_flake;

      if (flake === null) {
        // まだ基底タイルが読み込まれていない
        return null;
      }

      var size = 2; // 2^(flake.z + 1)

      var xf = size * xt;
      var yf = size * yt;
      var dem_flake = flake; // DEM を持った地表断片

      for (;;) {
        var u = GeoMath.clamp(Math.floor(xf), 0, size - 1) % 2;
        var v = GeoMath.clamp(Math.floor(yf), 0, size - 1) % 2;
        var child = flake._children[u + 2 * v];

        if (child === null) {
          // これ以上のレベルは存在しない
          break;
        } else if (flake._dem_state === DemState.LOADED) {
          // より正確度が高い DEM を持つ地表断片に更新
          dem_flake = flake;
        }

        flake = child;
        size *= 2;
        xf *= 2;
        yf *= 2;
      }

      return dem_flake._dem_data;
    }
    /**
     * @summary フレームの最後の処理
     */

  }, {
    key: "endFrame",
    value: function endFrame() {
      var max_touch_flakes = this._hist_stats.getMaxValue(this._num_touch_flakes);

      if (this._num_cache_flakes > this._flake_reduce_thresh * max_touch_flakes) {
        this._reduceFlakes(max_touch_flakes);
      }

      if (this._num_cache_meshes > this._mesh_reduce_lower && this._num_cache_meshes > this._mesh_reduce_thresh * this._num_touch_meshes) {
        this._reduceMeshes();
      }

      this._dem_area_updated.clear();

      this._num_touch_flakes = 0;
      this._num_touch_meshes = 0;
      ++this._frame_counter;
    }
    /**
     * _root_flake, _avg_height, _status を設定するためのリクエスト
     * @private
     */

  }, {
    key: "_requestRoot",
    value: function _requestRoot() {
      var _this = this;

      var z = 0;
      var x = 0;
      var y = 0;
      this._root_cancel_id = this._dem_provider.requestTile(z, x, y, function (data) {
        if (data) {
          var dem = new DemBinary(z, x, y, _this._ρ, data);
          _this._avg_height = dem.newAvgHeightMaps();
          _this._root_flake = new Flake(null, z, x, y);

          _this._root_flake.setupRoot(_this, dem);

          _this._status = Status.READY;

          _this._dem_area_updated.addTileArea(dem);
        } else {
          // データ取得に失敗
          _this._status = Status.FAILED;
        }

        _this._root_cancel_id = null;
        --_this._num_dem_requesteds;
      });
      ++this._num_dem_requesteds;
    }
    /**
     * @private
     */

  }, {
    key: "_reduceFlakes",
    value: function _reduceFlakes(max_touch_flakes) {
      // Flake を集めて、優先度で整列
      var flat_flakes = this._root_flake.flattenFlakes(); // assert: flat_flakes.length == this._num_cache_flakes


      flat_flakes.sort(function (a, b) {
        return a.compareForReduce(b);
      }); // 優先度の低い Flake を削除

      var num_cache_flakes = Math.floor(this._flake_reduce_factor * max_touch_flakes);
      flat_flakes.slice(num_cache_flakes).forEach(function (flake) {
        return flake.dispose();
      }); // assert: this._num_cache_flakes == num_cache_flakes
    }
    /**
     * @private
     */

  }, {
    key: "_reduceMeshes",
    value: function _reduceMeshes() {
      var flat_meshes = this._root_flake.flattenMeshes(); // assert: flat_meshes.length == this._num_cache_meshes


      flat_meshes.sort(function (a, b) {
        return a.compareForReduce(b);
      });
      var num_cache_meshes = Math.floor(this._mesh_reduce_factor * this._num_touch_meshes);
      flat_meshes.slice(num_cache_meshes).forEach(function (mnode) {
        return mnode.dispose();
      }); // assert: this._num_cache_meshes == num_cache_meshes
    }
  }, {
    key: "glenv",
    get: function get() {
      return this._glenv;
    }
    /**
     * DEM データプロバイダ
     * @type {mapray.DemProvider}
     * @readonly
     */

  }, {
    key: "dem_provider",
    get: function get() {
      return this._dem_provider;
    }
    /**
     * @summary Globe 状態を取得
     * @type {mapray.Globe.Status}
     * @readonly
     */

  }, {
    key: "status",
    get: function get() {
      return this._status;
    }
    /**
     * @summary DEM が更新された領域を取得
     * @type {mapray.UpdatedTileArea}
     * @readonly
     */

  }, {
    key: "dem_area_updated",
    get: function get() {
      return this._dem_area_updated;
    }
    /**
     * @summary 基底 Flake を取得
     * @type {mapray.Globe.Flake}
     * @readonly
     */

  }, {
    key: "root_flake",
    get: function get() {
      var flake = this._root_flake;
      flake.touch();
      return flake;
    }
  }]);

  return Globe;
}();
/**
 * @summary Globe 状態の列挙型
 * @enum {object}
 * @memberof mapray.Globe
 * @constant
 * @see mapray.Globe#status
 */


var Status = {
  /**
   * 準備中 (初期状態)
   */
  NOT_READY: {
    id: "NOT_READY"
  },

  /**
   * 準備完了
   */
  READY: {
    id: "READY"
  },

  /**
   * 失敗状態
   */
  FAILED: {
    id: "FAILED"
  }
};
Globe.Status = Status;
/**
 * @summary 地表断片
 * @memberof mapray.Globe
 * @private
 */

var Flake =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Globe.Flake} parent
   * @param {number}             z
   * @param {number}             x
   * @param {number}             y
   */
  function Flake(parent, z, x, y) {
    _classCallCheck(this, Flake);

    /**
     * @summary 地表分割レベル
     * @member mapray.Globe.Flake#z
     * @type {number}
     */
    this.z = z;
    /**
     * @summary 地表タイル X 座標
     * @member mapray.Globe.Flake#x
     * @type {number}
     */

    this.x = x;
    /**
     * @summary 地表タイル Y 座標
     * @member mapray.Globe.Flake#y
     * @type {number}
     */

    this.y = y; // Flake 階層

    this._parent = parent;
    this._children = [null, null, null, null];
    this._globe = parent !== null ? parent._globe : null; // DEM データ

    this._dem_data = null; // DEM バイナリ、または取り消しオブジェクト

    this._dem_state = DemState.NONE; // エンティティ辞書  Map.<mapray.Entity.FlakePrimitiveProducer, boolean>

    this._entity_map = null; // MeshNode

    this._meshes = []; // 標高代表値

    this._prev_Za_dem = null; // 前回の Za (DemBinary) だだし、標高代表が決定しているときは this

    this._prev_Zr_dem = null; // 前回の Zr (DemBinary)

    this._base_height = 0; // 平均標高 (h~)

    this._height_min = 0; // 最大標高 (h⇓)

    this._height_max = 0; // 最小標高 (h⇑)

    this._dem_zlimit = 0; // メッシュ生成時の DEM Z レベル上限 (Zb)
    // 境界箱 (AABB)

    this._gocs_x_min = 0;
    this._gocs_x_max = 0;
    this._gocs_y_min = 0;
    this._gocs_y_max = 0;
    this._gocs_z_min = 0;
    this._gocs_z_max = 0; // キャッシュ管理

    this._aframe = -1;

    if (this._globe !== null) {
      this._globe._num_cache_flakes += 1;
    }
  }
  /**
   * 基準の標高
   * @type {number}
   * @readonly
   */


  _createClass(Flake, [{
    key: "setupRoot",

    /**
     * @summary 基底 Flake 専用の設定
     * @package
     */
    value: function setupRoot(globe, dem) {
      this._globe = globe;
      this._dem_data = dem;
      this._dem_state = DemState.LOADED;
      this._entity_map = new Map();

      this._estimate();

      globe._num_cache_flakes += 1;
    }
    /**
     * @summary 子 Flake を取得または生成
     * @param  {number} u            子 Flake U 座標 (0 または 1)
     * @param  {number} v            子 Flake V 座標 (0 または 1)
     * @return {mapray.Globe.Flake}  子 Flake インスタンス
     */

  }, {
    key: "newChild",
    value: function newChild(u, v) {
      var index = u + 2 * v;
      var child = this._children[index];

      if (child === null) {
        // 存在しないときは Flake を生成する
        child = new Flake(this, this.z + 1, 2 * this.x + u, 2 * this.y + v);
        this._children[index] = child;
      }

      child._estimate();

      child.touch();
      return child;
    }
    /**
     * @summary カリングするか?
     * @param  {mapray.Vector4[]} clip_planes  クリップ平面配列
     * @return {boolean}                       見えないとき true, 見えるまたは不明のとき false
     */

  }, {
    key: "isInvisible",
    value: function isInvisible(clip_planes) {
      switch (this.z) {
        case 0:
          return this._isInvisible_0(clip_planes);

        default:
          return this._isInvisible_N(clip_planes);
      }
    }
    /**
     * @summary レンダリングオブジェクトを検索
     *
     * @param {number} lod  地表詳細レベル (LOD)
     *
     * @return {mapray.FlakeRenderObject}
     */

  }, {
    key: "getRenderObject",
    value: function getRenderObject(lod) {
      var η = Math.pow(2, -lod) * Flake.ε; // 2^-lod ε

      var cu; // 水平球面分割レベル

      if (η <= 2) {
        cu = Math.max(Math.ceil(GeoMath.LOG2PI - this.z - Math.maprayLog2(Math.acos(1 - η))), 0);
      } else {
        cu = 0;
      }

      var cosφ = this._getCosφ();

      var cv; // 垂直球面分割レベル

      if (η * cosφ <= 2) {
        cv = Math.max(Math.ceil(GeoMath.LOG2PI - this.z + Math.maprayLog2(cosφ / Math.acos(1 - η * cosφ))), 0);
      } else {
        cv = 0;
      }

      var node = this._getMeshNode(lod, cu, cv);

      node.touch();
      return node.getRenderObject();
    }
    /**
     * @summary this と交差する FlakePrimitiveProducer インスタンスの列挙子を取得
     *
     * @return {iterable.<mapray.Entity.FlakePrimitiveProducer>}
     */

  }, {
    key: "getEntityProducers",
    value: function getEntityProducers() {
      var entity_map = this._getEntityMap();

      return entity_map.keys();
    }
    /**
     * @summary Flake ツリーに producer を追加
     *
     * 事前条件:
     *   - this._entity_map !== null
     *   - this と this の子孫に producer が存在しない
     *
     * @param {mapray.Entity.FlakePrimitiveProducer} producer
     */

  }, {
    key: "addEntityProducer",
    value: function addEntityProducer(producer) {
      switch (producer.getAreaStatus(this)) {
        case Entity.AreaStatus.PARTIAL:
          {
            // エントリに producer を追加
            this._entity_map.set(producer, false); // this の子孫も同様の処理


            var _iteratorNormalCompletion3 = true;
            var _didIteratorError3 = false;
            var _iteratorError3 = undefined;

            try {
              for (var _iterator3 = this._children[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
                var child = _step3.value;

                if (child !== null && child._entity_map !== null) {
                  child.addEntityProducer(producer);
                }
              }
            } catch (err) {
              _didIteratorError3 = true;
              _iteratorError3 = err;
            } finally {
              try {
                if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
                  _iterator3["return"]();
                }
              } finally {
                if (_didIteratorError3) {
                  throw _iteratorError3;
                }
              }
            }
          }
          break;

        case Entity.AreaStatus.FULL:
          {
            this._addEntityFullProducer(producer);
          }
          break;
      }
    }
    /**
     * @summary Flake ツリーに producer を追加
     *
     * 事前条件:
     *   - producer.getAreaStatus( this ) === Entity.AreaStatus.FULL
     *   - this._entity_map !== null
     *   - this と this の子孫に producer が存在しない
     *
     * @param {mapray.Entity.FlakePrimitiveProducer} producer
     *
     * @private
     */

  }, {
    key: "_addEntityFullProducer",
    value: function _addEntityFullProducer(producer) {
      // エントリに producer を追加
      this._entity_map.set(producer, true); // this の子孫も同様の処理


      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = this._children[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var child = _step4.value;

          if (child !== null && child._entity_map !== null) {
            child._addEntityFullProducer(producer);
          }
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) {
            _iterator4["return"]();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }
    }
    /**
     * @summary Flake ツリーから producer を削除
     *
     * 事前条件:
     *   - this._entity_map !== null
     * 事後条件:
     *   - this と this の子孫に producer が存在しない
     *
     * @param {mapray.Entity.FlakePrimitiveProducer} producer
     */

  }, {
    key: "removeEntityProducer",
    value: function removeEntityProducer(producer) {
      if (!this._entity_map.has(producer)) {
        // もともと producer は this と this の子孫に存在しない
        return;
      } // エントリから producer を削除


      this._entity_map["delete"](producer); // this に producer に対応するメッシュが存在すれば削除


      this._removeEntityMeshes(producer); // this の子孫も同様の処理


      var _iteratorNormalCompletion5 = true;
      var _didIteratorError5 = false;
      var _iteratorError5 = undefined;

      try {
        for (var _iterator5 = this._children[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
          var child = _step5.value;

          if (child !== null && child._entity_map !== null) {
            child.removeEntityProducer(producer);
          }
        }
      } catch (err) {
        _didIteratorError5 = true;
        _iteratorError5 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion5 && _iterator5["return"] != null) {
            _iterator5["return"]();
          }
        } finally {
          if (_didIteratorError5) {
            throw _iteratorError5;
          }
        }
      }
    }
    /**
     * @summary Flake ツリーの producer を更新
     *
     * 事前条件:
     *   - this._entity_map !== null
     *
     * @param {mapray.Entity.FlakePrimitiveProducer} producer
     */

  }, {
    key: "updateEntityProducer",
    value: function updateEntityProducer(producer) {
      this.removeEntityProducer(producer);
      this.addEntityProducer(producer);
    }
    /**
     * @summary 地表断片とレイの交点までの距離を検索
     * <p>地表断片 this と線分 (ray.position を始点とし、そこから ray.direction 方向に limit 距離未満にある点) との交点の中で、始点から最も近い交点までの距離を返す。</p>
     * <p>ただし地表断片と線分が交差しないときは limit を返す。</p>
     * <p>事前条件: this._globe.status === Status.READY</p>
     * @param  {mapray.Ray} ray    ray.position を始点として ray.direction 方向に伸びる半直線
     * @param  {number}     limit  この距離までの交点を検索
     * @return {number}            ray.position から交点までの距離、ただし交差しなかったときは limit
     */

  }, {
    key: "findRayDistance",
    value: function findRayDistance(ray, limit) {
      var dem_flake;

      for (dem_flake = this; dem_flake._dem_state !== DemState.LOADED; dem_flake = dem_flake._parent) {}

      if (this.z - dem_flake.z === this._globe._ρ) {
        return this._findQuadRayDistance(ray, limit, dem_flake);
      } else if (this._cullForRayDistance(ray, limit)) {
        return limit;
      } else {
        var dmin = limit;

        for (var v = 0; v < 2; ++v) {
          for (var u = 0; u < 2; ++u) {
            dmin = this.newChild(u, v).findRayDistance(ray, dmin);
          }
        }

        return dmin;
      }
    }
    /**
     * @summary 自己と子孫を破棄
     */

  }, {
    key: "dispose",
    value: function dispose() {
      var i;
      var parent = this._parent;

      if (parent === null) {
        // すでに破棄済み
        return;
      }

      var globe = this._globe; // メッシュを破棄

      var meshes = this._meshes;

      while (meshes.length > 0) {
        meshes[0].dispose();
      } // 子孫 Flake を破棄


      var children = this._children;

      for (i = 0; i < 4; ++i) {
        var child = children[i];

        if (child !== null) {
          child.dispose();
        }
      } // 親 Flake から this を削除


      var pchildren = parent._children;

      for (i = 0; i < 4; ++i) {
        if (pchildren[i] === this) {
          pchildren[i] = null;
          break;
        }
      }

      this._parent = null; // DEM リクエストの取り消し

      if (this._dem_state === DemState.REQUESTED) {
        globe._dem_provider.cancelRequest(this._dem_data);

        --globe._num_dem_requesteds;
      } // Flake 数を減らす


      globe._num_cache_flakes -= 1;
    }
    /**
     * @summary 自己と子孫の Flake リストを取得
     * @return {array}
     * @package
     */

  }, {
    key: "flattenFlakes",
    value: function flattenFlakes() {
      var list = [];

      this._flattenFlakes(list);

      return list;
    }
    /**
     * @summary 自己と子孫の MeshNode リストを取得
     * @return {array}
     * @package
     */

  }, {
    key: "flattenMeshes",
    value: function flattenMeshes() {
      var list = [];

      this._flattenMeshes(list);

      return list;
    }
    /**
     * @summary 削減用の Flake 比較
     * @param  {mapray.Globe.Flake} other  比較対象
     * @return {number}                    比較値
     * @package
     */

  }, {
    key: "compareForReduce",
    value: function compareForReduce(other) {
      // 最近アクセスしたものを優先
      // 同じなら Z レベルが小さい方を優先
      var a = this;
      var b = other;
      var aframe = b._aframe - a._aframe;
      return aframe !== 0 ? aframe : a.z - b.z;
    }
    /**
     * @private
     */

  }, {
    key: "_flattenFlakes",
    value: function _flattenFlakes(list) {
      list.push(this);
      var children = this._children;

      for (var i = 0; i < 4; ++i) {
        var child = children[i];

        if (child !== null) {
          child._flattenFlakes(list);
        }
      }
    }
    /**
     * @private
     */

  }, {
    key: "_flattenMeshes",
    value: function _flattenMeshes(list) {
      Array.prototype.push.apply(list, this._meshes);
      var children = this._children;

      for (var i = 0; i < 4; ++i) {
        var child = children[i];

        if (child !== null) {
          child._flattenMeshes(list);
        }
      }
    }
    /**
     * @summary アクセスフレームを更新
     * @package
     */

  }, {
    key: "touch",
    value: function touch() {
      var globe = this._globe;

      if (this._aframe !== globe._frame_counter) {
        this._aframe = globe._frame_counter;
        globe._num_touch_flakes += 1;
      }
    }
    /**
     * @summary メッシュノードを取得
     *
     * @param {number} lod  地表詳細レベル (LOD)
     * @param {number} cu   水平球面分割レベル
     * @param {number} cv   垂直球面分割レベル
     *
     * @return {mapray.Globe.MeshNode}  メッシュノード
     *
     * @private
     */

  }, {
    key: "_getMeshNode",
    value: function _getMeshNode(lod, cu, cv) {
      var dem = this._getMeshDemBinary(lod);

      var dpows = dem.getDivisionPowers(this, lod, cu, cv); // キャッシュに存在すれば、それを返す

      var meshes = this._meshes;
      var length = meshes.length;

      for (var i = 0; i < length; ++i) {
        var item = meshes[i];

        if (item.match(dem, dpows)) {
          return item;
        }
      } // キャッシュに存在しないので新規に生成


      var node = new MeshNode(this, dem, dpows);
      meshes.unshift(node); // 検索効率のため先頭に追加

      return node;
    }
    /**
     * @summary メッシュ用の DEM バイナリを取得
     * @param  {number} lod        地表詳細レベル (LOD)
     * @return {mapray.DemBinary}  DEM タイルデータ
     * @private
     */

  }, {
    key: "_getMeshDemBinary",
    value: function _getMeshDemBinary(lod) {
      var zDesired = GeoMath.clamp(Math.round(lod + this._globe._dem_zbias), 0, this._dem_zlimit);

      var dem = this._findNearestDemTile(zDesired); // 上のレベルの DEM をリクエスト


      if (dem.z < zDesired) {
        var qlevel = dem.getQuadLevel(this.z, this.x, this.y);

        if (qlevel > 0) {
          this._requestAncestorDemTile(Math.min(dem.z + qlevel, zDesired));
        }
      }

      return dem;
    }
    /**
     * @summary 先祖 DEM タイルデータを検索
     * @desc
     * <p>this の (レベルが zlimit またはそれ以下の) 祖先の中で、現在キャッシュに存在する最大レベルの DEM タイルデータを検索する。</p>
     * @param  {number} zlimit     先祖レベルの上限
     * @return {mapray.DemBinary}  先祖 DEM タイルデータ
     */

  }, {
    key: "_findNearestDemTile",
    value: function _findNearestDemTile(zlimit) {
      var flake = this; // zlimit の地表断片を検索

      var count = this.z - zlimit;

      for (var i = 0; i < count; ++i) {
        flake = flake._parent;
      } // 次の DemBinary を持つ地表断片を検索


      while (flake._dem_state !== DemState.LOADED) {
        flake = flake._parent;
      } // 見つけた地表断片の DemBinary を返す


      return flake._dem_data;
    }
    /**
     * @summary 地表断片を包含する DEM タイルデータを要求
     * @desc
     * <p>this を包含または this と一致する、ズームレベル ze の DEM タイルをサーバーに要求する。</p>
     * <p>ただしすでにキャッシュにその DEM タイルが存在、または REQUESTED 状態のときは要求しない。</p>
     * <p>FAILED 状態かつ ze > 0 のときは、再帰的に ze - 1 を要求する。</p>
     * <p>要求が最大数に達しているときは無視する。</p>
     * @param {number} ze  DEM ズームレベル
     */

  }, {
    key: "_requestAncestorDemTile",
    value: function _requestAncestorDemTile(ze) {
      var globe = this._globe;

      if (globe._num_dem_requesteds >= globe._max_dem_requesteds) {
        // 要求が最大数に達しているので受け入れない
        return;
      }

      var flake = this; // zlimit の地表断片を検索

      var count = this.z - ze;

      for (var i = 0; i < count; ++i) {
        flake = flake._parent;
      }

      while (true) {
        var state = flake._dem_state;

        if (state === DemState.LOADED || state === DemState.REQUESTED) {
          // 要求する必要がない
          break;
        } else if (state === DemState.FAILED) {
          // 親でリトライ
          flake = flake._parent;
          continue;
        } else {
          // DEM タイルデータを要求
          // assert: state === DemState.NONE
          var provider = globe._dem_provider;
          flake._dem_data = provider.requestTile(flake.z, flake.x, flake.y, function (data) {
            if (flake._parent === null) {
              // すでに破棄済みなので無視
              return;
            }

            if (data) {
              flake._dem_data = new DemBinary(flake.z, flake.x, flake.y, globe._ρ, data);
              flake._dem_state = DemState.LOADED;

              globe._dem_area_updated.addTileArea(flake);
            } else {
              // データ取得に失敗
              flake._dem_data = null;
              flake._dem_state = DemState.FAILED;
            }

            --globe._num_dem_requesteds;
          });
          flake._dem_state = DemState.REQUESTED;
          ++globe._num_dem_requesteds;
          break;
        }
      }
    }
    /**
     * @private
     */

  }, {
    key: "_isInvisible_0",
    value: function _isInvisible_0(clip_planes) {
      var r = GeoMath.EARTH_RADIUS + this._height_max;

      for (var i = 0; i < clip_planes.length; ++i) {
        var dist = clip_planes[i][3]; // 平面から GOCS 原点 (地球中心) までの距離

        if (dist < -r) {
          // 地球全体がこの平面の裏側にあるので見えない
          return true;
        }
      }

      return false; // 見えている可能性がある
    }
    /**
     * @private
     */

  }, {
    key: "_isInvisible_N",
    value: function _isInvisible_N(clip_planes) {
      var xmin = this._gocs_x_min;
      var xmax = this._gocs_x_max;
      var ymin = this._gocs_y_min;
      var ymax = this._gocs_y_max;
      var zmin = this._gocs_z_min;
      var zmax = this._gocs_z_max;

      for (var i = 0; i < clip_planes.length; ++i) {
        var p = clip_planes[i];
        var px = p[0];
        var py = p[1];
        var pz = p[2];
        var pw = p[3]; // 以下がすべて成り立つとボックス全体は平面の裏側にある
        //   px*xmin + py*ymin + pz*zmin + pw < 0
        //   px*xmax + py*ymin + pz*zmin + pw < 0
        //   px*xmin + py*ymax + pz*zmin + pw < 0
        //   px*xmax + py*ymax + pz*zmin + pw < 0
        //   px*xmin + py*ymin + pz*zmax + pw < 0
        //   px*xmax + py*ymin + pz*zmax + pw < 0
        //   px*xmin + py*ymax + pz*zmax + pw < 0
        //   px*xmax + py*ymax + pz*zmax + pw < 0

        var c0 = px * xmin + py * ymin;
        var c1 = px * xmax + py * ymin;
        var c2 = px * xmin + py * ymax;
        var c3 = px * xmax + py * ymax;
        var c4 = -pz * zmin - pw;
        var c5 = -pz * zmax - pw;

        if (c0 < c4 && c1 < c4 && c2 < c4 && c3 < c4 && c0 < c5 && c1 < c5 && c2 < c5 && c3 < c5) {
          // ボックス全体が平面の裏側にあるので見えない
          return true;
        }
      }

      return false; // 見えている可能性がある
    }
    /**
     * @summary 中間緯度の余弦
     * @return {number}
     * @private
     */

  }, {
    key: "_getCos\u03C6",
    value: function _getCos() {
      var z = this.z;

      if (z > 0) {
        var y = this.y;
        var p = Math.pow(2, 1 - z);
        var y0 = Math.abs(1 - p * y);
        var y1 = Math.abs(1 - p * (y + 1));
        var ey = Math.exp(Math.PI * Math.min(y0, y1));
        return 2 * ey / (ey * ey + 1); // Cos[φ] == Cos[gd[y]] == Sech[y]
      } else {
        // z == 0 のときは φ == 0 とする
        return 1; // Cos[0]
      }
    }
    /**
     * @summary 標高代表値と境界箱を更新
     * @private
     */

  }, {
    key: "_estimate",
    value: function _estimate() {
      if (this._prev_Za_dem === this) {
        // 代表値は決定済みなので何もしない
        return;
      }

      var zg = this.z;
      var ρ = this._globe._ρ;
      var zr_dem;

      if (zg < ρ) {
        zr_dem = this._findNearestDemTile(zg);

        if (zr_dem === this._prev_Zr_dem) {
          // 前回と代表値が変わらないので何もしない
          return;
        }

        this._prev_Zr_dem = zr_dem;

        this._estimate_low(zr_dem);

        this._dem_zlimit = zg;
      } else {
        var za_dem = this._findNearestDemTile(zg - ρ);

        if (za_dem.isLeaf(zg, this.x, this.y)) {
          this._estimate_leaf(za_dem);
        } else {
          zr_dem = this._findNearestDemTile(za_dem.z + ρ);

          if (za_dem === this._prev_Za_dem && zr_dem === this._prev_Zr_dem) {
            // 前回と代表値が変わらないので何もしない
            return;
          }

          this._prev_Za_dem = za_dem;
          this._prev_Zr_dem = zr_dem;

          this._estimate_high(za_dem, zr_dem);
        }

        this._dem_zlimit = za_dem.z + ρ;
      } // 境界箱の更新


      switch (zg) {
        case 0:
          this._updataBoundingBox_0();

          break;

        case 1:
          this._updataBoundingBox_1();

          break;

        default:
          this._updataBoundingBox_N();

          break;
      }
    }
    /**
     * @summary 標高代表値を計算 (Zg < ρ)
     * @param {mapray.DemBinary} zr_dem  レベルが Zr の DEM
     * @private
     */

  }, {
    key: "_estimate_low",
    value: function _estimate_low(zr_dem) {
      var zg = this.z;
      var xg = this.x;
      var yg = this.y;

      var α = this._calcAlpha();

      this._base_height = this._globe._avg_height.sample(zg, xg, yg);
      this._height_min = Math.max(this._base_height + α * Flake.Fm, zr_dem.height_min);
      this._height_max = Math.min(this._base_height + α * Flake.Fp, zr_dem.height_max);

      if (zr_dem.z == zg || zr_dem.isLeaf(zg, xg, yg)) {
        // 標高代表値が確定した
        this._prev_Za_dem = this;
      }
    }
    /**
     * @summary 標高代表値を計算 (Zg >= ρ && !L(Za))
     * @param {mapray.DemBinary} za_dem  レベルが Za の DEM
     * @param {mapray.DemBinary} zr_dem  レベルが Zr の DEM
     * @private
     */

  }, {
    key: "_estimate_high",
    value: function _estimate_high(za_dem, zr_dem) {
      var globe = this._globe;
      var zg = this.z;
      var xg = this.x;
      var yg = this.y;
      var ze = za_dem.z; // -> za

      var xe = za_dem.x;
      var ye = za_dem.y;
      var ρ = globe._ρ;
      var pow = Math.pow(2, ze - zg);
      var size = 1 << ρ;
      var u = Math.floor(size * ((xg + 0.5) * pow - xe));
      var v = Math.floor(size * ((yg + 0.5) * pow - ye));
      var smin = size * (xg * pow - xe) - u;
      var smax = size * ((xg + 1) * pow - xe) - u;
      var tmin = size * (yg * pow - ye) - v;
      var tmax = size * ((yg + 1) * pow - ye) - v;
      var heights = za_dem.getHeights(u, v);
      var h00 = heights[0];
      var h10 = heights[1];
      var h01 = heights[2];
      var h11 = heights[3];
      var h0 = (h00 * (1 - smin) + h10 * smin) * (1 - tmin) + (h01 * (1 - smin) + h11 * smin) * tmin;
      var h1 = (h00 * (1 - smax) + h10 * smax) * (1 - tmin) + (h01 * (1 - smax) + h11 * smax) * tmin;
      var h2 = (h00 * (1 - smin) + h10 * smin) * (1 - tmax) + (h01 * (1 - smin) + h11 * smin) * tmax;
      var h3 = (h00 * (1 - smax) + h10 * smax) * (1 - tmax) + (h01 * (1 - smax) + h11 * smax) * tmax;

      var α = this._calcAlpha();

      this._base_height = 0.25 * (h0 + h1 + h2 + h3);
      this._height_min = Math.max(this._base_height + α * Flake.Fm, zr_dem.height_min);
      this._height_max = Math.min(this._base_height + α * Flake.Fp, zr_dem.height_max);

      if (ze < zg - ρ) {
        // 上のレベルの DEM をリクエスト
        var qlevel = za_dem.getQuadLevel(zg, xg, yg); // assert: qlevel > 0

        this._requestAncestorDemTile(Math.min(ze + qlevel, zg - ρ));
      } else if (zr_dem.z == zg || zr_dem.isLeaf(zg, xg, yg)) {
        // 標高代表値が確定した
        // assert: ze == zg - ρ
        this._prev_Za_dem = this;
      }
    }
    /**
     * @summary 標高代表値を計算 (Zg >= ρ && L(Za))
     * @param {mapray.DemBinary} za_dem  レベルが Za の DEM
     * @private
     */

  }, {
    key: "_estimate_leaf",
    value: function _estimate_leaf(za_dem) {
      var zg = this.z;
      var xg = this.x;
      var yg = this.y;
      var ze = za_dem.z; // -> za

      var xe = za_dem.x;
      var ye = za_dem.y;
      var pow = Math.pow(2, ze - zg);
      var size = 1 << this._globe._ρ;
      var u = Math.floor(size * ((xg + 0.5) * pow - xe));
      var v = Math.floor(size * ((yg + 0.5) * pow - ye));
      var smin = size * (xg * pow - xe) - u;
      var smax = size * ((xg + 1) * pow - xe) - u;
      var tmin = size * (yg * pow - ye) - v;
      var tmax = size * ((yg + 1) * pow - ye) - v;
      var heights = za_dem.getHeights(u, v);
      var h00 = heights[0];
      var h10 = heights[1];
      var h01 = heights[2];
      var h11 = heights[3]; // Hi = Di( Za )

      var h0 = (h00 * (1 - smin) + h10 * smin) * (1 - tmin) + (h01 * (1 - smin) + h11 * smin) * tmin;
      var h1 = (h00 * (1 - smax) + h10 * smax) * (1 - tmin) + (h01 * (1 - smax) + h11 * smax) * tmin;
      var h2 = (h00 * (1 - smin) + h10 * smin) * (1 - tmax) + (h01 * (1 - smin) + h11 * smin) * tmax;
      var h3 = (h00 * (1 - smax) + h10 * smax) * (1 - tmax) + (h01 * (1 - smax) + h11 * smax) * tmax;
      this._base_height = 0.25 * (h0 + h1 + h2 + h3);
      this._height_min = Math.min(h0, h1, h2, h3);
      this._height_max = Math.max(h0, h1, h2, h3); // 標高代表値が確定した

      this._prev_Za_dem = this;
    }
    /**
     * @summary α を計算
     * @desc
     * <p>中間緯度の標高 0 での緯線の長さを示す値 α を計算する。</p>
     * @return {number}  α
     * @private
     */

  }, {
    key: "_calcAlpha",
    value: function _calcAlpha() {
      var pow = Math.pow(2, 1 - this.z);
      return pow * Flake.πr / Math.cosh((1 - pow * (this.y + 0.5)) * Math.PI);
    }
    /**
     * @summary 境界箱を更新 (Z == 0)
     */

  }, {
    key: "_updataBoundingBox_0",
    value: function _updataBoundingBox_0() {
      var r = GeoMath.EARTH_RADIUS + this._height_max;
      this._gocs_x_min = -r;
      this._gocs_x_max = r;
      this._gocs_y_min = -r;
      this._gocs_y_max = r;
      this._gocs_z_min = -r;
      this._gocs_z_max = r;
    }
    /**
     * @summary 境界箱を更新 (Z == 1)
     */

  }, {
    key: "_updataBoundingBox_1",
    value: function _updataBoundingBox_1() {
      var r = GeoMath.EARTH_RADIUS + this._height_max;
      var x = this.x;
      var y = this.y;
      this._gocs_x_min = -r;
      this._gocs_x_max = r;
      this._gocs_y_min = r * (x - 1);
      this._gocs_y_max = r * x;
      this._gocs_z_min = -r * y;
      this._gocs_z_max = r * (1 - y);
    }
    /**
     * @summary 境界箱を更新 (Z >= 2)
     */

  }, {
    key: "_updataBoundingBox_N",
    value: function _updataBoundingBox_N() {
      var pi = Math.PI;
      var z = this.z;
      var x = this.x;
      var y = this.y; // 座標範囲 (単位球メルカトル座標系)

      var msize = Math.pow(2, 1 - z) * pi;
      var mx_min = -pi + x * msize;
      var mx_max = -pi + (x + 1) * msize;
      var my_min = pi - (y + 1) * msize;
      var my_max = pi - y * msize; // 事前計算変数

      var λmin = mx_min;
      var λmax = mx_max;
      var emin = Math.exp(my_min); // Exp[my_min]

      var emax = Math.exp(my_max); // Exp[my_max]

      var e2min = emin * emin; // Exp[my_min]^2

      var e2max = emax * emax; // Exp[my_max]^2
      // 座標範囲 (地心直交座標系)
      //
      // z >= 2 のとき、λとφの範囲は以下の区間のどれかに入る
      //   φ:                (-π/2, 0] [0, π/2)
      //   λ:   [-π, -π/2] [-π/2, 0] [0, π/2] [π/2, π]
      //
      // 区間ごとの関数の変化 (各区間で単調増加または単調減少)
      //   Sin[φ]:            (-1 → 0] [0 → 1)
      //   Cos[φ]:            ( 0 → 1] [1 → 0)
      //   Sin[λ]: [ 0 → -1] [-1 → 0] [0 → 1] [1 →  0]
      //   Cos[λ]: [-1 →  0] [ 0 → 1] [1 → 0] [0 → -1]

      var rmin = GeoMath.EARTH_RADIUS + this._height_min;
      var rmax = GeoMath.EARTH_RADIUS + this._height_max;
      var cosφmin = 2 * emin / (e2min + 1);
      var cosφmax = 2 * emax / (e2max + 1); // gx = r Cos[φ] Cos[λ]
      // gy = r Cos[φ] Sin[λ]
      // gz = r Sin[φ]

      if (my_min + my_max < 0) {
        // φ : (-π/2, 0]
        if (λmin + λmax < -pi) {
          // λ : [-π, -π/2]
          this._gocs_x_min = rmax * cosφmax * Math.cos(λmin);
          this._gocs_x_max = rmin * cosφmin * Math.cos(λmax);
          this._gocs_y_min = rmax * cosφmax * Math.sin(λmax);
          this._gocs_y_max = rmin * cosφmin * Math.sin(λmin);
        } else if (λmin + λmax < 0) {
          // λ : [-π/2, 0]
          this._gocs_x_min = rmin * cosφmin * Math.cos(λmin);
          this._gocs_x_max = rmax * cosφmax * Math.cos(λmax);
          this._gocs_y_min = rmax * cosφmax * Math.sin(λmin);
          this._gocs_y_max = rmin * cosφmin * Math.sin(λmax);
        } else if (λmin + λmax < pi) {
          // λ : [0, π/2]
          this._gocs_x_min = rmin * cosφmin * Math.cos(λmax);
          this._gocs_x_max = rmax * cosφmax * Math.cos(λmin);
          this._gocs_y_min = rmin * cosφmin * Math.sin(λmin);
          this._gocs_y_max = rmax * cosφmax * Math.sin(λmax);
        } else {
          // λ : [π/2, π]
          this._gocs_x_min = rmax * cosφmax * Math.cos(λmax);
          this._gocs_x_max = rmin * cosφmin * Math.cos(λmin);
          this._gocs_y_min = rmin * cosφmin * Math.sin(λmax);
          this._gocs_y_max = rmax * cosφmax * Math.sin(λmin);
        }

        this._gocs_z_min = rmax * (e2min - 1) / (e2min + 1);
        this._gocs_z_max = rmin * (e2max - 1) / (e2max + 1);
      } else {
        // φ : [0, π/2)
        if (λmin + λmax < -pi) {
          // λ : [-π, -π/2]
          this._gocs_x_min = rmax * cosφmin * Math.cos(λmin);
          this._gocs_x_max = rmin * cosφmax * Math.cos(λmax);
          this._gocs_y_min = rmax * cosφmin * Math.sin(λmax);
          this._gocs_y_max = rmin * cosφmax * Math.sin(λmin);
        } else if (λmin + λmax < 0) {
          // λ : [-π/2, 0]
          this._gocs_x_min = rmin * cosφmax * Math.cos(λmin);
          this._gocs_x_max = rmax * cosφmin * Math.cos(λmax);
          this._gocs_y_min = rmax * cosφmin * Math.sin(λmin);
          this._gocs_y_max = rmin * cosφmax * Math.sin(λmax);
        } else if (λmin + λmax < pi) {
          // λ : [0, π/2]
          this._gocs_x_min = rmin * cosφmax * Math.cos(λmax);
          this._gocs_x_max = rmax * cosφmin * Math.cos(λmin);
          this._gocs_y_min = rmin * cosφmax * Math.sin(λmin);
          this._gocs_y_max = rmax * cosφmin * Math.sin(λmax);
        } else {
          // λ : [π/2, π]
          this._gocs_x_min = rmax * cosφmin * Math.cos(λmax);
          this._gocs_x_max = rmin * cosφmax * Math.cos(λmin);
          this._gocs_y_min = rmin * cosφmax * Math.sin(λmax);
          this._gocs_y_max = rmax * cosφmin * Math.sin(λmin);
        }

        this._gocs_z_min = rmin * (e2min - 1) / (e2min + 1);
        this._gocs_z_max = rmax * (e2max - 1) / (e2max + 1);
      }
    }
    /**
     * サーバーにさらに正確度が高い DEM タイルデータが存在すれば、それをリクエストする。
     * @param  {number} xt  X 座標 (基底タイル座標系)
     * @param  {number} yt  Y 座標 (基底タイル座標系)
     * @private
     */

  }, {
    key: "_requestHighestAccuracy",
    value: function _requestHighestAccuracy(xt, yt) {
      var qlevel = this._dem_data.getQuadLevelDirect(xt, yt);

      if (qlevel == 0) {
        // さらに正確度が高い DEM タイルデータは存在しない
        return;
      }

      var flake = this;
      var size = Math.round(Math.pow(2, this.z + 1));
      var xf = size * xt;
      var yf = size * yt;

      for (var i = 0; i < qlevel; ++i) {
        var u = GeoMath.clamp(Math.floor(xf), 0, size - 1) % 2;
        var v = GeoMath.clamp(Math.floor(yf), 0, size - 1) % 2;
        flake = flake.newChild(u, v);
        size *= 2;
        xf *= 2;
        yf *= 2;
      }

      flake._requestAncestorDemTile(flake.z);
    }
    /**
     * @summary 地表断片とレイの交点までの距離を検索
     * <p>地表断片 this と線分 (ray.position を始点とし、そこから ray.direction 方向に limit 距離未満にある点) との交点までの距離を返す。</p>
     * <p>ただし地表断片と線分が交差しないときは limit を返す。</p>
     * @private
     */

  }, {
    key: "_findQuadRayDistance",
    value: function _findQuadRayDistance(ray, limit, dem_flake) {
      var pts = this._getQuadPositions(dem_flake, Flake._temp_positions);

      var dist = Flake._findTriRayDistance(ray, limit, pts[0], pts[2], pts[1]);

      return dist === limit ? Flake._findTriRayDistance(ray, limit, pts[1], pts[2], pts[3]) : dist;
    }
    /**
     * @summary 三角形とレイの交点までの距離を検索
     * <p>三角形 p0, p1, p2 と線分 (ray.position を始点とし、そこから ray.direction 方向に limit 距離未満にある点) との交点までの距離を返す。</p>
     * <p>ただし地表断片と線分が交差しないときは limit を返す。</p>
     * @private
     */

  }, {
    key: "_getQuadPositions",

    /**
     * @summary 四隅の位置を取得
     * @param  {mapray.Globe.Flake} dem_flake  DEM の地表断片
     * @param  {array}              positions  結果の格納先
     * @return {array}                         positions = [左上, 右上, 左下, 右下]
     * @private
     */
    value: function _getQuadPositions(dem_flake, positions) {
      var xg = this.x;
      var yg = this.y;
      var xe = dem_flake.x;
      var ye = dem_flake.y;
      var size = 1 << this._globe._ρ;

      var heights = dem_flake._dem_data.getHeights(xg - size * xe, yg - size * ye);

      var msize = Math.pow(2, 1 - this.z) * Math.PI;
      var mx0 = xg * msize - Math.PI;
      var my0 = Math.PI - yg * msize;

      for (var iv = 0, my = my0; iv < 2; ++iv, my -= msize) {
        var ey = Math.exp(my);
        var ey2 = ey * ey;
        var sinφ = (ey2 - 1) / (ey2 + 1);
        var cosφ = 2 * ey / (ey2 + 1);

        for (var iu = 0, mx = mx0; iu < 2; ++iu, mx += msize) {
          var index = iu + 2 * iv;
          var radius = GeoMath.EARTH_RADIUS + heights[index];
          var sinλ = Math.sin(mx);
          var cosλ = Math.cos(mx);
          var pos = positions[index];
          pos[0] = radius * cosφ * cosλ;
          pos[1] = radius * cosφ * sinλ;
          pos[2] = radius * sinφ;
        }
      }

      return positions;
    }
    /**
     * @summary 地表断片とレイの交点までの距離を検索
     * <p>地表断片 this と線分 (ray.position を始点とし、そこから ray.direction 方向に limit 距離未満にある点) が交差しないときは true, 交差するまたは不明のとき false を返す。
     * @private
     */

  }, {
    key: "_cullForRayDistance",
    value: function _cullForRayDistance(ray, limit) {
      var q = ray.position;
      var qx = q[0];
      var qy = q[1];
      var qz = q[2];
      var xmin = this._gocs_x_min;
      var xmax = this._gocs_x_max;
      var ymin = this._gocs_y_min;
      var ymax = this._gocs_y_max;
      var zmin = this._gocs_z_min;
      var zmax = this._gocs_z_max;

      if (xmin <= qx && qx <= xmax && ymin <= qy && qy <= ymax && zmin <= qz && qz <= zmax) {
        // ray の始点が AABB の表面または内部 -> 交差する可能性がある
        return false;
      }

      var v = ray.direction;
      var vx = v[0];
      var vy = v[1];
      var vz = v[2];
      var t;
      var px;
      var py;
      var pz; // yz

      if (qx < xmin && vx > 0) {
        t = (xmin - qx) / vx;

        if (t < limit) {
          py = qy + t * vy;
          pz = qz + t * vz;

          if (ymin <= py && py <= ymax && zmin <= pz && pz <= zmax) {
            // ray 線分は AABB の xmin 面内で交差
            return false;
          }
        }
      } else if (qx > xmax && vx < 0) {
        t = (xmax - qx) / vx;

        if (t < limit) {
          py = qy + t * vy;
          pz = qz + t * vz;

          if (ymin <= py && py <= ymax && zmin <= pz && pz <= zmax) {
            // ray 線分は AABB の xmax 面内で交差
            return false;
          }
        }
      } // xz


      if (qy < ymin && vy > 0) {
        t = (ymin - qy) / vy;

        if (t < limit) {
          px = qx + t * vx;
          pz = qz + t * vz;

          if (xmin <= px && px <= xmax && zmin <= pz && pz <= zmax) {
            // ray 線分は AABB の ymin 面内で交差
            return false;
          }
        }
      } else if (qy > ymax && vy < 0) {
        t = (ymax - qy) / vy;

        if (t < limit) {
          px = qx + t * vx;
          pz = qz + t * vz;

          if (xmin <= px && px <= xmax && zmin <= pz && pz <= zmax) {
            // ray 線分は AABB の ymax 面内で交差
            return false;
          }
        }
      } // xy


      if (qz < zmin && vz > 0) {
        t = (zmin - qz) / vz;

        if (t < limit) {
          px = qx + t * vx;
          py = qy + t * vy;

          if (xmin <= px && px <= xmax && ymin <= py && py <= ymax) {
            // ray 線分は AABB の zmin 面内で交差
            return false;
          }
        }
      } else if (qz > zmax && vz < 0) {
        t = (zmax - qz) / vz;

        if (t < limit) {
          px = qx + t * vx;
          py = qy + t * vy;

          if (xmin <= px && px <= xmax && ymin <= py && py <= ymax) {
            // ray 線分は AABB の zmax 面内で交差
            return false;
          }
        }
      } // ray 線分と AABB は交差しない


      return true;
    }
    /**
     * @summary エンティティのメッシュを削除
     *
     * @param {mapray.Entity.FlakePrimitiveProducer} producer
     *
     * @private
     */

  }, {
    key: "_removeEntityMeshes",
    value: function _removeEntityMeshes(producer) {
      var _iteratorNormalCompletion6 = true;
      var _didIteratorError6 = false;
      var _iteratorError6 = undefined;

      try {
        for (var _iterator6 = this._meshes[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
          var node = _step6.value;
          node.removeEntityMesh(producer);
        }
      } catch (err) {
        _didIteratorError6 = true;
        _iteratorError6 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion6 && _iterator6["return"] != null) {
            _iterator6["return"]();
          }
        } finally {
          if (_didIteratorError6) {
            throw _iteratorError6;
          }
        }
      }
    }
    /**
     * @summary エンティティ辞書を取得
     *
     * @return {Map.<mapray.Entity.FlakePrimitiveProducer, boolean>}
     *
     * @private
     */

  }, {
    key: "_getEntityMap",
    value: function _getEntityMap() {
      if (this._entity_map === null) {
        // 存在しないので新たに生成する
        var parent_map = this._parent._getEntityMap(); // 親の辞書


        var entity_map = new Map();
        var _iteratorNormalCompletion7 = true;
        var _didIteratorError7 = false;
        var _iteratorError7 = undefined;

        try {
          for (var _iterator7 = parent_map[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
            var _step7$value = _slicedToArray(_step7.value, 2),
                producer = _step7$value[0],
                isfull = _step7$value[1];

            if (isfull) {
              // 親が FULL なので、子も FULL
              entity_map.set(producer, true);
            } else {
              switch (producer.getAreaStatus(this)) {
                case Entity.AreaStatus.PARTIAL:
                  entity_map.set(producer, false);
                  break;

                case Entity.AreaStatus.FULL:
                  entity_map.set(producer, true);
                  break;

                default:
                  // Entity.AreaStatus.EMPTY
                  break;
              }
            }
          }
        } catch (err) {
          _didIteratorError7 = true;
          _iteratorError7 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion7 && _iterator7["return"] != null) {
              _iterator7["return"]();
            }
          } finally {
            if (_didIteratorError7) {
              throw _iteratorError7;
            }
          }
        }

        this._entity_map = entity_map;
      }

      return this._entity_map;
    }
  }, {
    key: "base_height",
    get: function get() {
      return this._base_height;
    }
    /**
     * 最小の標高
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_min",
    get: function get() {
      return this._height_min;
    }
    /**
     * 最大の標高
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_max",
    get: function get() {
      return this._height_max;
    }
  }], [{
    key: "_findTriRayDistance",
    value: function _findTriRayDistance(ray, limit, p0, p1, p2) {
      var v = ray.direction; // P1 - P0

      var p1_p0 = Flake._temp_ray_1;
      p1_p0[0] = p1[0] - p0[0];
      p1_p0[1] = p1[1] - p0[1];
      p1_p0[2] = p1[2] - p0[2]; // P2 - P0

      var p2_p0 = Flake._temp_ray_2;
      p2_p0[0] = p2[0] - p0[0];
      p2_p0[1] = p2[1] - p0[1];
      p2_p0[2] = p2[2] - p0[2]; // N = (P1 − P0) × (P2 − P0)

      var n = GeoMath.cross3(p1_p0, p2_p0, Flake._temp_ray_3); // N . V

      var nv = GeoMath.dot3(n, v);

      if (nv < 0) {
        var q = ray.position; // P0 - Q

        var p0_q = Flake._temp_ray_4;
        p0_q[0] = p0[0] - q[0];
        p0_q[1] = p0[1] - q[1];
        p0_q[2] = p0[2] - q[2]; //      N . (P0 - Q)
        // t = --------------
        //         N . V

        var t = GeoMath.dot3(n, p0_q) / nv;

        if (t >= 0 && t < limit) {
          // P = Q + t V
          var p = Flake._temp_ray_5;
          p[0] = q[0] + t * v[0];
          p[1] = q[1] + t * v[1];
          p[2] = q[2] + t * v[2]; // P0 - P

          var p0_p = Flake._temp_ray_6;
          p0_p[0] = p0[0] - p[0];
          p0_p[1] = p0[1] - p[1];
          p0_p[2] = p0[2] - p[2]; // P1 - P

          var p1_p = Flake._temp_ray_7;
          p1_p[0] = p1[0] - p[0];
          p1_p[1] = p1[1] - p[1];
          p1_p[2] = p1[2] - p[2]; // P2 - P

          var p2_p = Flake._temp_ray_8;
          p2_p[0] = p2[0] - p[0];
          p2_p[1] = p2[1] - p[1];
          p2_p[2] = p2[2] - p[2]; // ((P0 - P) × (P1 - P)) . N >= 0
          // ((P1 - P) × (P2 - P)) . N >= 0
          // ((P2 - P) × (P0 - P)) . N >= 0

          if (GeoMath.dot3(GeoMath.cross3(p0_p, p1_p, Flake._temp_ray_9), n) >= 0 && GeoMath.dot3(GeoMath.cross3(p1_p, p2_p, Flake._temp_ray_10), n) >= 0 && GeoMath.dot3(GeoMath.cross3(p2_p, p0_p, Flake._temp_ray_11), n) >= 0) {
            return t;
          }
        }
      }

      return limit;
    }
  }]);

  return Flake;
}();
/**
 * @summary 球面分割数の係数
 * @type {number}
 * @constant
 */


Flake.ε = 0.0625;
/**
 * @summary 標高下限係数
 * @type {number}
 * @constant
 */

Flake.Fm = -2.0;
/**
 * @summary 標高上限係数
 * @type {number}
 * @constant
 */

Flake.Fp = 2.0;
Flake.πr = Math.PI * GeoMath.EARTH_RADIUS;

Flake._temp_positions = function () {
  var p = [];

  for (var i = 0; i < 4; ++i) {
    p.push(GeoMath.createVector3());
  }

  return p;
}();

Flake._temp_ray_1 = GeoMath.createVector3();
Flake._temp_ray_2 = GeoMath.createVector3();
Flake._temp_ray_3 = GeoMath.createVector3();
Flake._temp_ray_4 = GeoMath.createVector3();
Flake._temp_ray_5 = GeoMath.createVector3();
Flake._temp_ray_6 = GeoMath.createVector3();
Flake._temp_ray_7 = GeoMath.createVector3();
Flake._temp_ray_8 = GeoMath.createVector3();
Flake._temp_ray_9 = GeoMath.createVector3();
Flake._temp_ray_10 = GeoMath.createVector3();
Flake._temp_ray_11 = GeoMath.createVector3();
/**
 * @summary 履歴統計
 * @memberof mapray.Globe
 * @private
 */

var HistStats =
/*#__PURE__*/
function () {
  function HistStats() {
    _classCallCheck(this, HistStats);

    this._history = [];
    this._max_value = 0;
    this._hsize = 200; // >= 3
  }
  /**
   * @summary 最大値を取得
   */


  _createClass(HistStats, [{
    key: "getMaxValue",
    value: function getMaxValue(value) {
      var history = this._history;
      var old_max = this._max_value;

      if (history.length < this._hsize) {
        // 追加のみ
        if (value > old_max) {
          this._max_value = value;
        }
      } else {
        // 追加と削除
        if (value >= old_max) {
          // 最大値は value に変わる
          this._max_value = value;
          history.shift();
        } else if (history[0] < old_max) {
          // 最大値は変わらず
          history.shift();
        } else {
          // 最大値は変わる可能性がある
          history.shift();
          this._max_value = HistStats._find_max(history);
        }
      }

      history.push(value);
      return this._max_value;
    }
  }], [{
    key: "_find_max",
    value: function _find_max(history) {
      var max_value = history[0];
      var length = history.length;

      for (var i = 1; i < length; ++i) {
        var value = history[i];

        if (value > max_value) {
          max_value = value;
        }
      }

      return max_value;
    }
  }]);

  return HistStats;
}();
/**
 * @summary メッシュ管理ノード
 * @memberof mapray.Globe
 * @private
 */


var MeshNode =
/*#__PURE__*/
function () {
  /**
   * @summary 初期化
   * @param  {mapray.Globe.Flake} flake  所有者
   * @param  {mapray.DemBinary}   dem    DEM バイナリ
   * @param  {number[]}           dpows  分割指数
   */
  function MeshNode(flake, dem, dpows) {
    _classCallCheck(this, MeshNode);

    this._flake = flake;
    this._dem = dem;
    this._dpows = Array.from(dpows);
    this._aframe = -1; // 地表のメッシュ

    this._base_mesh = new FlakeMesh(flake._globe.glenv, flake, dpows, dem); // エンティティのメッシュ
    //   key:   FlakePrimitiveProducer
    //   value: Mesh | CACHED_EMPTY_MESH

    this._entity_meshes = new Map(); // メッシュ数をカウントアップ

    flake._globe._num_cache_meshes += 1;
  }
  /**
   * @summary FlakeRenderObject インスタンスを取得
   *
   * @return {mapray.FlakeRenderObject}
   */


  _createClass(MeshNode, [{
    key: "getRenderObject",
    value: function getRenderObject() {
      var flake = this._flake;
      var fro = new FlakeRenderObject(flake, flake._globe.glenv, this._base_mesh); // fro にエンティティ毎のデータを追加

      var _iteratorNormalCompletion8 = true;
      var _didIteratorError8 = false;
      var _iteratorError8 = undefined;

      try {
        for (var _iterator8 = flake.getEntityProducers()[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
          var producer = _step8.value;

          // producer に対応するキャッシュされた Mesh
          var mesh = this._getEntityMesh(producer);

          if (mesh === CACHED_EMPTY_MESH) {
            // 空メッシュとしてキャッシュされている --> fro に追加しない
            continue;
          }

          if (mesh === null) {
            // メッシュがキャッシュに存在しないので、メッシュを生成してキャッシュする
            mesh = producer.createMesh(flake, this._dpows, this._dem);

            this._setEntityMesh(producer, mesh);

            if (mesh === null) {
              // 空メッシュとしてキャッシュされた --> fro に追加しない
              continue;
            }
          } // fro にエンティティを追加


          fro.addEntityData(mesh, producer);
        }
      } catch (err) {
        _didIteratorError8 = true;
        _iteratorError8 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion8 && _iterator8["return"] != null) {
            _iterator8["return"]();
          }
        } finally {
          if (_didIteratorError8) {
            throw _iteratorError8;
          }
        }
      }

      return fro;
    }
    /**
     * @summary 一致するか?
     * @param  {mapray.DemBinary} dem    DEM バイナリ
     * @param  {number[]}         dpows  分割指数
     * @return {boolean}                 一致するとき true, 一致しないとき false
     */

  }, {
    key: "match",
    value: function match(dem, dpows) {
      return this._dem === dem && this._dpows[0] === dpows[0] && this._dpows[1] === dpows[1];
    }
    /**
     * @summary アクセスフレームを更新
     */

  }, {
    key: "touch",
    value: function touch() {
      var globe = this._flake._globe;

      if (this._aframe !== globe._frame_counter) {
        this._aframe = globe._frame_counter;
        globe._num_touch_meshes += 1;
      }
    }
    /**
     * @summary ノードを破棄
     */

  }, {
    key: "dispose",
    value: function dispose() {
      if (this._base_mesh === null) {
        // すでに破棄されている
        return;
      }

      var flake = this._flake; // Flake から this ノードを削除

      var meshes = flake._meshes;
      var length = meshes.length;

      for (var i = 0; i < length; ++i) {
        if (meshes[i] === this) {
          meshes.splice(i, 1);
          break;
        }
      } // メッシュを破棄


      this._base_mesh.dispose();

      this._base_mesh = null;
      var _iteratorNormalCompletion9 = true;
      var _didIteratorError9 = false;
      var _iteratorError9 = undefined;

      try {
        for (var _iterator9 = this._entity_meshes.values()[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
          var mesh = _step9.value;

          if (mesh instanceof Mesh) {
            mesh.dispose();
          }
        } // メッシュ数をカウントダウン

      } catch (err) {
        _didIteratorError9 = true;
        _iteratorError9 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion9 && _iterator9["return"] != null) {
            _iterator9["return"]();
          }
        } finally {
          if (_didIteratorError9) {
            throw _iteratorError9;
          }
        }
      }

      flake._globe._num_cache_meshes -= 1;
    }
    /**
     * @summary 削減用の MeshNode 比較
     * @param  {mapray.Globe.MeshNode} other  比較対象
     * @return {number}                       比較値
     * @package
     */

  }, {
    key: "compareForReduce",
    value: function compareForReduce(other) {
      // 最近アクセスしたものを優先
      var a = this;
      var b = other;
      return b._aframe - a._aframe;
    }
    /**
     * @summary エンティティのメッシュを削除
     *
     * @desc
     * <p>producer に対応するメッシュが存在すれば削除する。</p>
     *
     * @param {mapray.Entity.FlakePrimitiveProducer} producer
     */

  }, {
    key: "removeEntityMesh",
    value: function removeEntityMesh(producer) {
      this._entity_meshes["delete"](producer);
    }
    /**
     * @summary エンティティのメッシュを取得
     *
     * @desc
     * <p>producer に対応するメッシュを取得する。</p>
     * <p>ただし存在しないとき null, 空メッシュが設定されているときは CACHED_EMPTY_MESH を返す。</p>
     *
     * @param {mapray.Entity.FlakePrimitiveProducer} producer
     *
     * @return {?(mapray.Mesh|CACHED_EMPTY_MESH)}
     *
     * @private
     */

  }, {
    key: "_getEntityMesh",
    value: function _getEntityMesh(producer) {
      var mesh = this._entity_meshes.get(producer);

      return mesh !== undefined ? mesh : null;
    }
    /**
     * @summary エンティティのメッシュを設定
     *
     * @desc
     * <p>producer に対応するメッシュを設定する。</p>
     * <p>空メッシュを設定するときは mesh に null を指定する。</p>
     *
     * @param {mapray.Entity.FlakePrimitiveProducer} producer
     * @param {?mapray.Mesh}                         mesh
     *
     * @private
     */

  }, {
    key: "_setEntityMesh",
    value: function _setEntityMesh(producer, mesh) {
      var value = mesh !== null ? mesh : CACHED_EMPTY_MESH;

      this._entity_meshes.set(producer, value);
    }
  }]);

  return MeshNode;
}();
/**
 * @summary DEM 状態の列挙型
 * @enum {object}
 * @memberof mapray.Globe
 * @constant
 */


var DemState = {
  /**
   * DEM タイルが存在しない
   */
  NONE: {
    id: "NONE"
  },

  /**
   * DEM タイルが存在する
   */
  LOADED: {
    id: "LOADED"
  },

  /**
   * DEM タイルをリクエスト中
   */
  REQUESTED: {
    id: "REQUESTED"
  },

  /**
   * DEM タイルのリクエストに失敗
   */
  FAILED: {
    id: "FAILED"
  }
};
/**
 * @summary キャッシュされた空メッシュを表す
 *
 * @memberof mapray.Globe
 * @constant
 */

var CACHED_EMPTY_MESH = {
  id: "CACHED_EMPTY_MESH"
};

/**
 * @summary 描画地表断片
 * @memberof mapray
 * @private
 */
var RenderFlake =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Globe.Flake} flake  地表断片
   */
  function RenderFlake(flake) {
    _classCallCheck(this, RenderFlake);

    /**
     *  @summary 地表断片
     *  @member mapray.RenderFlake#flake
     *  @type {mapray.Globe.Flake}
     */
    this.flake = flake;
    /**
     *  @summary 地表詳細レベル (LOD)
     *  @member mapray.RenderFlake#lod
     *  @type {number}
     */

    /**
     *  @summary LOD (左下)
     *  @member mapray.RenderFlake#lod_00
     *  @type {number}
     */

    /**
     *  @summary LOD (右下)
     *  @member mapray.RenderFlake#lod_10
     *  @type {number}
     */

    /**
     *  @summary LOD (左上)
     *  @member mapray.RenderFlake#lod_01
     *  @type {number}
     */

    /**
     *  @summary LOD (右上)
     *  @member mapray.RenderFlake#lod_11
     *  @type {number}
     */
  }
  /**
   * @summary レンダリングオブジェクトを検索
   *
   * @return {mapray.FlakeRenderObject}
   */


  _createClass(RenderFlake, [{
    key: "getRenderObject",
    value: function getRenderObject() {
      return this.flake.getRenderObject(this.lod);
    }
  }]);

  return RenderFlake;
}();

/**
 * @summary 描画地表断片を収集するツール
 * @memberof mapray.RenderStage
 * @private
 */

var FlakeCollector =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.RenderStage} stage   所有者である RenderStage
   */
  function FlakeCollector(stage) {
    _classCallCheck(this, FlakeCollector);

    this._setupViewVectors(stage);

    this._setupClipPlanes(stage);

    var viewer = stage._viewer;
    var dem_provider = viewer.dem_provider;
    var tile_texture_cache = viewer.tile_texture_cache;
    this._min_image_z = tile_texture_cache.getImageZMin();
    var dem_zbias = GeoMath.LOG2PI - dem_provider.getResolutionPower() + 1; // b = log2π - ρ + 1

    this._max_zbias = Math.max(tile_texture_cache.getImageZBias(), dem_zbias);
    this._globe = viewer.globe;
    this._rflake_list = []; // デバッグ統計

    this._debug_stats = viewer.debug_stats;

    if (this._debug_stats) {
      this._num_procA_flakes = 0;
      this._num_procB_flakes = 0;
    } // 事前生成オブジェクト


    this._view_dir_N = GeoMath.createVector3();
    this._view_dir_V = GeoMath.createVector3();
  }
  /**
   * @private
   */


  _createClass(FlakeCollector, [{
    key: "_setupViewVectors",
    value: function _setupViewVectors(stage) {
      var view_to_gocs = stage._view_to_gocs;
      var pixel_step = stage._pixel_step;
      var view_pos_Q = GeoMath.createVector3();
      var view_dir_wU = GeoMath.createVector3(); // 地表詳細レベル (LOD) 計算用の Q, w*U ベクトルを設定

      view_pos_Q[0] = view_to_gocs[12];
      view_pos_Q[1] = view_to_gocs[13];
      view_pos_Q[2] = view_to_gocs[14];
      view_dir_wU[0] = -view_to_gocs[8] * pixel_step;
      view_dir_wU[1] = -view_to_gocs[9] * pixel_step;
      view_dir_wU[2] = -view_to_gocs[10] * pixel_step;
      /**
       *  @summary 位置ベクトル Q
       *  @member mapray.FlakeCollector#_view_pos_Q
       *  @type {mapray.Vector3}
       *  @private
       *  @see doc/ImageLevelCalculation.txt
       */

      this._view_pos_Q = view_pos_Q;
      /**
       *  @summary ベクトル w * U
       *  @member mapray.FlakeCollector#_view_dir_wU
       *  @type {mapray.Vector3}
       *  @private
       *  @see doc/ImageLevelCalculation.txt
       */

      this._view_dir_wU = view_dir_wU;
    }
    /**
     * @private
     */

  }, {
    key: "_setupClipPlanes",
    value: function _setupClipPlanes(stage) {
      var view_to_gocs = stage._view_to_gocs;
      var gocs_to_view = stage._gocs_to_view;
      var volume_planes = stage._volume_planes;
      var clip_planes = []; // 地表遮蔽カリング平面

      var root_flake = stage._viewer._globe.root_flake;
      var rmin = GeoMath.EARTH_RADIUS + root_flake.height_min; // 最小半径

      var rmax = GeoMath.EARTH_RADIUS + root_flake.height_max; // 最大半径
      // P (視点位置)

      var px = view_to_gocs[12];
      var py = view_to_gocs[13];
      var pz = view_to_gocs[14]; // q = √[(P.P - rmin^2)(rmax^2 - rmin^2)] - rmin^2

      var p2 = px * px + py * py + pz * pz;
      var rmin2 = rmin * rmin;
      var rmax2 = rmax * rmax;
      var q = Math.sqrt((p2 - rmin2) * (rmax2 - rmin2)) - rmin2; // L = <P, q> / ‖P‖

      var plane = GeoMath.createVector4();
      var recip = 1 / Math.sqrt(p2);
      plane[0] = px * recip;
      plane[1] = py * recip;
      plane[2] = pz * recip;
      plane[3] = q * recip;
      clip_planes.push(plane); // L を基とした遠方距離

      var far_dist = Math.sqrt(p2 + rmax2 + 2 * q); // 視体積平面を取得して、地心直交座標系に変換
      // (直交変換なので x, y, z は正規化されている)

      for (var i = 0; i < 6; ++i) {
        var src_plane = volume_planes[i];
        var dst_plane = GeoMath.createVector4();

        if (i == 1 && src_plane[3] > far_dist) {
          // 遠方平面が必要以上に遠いとき far_dist に置き換える
          src_plane = GeoMath.createVector4(src_plane);
          src_plane[3] = far_dist;
        }

        GeoMath.transformPlane_A(gocs_to_view, src_plane, dst_plane);
        clip_planes.push(dst_plane);
      }

      this._clip_planes = clip_planes;
    }
    /**
     * @summary 描画地表断片を収集
     * @return {mapray.RenderFlake[]}  収集され描画地表断片の集合
     */

  }, {
    key: "traverse",
    value: function traverse() {
      this._collectFlakes(this._globe.root_flake); // デバッグ統計


      if (this._debug_stats) {
        this._debug_stats.num_procA_flakes = this._num_procA_flakes;
        this._debug_stats.num_procB_flakes = this._num_procB_flakes;
      }

      return this._rflake_list;
    }
    /**
     * @private
     */

  }, {
    key: "_collectFlakes",
    value: function _collectFlakes(flake) {
      if (this._debug_stats !== null) {
        this._num_procA_flakes += 1;
      }

      if (flake.isInvisible(this._clip_planes)) {
        // 地表タイルが見えないので描画しない
        return;
      }

      if (flake.z < this._min_image_z) {
        // 地表タイルより小さな画像タイルしかない
        this._collectNextLevelFlakes(flake); // 地表タイルを分割


        return;
      }

      if (this._debug_stats !== null) {
        this._num_procB_flakes += 1;
      } // 地表断片の詳細レベルの範囲


      var range = this._getLevelOfDetailRange(flake);

      var zt = range.mid + this._max_zbias; // 最大タイルレベル

      if (range.max - range.min > FlakeCollector.MAX_LOD_INTERVAL || zt > flake.z) {
        //    地表断片の LOD 幅が閾値より大きい
        // or 最大タイルレベル > 地表断片レベル
        this._collectNextLevelFlakes(flake); // 地表断片を分割


        return;
      } // リストに RenderFlake を追加


      this._addRenderFlake(flake, range);
    }
    /**
     * @private
     */

  }, {
    key: "_collectNextLevelFlakes",
    value: function _collectNextLevelFlakes(flake) {
      for (var v = 0; v < 2; ++v) {
        for (var u = 0; u < 2; ++u) {
          this._collectFlakes(flake.newChild(u, v));
        }
      }
    }
    /**
     * @summary 地表断片の詳細レベルの範囲を取得
     * @private
     */

  }, {
    key: "_getLevelOfDetailRange",
    value: function _getLevelOfDetailRange(flake) {
      var pi = Math.PI;
      var z = flake.z;
      var x = flake.x;
      var y = flake.y; // 座標範囲 (単位球メルカトル座標系)

      var msize = Math.pow(2, 1 - z) * pi;
      var mx_min = -pi + x * msize;
      var my_min = pi - (y + 1) * msize;
      var max_mstep = pi / 32;
      var mcount = Math.ceil(msize / max_mstep);
      var mstep = msize / mcount;
      var r = GeoMath.EARTH_RADIUS + flake.base_height;
      var Q = this._view_pos_Q;
      var wU = this._view_dir_wU;
      var N = this._view_dir_N;
      var V = this._view_dir_V;
      var dMin = Number.MAX_VALUE;
      var dMax = -Number.MAX_VALUE;

      for (var iy = 0, my = my_min; iy < mcount + 1; ++iy, my += mstep) {
        var ey = Math.exp(my);
        var ey2 = ey * ey;
        var sinφ = (ey2 - 1) / (ey2 + 1);
        var cosφ = 2 * ey / (ey2 + 1);
        var denom = 1 / (r * cosφ);

        for (var ix = 0, mx = mx_min; ix < mcount + 1; ++ix, mx += mstep) {
          var sinλ = Math.sin(mx);
          var cosλ = Math.cos(mx); // N

          N[0] = cosφ * cosλ;
          N[1] = cosφ * sinλ;
          N[2] = sinφ; // V = r N - Q

          V[0] = r * N[0] - Q[0];
          V[1] = r * N[1] - Q[1];
          V[2] = r * N[2] - Q[2]; // w U.V

          var wUV = GeoMath.dot3(wU, V);

          if (wUV <= 0) {
            // 頂点が視点の後ろ側
            return {
              min: -1000,
              max: 1000,
              mid: 0
            };
          } //      w U.(r N - Q)
          // d = ---------------
          //        r Cos[φ]


          var deriv = wUV * denom; // 最大最小を更新

          dMin = Math.min(dMin, deriv);
          dMax = Math.max(dMax, deriv);
        }
      }

      var lodMin = -Math.maprayLog2(dMax); // Log2[1/dMax]

      var lodMax = -Math.maprayLog2(dMin); // Log2[1/dMin]

      return {
        min: lodMin,
        max: lodMax,
        mid: (lodMin + lodMax) / 2
      };
    }
    /**
     * @summary 単位球メルカトル座標 x, y の地表詳細レベルを計算
     * @desc
     * <p>以下の値が設定されていなければならない。</p>
     * <ul>
     *   <li>this._view_pos_Q</li>
     *   <li>this._view_dir_wU</li>
     * </ul>
     * @param  {number} x  X 座標
     * @param  {number} y  Y 座標
     * @param  {number} r  GOGS 原点からの距離 (Meters)
     * @return {number}    地表詳細レベル
     * @private
     */

  }, {
    key: "_calcLOD",
    value: function _calcLOD(x, y, r) {
      var sinλ = Math.sin(x);
      var cosλ = Math.cos(x);
      var ey = Math.exp(y);
      var ey2 = ey * ey;
      var sinφ = (ey2 - 1) / (ey2 + 1);
      var cosφ = 2 * ey / (ey2 + 1); // N

      var N = this._view_dir_N;
      N[0] = cosφ * cosλ;
      N[1] = cosφ * sinλ;
      N[2] = sinφ; // V = r N - Q

      var V = this._view_dir_V;
      var Q = this._view_pos_Q;
      V[0] = r * N[0] - Q[0];
      V[1] = r * N[1] - Q[1];
      V[2] = r * N[2] - Q[2]; // w U.V

      var wU = this._view_dir_wU;
      var wUV = GeoMath.dot3(wU, V); // > 0 (表示される Flake 前提なので正数)
      //          r Cos[φ]
      // 1/d = ---------------
      //        w U.(r N - Q)

      var inv_d = r * cosφ / wUV; // Log2[1/d]

      return Math.maprayLog2(inv_d);
    }
    /**
     * @summary 四隅の LOD を設定
     * @desc
     * <p>rflake に以下のプロパティを設定する。</p>
     * <ul>
     *   <li>rflake.lod_00</li>
     *   <li>rflake.lod_10</li>
     *   <li>rflake.lod_01</li>
     *   <li>rflake.lod_11</li>
     * </ul>
     * @private
     */

  }, {
    key: "_setCornerLODs",
    value: function _setCornerLODs(rflake) {
      var pi = Math.PI;
      var flake = rflake.flake;
      var z = flake.z;
      var x = flake.x;
      var y = flake.y; // 座標範囲 (単位球メルカトル座標系)

      var msize = Math.pow(2, 1 - z) * pi;
      var mx_min = -pi + x * msize;
      var mx_max = -pi + (x + 1) * msize;
      var my_min = pi - (y + 1) * msize;
      var my_max = pi - y * msize; // GOCS 原点からの距離

      var r = GeoMath.EARTH_RADIUS + flake.base_height; // 四隅の地表詳細レベル

      rflake.lod_00 = this._calcLOD(mx_min, my_min, r);
      rflake.lod_10 = this._calcLOD(mx_max, my_min, r);
      rflake.lod_01 = this._calcLOD(mx_min, my_max, r);
      rflake.lod_11 = this._calcLOD(mx_max, my_max, r);
    }
    /**
     * @summary 描画地表断片を追加
     * @private
     */

  }, {
    key: "_addRenderFlake",
    value: function _addRenderFlake(flake, range) {
      var rflake = new RenderFlake(flake);
      rflake.lod = range.mid;

      this._setCornerLODs(rflake);

      this._rflake_list.push(rflake);
    }
  }]);

  return FlakeCollector;
}();
/**
 * @summary Flake に対する LOD の許容幅
 * @desc
 * <p>1つの Flake 全体に対する最小 LOD と最大 LOD の間の最大幅である。</p>
 * <p>有効な範囲は 0.0 < MAX_LOD_INTERVAL < 1.0 である。</p>
 * @type {number}
 * @constant
 */


FlakeCollector.MAX_LOD_INTERVAL = 0.5;

/**
 * @summary WebGL シェーダラッパー
 * @desc
 * 頂点シェーダとフラグメントシェーダのセットである。
 * @memberof mapray
 * @private
 */
var Shader =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv} glenv    WebGL 環境
   * @param {string}     vs_code  頂点シェーダのソースコード
   * @param {string}     fs_code  フラグメントシェーダのソースコード
   * @exception {Error}           コンパイルエラー
   */
  function Shader(glenv, vs_code, fs_code) {
    _classCallCheck(this, Shader);

    this._glenv = glenv;

    try {
      /**
       * @summary 頂点シェーダオブジェクト
       * @member mapray.Shader#vs_object
       * @type {WebGLShader}
       * @readonly
       */
      this.vs_object = this._compile_shader('VERTEX_SHADER', vs_code);
      /**
       * @summary フラグメントシェーダオブジェクト
       * @member mapray.Shader#fs_object
       * @type {WebGLShader}
       * @readonly
       */

      this.fs_object = this._compile_shader('FRAGMENT_SHADER', fs_code);
    } catch (e) {
      var gl = glenv.context;
      if (this.vs_object) gl.deleteShader(this.vs_object);
      if (this.fs_object) gl.deleteShader(this.fs_object);
      throw e;
    }
  }
  /**
   * @summary シェーダを破棄
   */


  _createClass(Shader, [{
    key: "dispose",
    value: function dispose() {
      var gl = this._glenv.context;

      if (this.vs_object) {
        gl.deleteShader(this.vs_object);
        this.vs_object = null;
      }

      if (this.fs_object) {
        gl.deleteShader(this.fs_object);
        this.fs_object = null;
      }
    }
    /**
     * @summary シェーダをコンパイル
     * @param  {string}      type    'VERTEX_SHADER' or 'FRAGMENT_SHADER'
     * @param  {string}      source  ソースコード文字列
     * @return {WebGLShader}         コンパイルされたシェーダオブジェクト
     * @exception {Error}            コンパイルエラー
     * @private
     */

  }, {
    key: "_compile_shader",
    value: function _compile_shader(type, source) {
      var gl = this._glenv.context;
      var shader = gl.createShader(gl[type]);

      if (!shader) {
        throw new Error(type + " オブジェクトの生成に失敗しました");
      }

      try {
        gl.shaderSource(shader, source);
        gl.compileShader(shader);

        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
          // コンパイルエラー
          var log = gl.getShaderInfoLog(shader);
          throw new Error(type + " のコンパイルに失敗: " + log);
        }
      } catch (e) {
        gl.deleteShader(shader);
        throw e;
      }

      return shader;
    }
  }]);

  return Shader;
}();

/**
 * @summary マテリアル
 * @memberof mapray
 * @private
 */

var Material =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv} glenv    WebGL 環境
   * @param {string}       vs_code  頂点シェーダのソースコード
   * @param {string}       fs_code  フラグメントシェーダのソースコード
   */
  function Material(glenv, vs_code, fs_code) {
    _classCallCheck(this, Material);

    var shader = new Shader(glenv, vs_code, fs_code);
    this._gl = glenv.context;
    this._program = this._link_shaders(shader.vs_object, shader.fs_object);
    this._vertex_attribs = this._create_vertex_attribs();
    this._uniform_location = this._create_uniform_location();
    shader.dispose();
  }
  /**
   * @summary シェーダをリンク
   * @param  {WebGLShader}  vs  頂点シェーダ
   * @param  {WebGLShader}  fs  フラグメントシェーダ
   * @return {WebGLProgram}     リンクされたプログラムオブジェクト
   * @exception {Error}         リンクエラー
   * @private
   */


  _createClass(Material, [{
    key: "_link_shaders",
    value: function _link_shaders(vs, fs) {
      var gl = this._gl;
      var program = gl.createProgram();

      if (!program) {
        throw new Error("プログラムオブジェクトの生成に失敗しました");
      }

      try {
        gl.attachShader(program, vs);
        gl.attachShader(program, fs);
        gl.linkProgram(program);

        if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
          // リンクエラー
          var log = gl.getProgramInfoLog(program);
          gl.detachShader(program, fs);
          gl.detachShader(program, vs);
          throw new Error("シェーダのリンクに失敗: " + log);
        }
      } catch (e) {
        gl.deleteProgram(program);
        throw e;
      }

      return program;
    }
    /**
     * @summary 頂点属性情報を作成
     *
     * @return {array}  頂点属性名前とロケーションの配列
     * @private
     */

  }, {
    key: "_create_vertex_attribs",
    value: function _create_vertex_attribs() {
      var gl = this._gl;
      var program = this._program;
      var attribs = [];
      var num_items = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);

      for (var i = 0; i < num_items; ++i) {
        var info = gl.getActiveAttrib(program, i);
        var attrib = {
          name: info.name,
          location: gl.getAttribLocation(program, info.name)
        };
        attribs.push(attrib);
      }

      return attribs;
    }
    /**
     * @summary uniform 変数のロケーション辞書を作成
     *
     * @return {object}  ロケーション辞書
     * @private
     */

  }, {
    key: "_create_uniform_location",
    value: function _create_uniform_location() {
      var gl = this._gl;
      var program = this._program;
      var location = {}; // Uniform 変数のロケーション

      var num_items = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);

      for (var i = 0; i < num_items; ++i) {
        var info = gl.getActiveUniform(program, i);
        location[info.name] = gl.getUniformLocation(program, info.name);
      }

      return location;
    }
    /**
     * @summary リソースを破棄
     */

  }, {
    key: "dispose",
    value: function dispose() {
      var gl = this._gl;
      gl.deleteProgram(this._program);
      this._program = null;
    }
    /**
     * @summary プログラムを束縛
     */

  }, {
    key: "bindProgram",
    value: function bindProgram() {
      var gl = this._gl;
      gl.useProgram(this._program);
    }
    /**
     * @summary 真偽値パラメータを設定
     * @param {string}  name   変数名
     * @param {boolean} value  真偽値
     */

  }, {
    key: "setBoolean",
    value: function setBoolean(name, value) {
      var location = this._uniform_location[name];

      if (location) {
        var gl = this._gl;
        gl.uniform1i(location, value ? 1 : 0);
      }
    }
    /**
     * @summary 整数パラメータを設定
     * @param {string} name   変数名
     * @param {number} value  整数値
     */

  }, {
    key: "setInteger",
    value: function setInteger(name, value) {
      var location = this._uniform_location[name];

      if (location) {
        var gl = this._gl;
        gl.uniform1i(location, value);
      }
    }
    /**
     * @summary float パラメータを設定
     * @param {string} name   変数名
     * @param {number} value  float 値
     */

  }, {
    key: "setFloat",
    value: function setFloat(name, value) {
      var location = this._uniform_location[name];

      if (location) {
        var gl = this._gl;
        gl.uniform1f(location, value);
      }
    }
    /**
     * @summary 2次ベクトルパラメータを設定
     * @param {string}         name   変数名
     * @param {mapray.Vector2} value  2次ベクトル
     */

  }, {
    key: "setVector2",
    value: function setVector2(name, value) {
      var location = this._uniform_location[name];

      if (location) {
        var gl = this._gl;
        gl.uniform2fv(location, value);
      }
    }
    /**
     * @summary 3次ベクトルパラメータを設定
     * @param {string}         name   変数名
     * @param {mapray.Vector3} value  3次ベクトル
     */

  }, {
    key: "setVector3",
    value: function setVector3(name, value) {
      var location = this._uniform_location[name];

      if (location) {
        var gl = this._gl;
        gl.uniform3fv(location, value);
      }
    }
    /**
     * @summary 4次ベクトルパラメータを設定
     * @param {string}         name   変数名
     * @param {mapray.Vector4} value  4次ベクトル
     */

  }, {
    key: "setVector4",
    value: function setVector4(name, value) {
      var location = this._uniform_location[name];

      if (location) {
        var gl = this._gl;
        gl.uniform4fv(location, value);
      }
    }
    /**
     * @summary 行列パラメータを設定
     * @param {string}        name   変数名
     * @param {mapray.Matrix} value  行列
     */

  }, {
    key: "setMatrix",
    value: function setMatrix(name, value) {
      var location = this._uniform_location[name];

      if (location) {
        var gl = this._gl;
        gl.uniformMatrix4fv(location, false, value);
      }
    }
    /**
     * @summary 頂点属性データを束縛
     *
     * @desc
     * <p>mesh_attribs は頂点属性名から Mesh.AttribData インスタンスを取得する辞書である。</p>
     *
     * @param {object} mesh_attribs  メッシュ側の頂点属性データの辞書
     */

  }, {
    key: "bindVertexAttribs",
    value: function bindVertexAttribs(mesh_attribs) {
      var gl = this._gl;
      var mtl_attribs = this._vertex_attribs; // マテリアル側の頂点属性データ配列

      var num_attribs = mtl_attribs.length;

      for (var i = 0; i < num_attribs; ++i) {
        var mtl_attrib = mtl_attribs[i];
        var mesh_attrib = mesh_attribs[mtl_attrib.name];
        var location = mtl_attrib.location;

        if (mesh_attrib !== undefined) {
          // 頂点属性データを束縛
          gl.bindBuffer(gl.ARRAY_BUFFER, mesh_attrib.buffer);
          gl.enableVertexAttribArray(location);
          gl.vertexAttribPointer(location, mesh_attrib.num_components, mesh_attrib.component_type, mesh_attrib.normalized, mesh_attrib.byte_stride, mesh_attrib.byte_offset);
        } else {
          // メッシュ側に必要な頂点属性がないとき
          gl.disableVertexAttribArray(location);
        }
      }
    }
    /**
     * @summary テクスチャをバインド
     * @desc
     * <p>注意: 現行テクスチャ (Active Texture) も変更される。</p>
     * @param {number}       unit     テクスチャユニット番号
     * @param {WebGLTexture} texture  テクスチャオブジェクト
     */

  }, {
    key: "bindTexture2D",
    value: function bindTexture2D(unit, texture) {
      var gl = this._gl;
      gl.activeTexture(gl.TEXTURE0 + unit);
      gl.bindTexture(gl.TEXTURE_2D, texture);
    }
  }]);

  return Material;
}();

/**
 * @summary 地表断片マテリアル
 * @memberof mapray.RenderStage
 * @extends mapray.Material
 * @private
 */

var FlakeMaterial =
/*#__PURE__*/
function (_Material) {
  _inherits(FlakeMaterial, _Material);

  /**
   * @param {mapray.Viewer} viewer   所有者である Viewer
   * @param {string}      vs_code  頂点シェーダのソースコード
   * @param {string}      fs_code  フラグメントシェーダのソースコード
   */
  function FlakeMaterial(viewer, vs_code, fs_code) {
    var _this;

    _classCallCheck(this, FlakeMaterial);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(FlakeMaterial).call(this, viewer.glenv, vs_code, fs_code)); // シェーダ用の事前生成オブジェクト

    _this._flake_to_clip = GeoMath.createMatrixf();
    return _this;
  }
  /**
   * @summary 描画回数
   * @return {number}
   * @abstract
   */


  _createClass(FlakeMaterial, [{
    key: "numDrawings",
    value: function numDrawings() {
      return 1;
    }
    /**
     * @summary ワイヤーフレーム表示か?
     * @return {boolean}
     * @abstract
     */

  }, {
    key: "isWireframe",
    value: function isWireframe() {
      return false;
    }
    /**
     * @summary 地表断片のパラメータを設定
     *
     * @param  {mapray.RenderStage} stage   呼び出し側オブジェクト
     * @param  {mapray.RenderFlake} rflake  描画地表断片
     * @param  {mapray.FlakeMesh}   mesh    地表断片メッシュ
     * @param  {number}             index   描画インデックス
     * @return {boolean}  描画の有無
     *
     * @abstract
     */

  }, {
    key: "setFlakeParameter",
    value: function setFlakeParameter(stage, rflake, mesh, index) {
      return false;
    }
    /**
     * @summary 地表断片の共通パラメータを設定
     *
     * @param {mapray.RenderStage} stage  呼び出し側オブジェクト
     * @param {mapray.FlakeMesh}   mesh   地表断片メッシュ
     * @protected
     */

  }, {
    key: "setCommonParameter",
    value: function setCommonParameter(stage, mesh) {
      mesh.mul_flake_to_gocs(stage._gocs_to_clip, this._flake_to_clip);
      this.setMatrix("u_obj_to_clip", this._flake_to_clip);
    }
  }]);

  return FlakeMaterial;
}(Material);

/**
 * @summary 地図画像プロバイダ
 * @classdesc
 * <p>レンダラーに地図画像を与えるための抽象クラスである。</p>
 *
 * <p>このインスタンスには状態 ( {@link mapray.ImageProvider.Status} 型) があり、{@link mapray.ImageProvider#status|status()}
 *    メソッドにより状態を確認することができる。<p>
 *
 * <p>初期状態は READY または NOT_READY でなければならず、状態の変化は NOT_READY から READY または NOT_READY から FAILED しか存在しない。<p>
 * <p>READY 以外の状態では {@link mapray.ImageProvider#status|status()} を除くメソッドを呼び出すことはできない。<p>
 *
 * <p>初期状態が NOT_READY になる可能性があるプロバイダは、{@link mapray.ImageProvider#status|status()} メソッドをオーバーライドする必要がある。</p>
 *
 * <p>以下の抽象メソッドは既定の動作がないので、利用者はこれらのメソッドをオーバーライドした具象クラスを使用しなければならない。</p>
 * <ul>
 *   <li>{@link mapray.ImageProvider#requestTile|requestTile()}</li>
 *   <li>{@link mapray.ImageProvider#cancelRequest|cancelRequest()}</li>
 *   <li>{@link mapray.ImageProvider#getImageSize|getImageSize()}</li>
 *   <li>{@link mapray.ImageProvider#getZoomLevelRange|getZoomLevelRange()}</li>
 * </ul>
 *
 * @memberof mapray
 * @abstract
 * @protected
 * @see mapray.StandardImageProvider
 * @see mapray.Viewer
 */
var ImageProvider =
/*#__PURE__*/
function () {
  function ImageProvider() {
    _classCallCheck(this, ImageProvider);
  }

  _createClass(ImageProvider, [{
    key: "status",

    /**
     * @summary 状態の取得
     * @desc
     * <p>現在の ImageProvider 状態を返す。</p>
     * <p>callback を与えたとき、状態が NOT_READY から READY または FAILED に変化したときに callback が呼び出される。
     * NOT_READY 以外の状態で callback 与えても、それは無視されコールバック関数は登録されない。</p>
     *
     * @param  {mapray.ImageProvider.StatusCallback} [callback]  状態変化コールバック関数
     * @return {mapray.ImageProvider.Status}                     現在の ImageProvider 状態
     * @abstract
     */
    value: function status(callback) {
      return Status$1.READY;
    }
    /**
     * @summary 地図タイル画像を要求
     * @desc
     * <p>座標が (z, x, y) の地図タイル画像を要求する。</p>
     * <p>指定したタイル画像の取得が成功または失敗したときに callback が非同期に呼び出されなければならない。</p>
     * <p>だたし [cancelRequest()]{@link mapray.ImageProvider#cancelRequest} により要求が取り消されたとき、callback は呼び出しても呼び出さなくてもよい。また非同期呼び出しである必要もない。</p>
     * @param  {number}   z  ズームレベル
     * @param  {number}   x  X タイル座標
     * @param  {number}   y  Y タイル座標
     * @param  {mapray.ImageProvider.RequestCallback} callback  要求コールバック関数
     * @return {object}   要求 ID ([cancelRequest()]{@link mapray.ImageProvider#cancelRequest} に与えるオブジェクト)
     * @abstract
     */

  }, {
    key: "requestTile",
    value: function requestTile(z, x, y, callback) {
      throw new Error("mapray.ImageProvider#requestTile() method has not been overridden.");
    }
    /**
     * @summary 地図タイル画像の要求を取り消す
     * <p>[requestTile()]{@link mapray.ImageProvider#requestTile} による要求を可能であれば取り消す。</p>
     * @param {object} id  要求 ID ([requestTile()]{@link mapray.ImageProvider#requestTile} から得たオブジェクト)
     * @abstract
     */

  }, {
    key: "cancelRequest",
    value: function cancelRequest(id) {
      throw new Error("mapray.ImageProvider#cancelRequest() method has not been overridden.");
    }
    /**
     * @summary 地図タイル画像の寸法を取得
     * @desc
     * <p>サーバーが提供する地図タイル画像の寸法をする。</p>
     * <p>地図タイル画像は正方形を前提とし、水平方向の画素数を返す。</p>
     * <p>制限: this が同じなら常に同じ値を返さなければならない。</p>
     * @return {number}  地図タイル画像の画素数
     * @abstract
     */

  }, {
    key: "getImageSize",
    value: function getImageSize() {
      throw new Error("mapray.ImageProvider#getImageSize() method has not been overridden.");
    }
    /**
     * @summary 地図画像ズームレベルの範囲を取得
     * @desc
     * <p>サーバーが提供する地図タイル画像のズームレベルの範囲を取得する。</p>
     * <p>制限: this が同じなら常に同じ範囲を返さなければならない。</p>
     * @return {mapray.ImageProvider.Range}  ズームレベルの範囲
     * @abstract
     */

  }, {
    key: "getZoomLevelRange",
    value: function getZoomLevelRange() {
      throw new Error("mapray.ImageProvider#getZoomLevelRange() method has not been overridden.");
    }
  }]);

  return ImageProvider;
}();
/**
 * @summary 地図画像ズームレベル範囲
 * @memberof mapray.ImageProvider
 * @see mapray.ImageProvider#getZoomLevelRange
 */


var Range =
/*#__PURE__*/
function () {
  /**
   * @param {number} min  最小ズームレベル (0 または 0 より大きい整数)
   * @param {number} max  最大ズームレベル (min または min より大きい整数)
   */
  function Range(min, max) {
    _classCallCheck(this, Range);

    this._min = min;
    this._max = max;
  }
  /**
   * @summary 最小ズームレベル
   * @type {number}
   * @readonly
   */


  _createClass(Range, [{
    key: "min",
    get: function get() {
      return this._min;
    }
    /**
     * @summary 最大ズームレベル
     * @type {number}
     * @readonly
     */

  }, {
    key: "max",
    get: function get() {
      return this._max;
    }
  }]);

  return Range;
}();

ImageProvider.Range = Range;
/**
 * @summary 地図タイル画像要求コールバック関数型
 * @desc
 * <p>地図タイル画像の取得に成功または失敗したときに呼び出される関数の型である。</p>
 * <p>この関数は [requestTile()]{@link mapray.ImageProvider#requestTile} の callback 引数に与える。</p>
 * <p>画像の取得に成功したときは、image に Image のインスタンス、失敗したときは null を与える。</p>
 * <p>ただし [cancelRequest()]{@link mapray.ImageProvider#cancelRequest} により要求が取り消されたとき、コールバック関数の呼び出しは無視されるので image は任意の値でよい。<p>
 * @param {Image} image  地図タイル画像または null
 * @callback RequestCallback
 * @memberof mapray.ImageProvider
 */

/**
 * @summary ImageProvider 状態の列挙型
 * @enum {object}
 * @memberof mapray.ImageProvider
 * @constant
 * @see mapray.ImageProvider#status
 */

var Status$1 = {
  /**
   * 準備中
   */
  NOT_READY: {
    id: "NOT_READY"
  },

  /**
   * 準備完了
   */
  READY: {
    id: "READY"
  },

  /**
   * 失敗状態
   */
  FAILED: {
    id: "FAILED"
  }
};
ImageProvider.Status = Status$1;

/**
 * @summary ダミー画像プロバイダ
 *
 * 状態は常に READY、レベル 0 のみの巨大画像、ただし画像は永遠に返さない。
 *
 * @memberof mapray
 * @extends mapray.ImageProvider
 * @private
 */

var EmptyImageProvider =
/*#__PURE__*/
function (_ImageProvider) {
  _inherits(EmptyImageProvider, _ImageProvider);

  /**
   */
  function EmptyImageProvider() {
    _classCallCheck(this, EmptyImageProvider);

    return _possibleConstructorReturn(this, _getPrototypeOf(EmptyImageProvider).call(this));
  }
  /**
   * @override
   */


  _createClass(EmptyImageProvider, [{
    key: "requestTile",
    value: function requestTile(z, x, y, callback) {
      return this;
    }
    /**
     * @override
     */

  }, {
    key: "cancelRequest",
    value: function cancelRequest(id) {}
    /**
     * @override
     */

  }, {
    key: "getImageSize",
    value: function getImageSize() {
      return 4096;
    }
    /**
     * @override
     */

  }, {
    key: "getZoomLevelRange",
    value: function getZoomLevelRange() {
      return new ImageProvider.Range(0, 0);
    }
  }]);

  return EmptyImageProvider;
}(ImageProvider);

/**
 * @summary タイルテクスチャ
 * @memberof mapray
 * @private
 * @see mapray.TileTextureCache
 */
var TileTexture =
/*#__PURE__*/
function () {
  /**
   * @param {number}       z        地図ズームレベル
   * @param {number}       x        X タイル座標
   * @param {number}       y        Y タイル座標
   * @param {WebGLTexture} texture  テクスチャオブジェクト
   */
  function TileTexture(z, x, y, texture) {
    _classCallCheck(this, TileTexture);

    /**
     * @summary 地図ズームレベル
     * @member mapray.TileTexture#z
     * @type {number}
     */
    this.z = z;
    /**
     * @summary X タイル座標
     * @member mapray.TileTexture#x
     * @type {number}
     */

    this.x = x;
    /**
     * @summary Y タイル座標
     * @member mapray.TileTexture#y
     * @type {number}
     */

    this.y = y;
    /**
     * @summary テクスチャオブジェクト
     * @member mapray.TileTexture#texture
     * @type {WebGLTexture}
     */

    this.texture = texture;
  }
  /**
   * @summary リソースを破棄
   * @param {WebGLRenderingContext} gl  WebGL レンダリングコンテキスト
   */


  _createClass(TileTexture, [{
    key: "dispose",
    value: function dispose(gl) {
      gl.deleteTexture(this.texture);
      this.texture = null;
    }
  }]);

  return TileTexture;
}();

/**
 * @summary タイルテクスチャの管理
 * @memberof mapray
 * @private
 * @see mapray.TileTexture
 */

var TileTextureCache =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv}         glenv     WebGL 環境
   * @param {mapray.ImageProvider} provider  地図画像プロバイダ
   */
  function TileTextureCache(glenv, provider) {
    var _this = this;

    _classCallCheck(this, TileTextureCache);

    this._glenv = glenv;
    this._provider = null;
    this._min_image_z = 0;
    this._max_image_z = 0;
    this._image_zbias = 0;

    var status_callback = function status_callback(status) {
      if (status === ImageProvider.Status.READY) {
        // EmptyImageProvider から本来の provider に切り替える
        _this._flush();

        _this._resetImageProvider(provider);
      } else if (status === ImageProvider.Status.FAILED) {
        // provider が READY 状態にならなかった
        console.error("ImageProvider.Status.FAILED in TileTextureCache");
      }
    };

    this._resetImageProvider(provider.status(status_callback) === ImageProvider.Status.READY ? provider : new EmptyImageProvider()); // キャッシュを初期化


    this._croot = new CacheNode(); // キャッシュ制御変数

    this._max_accesses = 0; // 最近のフレームの最大アクセスノード数

    this._frame_counter = 0; // 現行フレーム番号

    this._lower_bound = 1.0; // >= 1.0

    this._upper_bound = 1.2; // >= lower_bound
    // リクエスト制御変数

    this._num_requesteds = 0; // 現在の REQUESTED 状態のノード数

    this._max_requesteds = 75; // 最大 REQUESTED ノード数

    this._new_requesteds = []; // 新規リクエストのリスト
    // WebGL 関連

    var gl = glenv.context;
    var aniso_ext = glenv.EXT_texture_filter_anisotropic;

    if (aniso_ext) {
      this._aniso_ext = aniso_ext;
      this._max_aniso = gl.getParameter(aniso_ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
    }

    this._use_mipmap = false;
  }
  /**
   * 画像プロバイダを再設定
   *
   *   _provider
   *   _min_image_z
   *   _max_image_z
   *   _image_zbias
   *
   * @private
   */


  _createClass(TileTextureCache, [{
    key: "_resetImageProvider",
    value: function _resetImageProvider(provider) {
      this._provider = provider;
      var renge = provider.getZoomLevelRange();
      this._min_image_z = renge.min;
      this._max_image_z = renge.max;
      this._image_zbias = Math.maprayLog2(2 * Math.PI / provider.getImageSize());
    }
    /**
     * すべてのリクエストを取り消す
     */

  }, {
    key: "cancel",
    value: function cancel() {
      this._flush();
    }
    /**
     * キャッシュをフラッシュ
     * @private
     */

  }, {
    key: "_flush",
    value: function _flush() {
      new NodeCanceller(this, this._croot); // リクエストを取り消す

      this._croot = new CacheNode(); // 取り消したノードは使えないので、単純にすべて捨てる

      this._max_accesses = 0; // assert: this._num_requesteds == 0
    }
    /**
     * LOD からテクスチャの Z レベルを計算するバイアス値を取得
     *
     * @return {number}  Log2[2Pi / size]
     */

  }, {
    key: "getImageZBias",
    value: function getImageZBias() {
      return this._image_zbias;
    }
    /**
     * @return {number}  タイルの Z レベルの最小値
     */

  }, {
    key: "getImageZMin",
    value: function getImageZMin() {
      return this._min_image_z;
    }
    /**
     * @summary リクエスト待ちのタイルの個数を取得
     *
     * @return {number}  リクエスト待ちのタイルの個数
     */

  }, {
    key: "getNumWaitingRequests",
    value: function getNumWaitingRequests() {
      return this._num_requesteds;
    }
    /**
     * @summary 先祖タイルテクスチャを検索
     * @desc
     * <p>[x, y, z] タイルの祖先の中で、現在キャッシュに存在する最大レベルのタイルテクスチャを検索し、hi に設定する。</p>
     *
     * <p>ただし検索されるタイルのズームレベルが Z とすると、Z <= max( zlimit, this._min_image_z )
     *    という条件から検索し、存在しなければ null となる。</p>
     *
     *  <p>hi より低いレベルにタイルが存在すれば、それを lo に設定し、存在しなければ lo に hi と同じタイルを設定する</p>
     *
     * <p>プロバイダにもっと相応しいテクスチャが存在する可能性があれば、そのテクスチャを要求する。</p>
     *
     * <p>前提: z >= this._min_image_z && z >= zlimit</p>
     *
     * @param  {number}          z   地図ズームレベル
     * @param  {number}          x   X タイル座標
     * @param  {number}          y   Y タイル座標
     * @param  {number}     zlimit   先祖レベルの上限
     * @return {mapray.TileTexture[]}  先祖タイルテクスチャ配列 [hi, lo]
     */

  }, {
    key: "findNearestAncestors",
    value: function findNearestAncestors(z, x, y, zlimit) {
      var depth = 0;
      var d_min = this._min_image_z;
      var pow = Math.pow(2, 1 - z);
      var xf = (x + 0.5) * pow;
      var yf = (y + 0.5) * pow;
      var node = this._croot;
      var u;
      var v;
      var index;
      var children;
      var child; // 最小レベルのノード  --->  node, depth

      for (; depth < d_min; ++depth) {
        u = Math.floor(xf) % 2;
        v = Math.floor(yf) % 2;
        index = u + 2 * v;
        children = node.children;
        child = children[index];

        if (child === null) {
          child = new CacheNode();
          children[index] = child;
        }

        xf *= 2;
        yf *= 2;
        node = child;
      }

      var d_max = this._max_image_z;
      var d_lo = GeoMath.clamp(zlimit - 1, d_min, d_max);
      var d_hi = GeoMath.clamp(zlimit, d_min, d_max);
      var tex_lo = null;
      var tex_hi = null;

      if (d_lo < d_hi) {
        /* assert: (d_min < d_max) && (d_min < zlimit <= d_max) */
        for (; depth <= d_lo; ++depth) {
          if (node.state === NodeState.LOADED) {
            // 候補テクスチャを更新
            tex_lo = node;
          } else if (node.state === NodeState.NONE) {
            // 新規リクエスト
            node.state = NodeState.REQUESTED;
            node.req_power = zlimit - depth;

            this._new_requesteds.push([node, depth, Math.floor(0.5 * xf), Math.floor(0.5 * yf)]);
          } else if (node.state === NodeState.REQUESTED) {
            // 要求度を更新
            node.updateRequestPower(zlimit - depth);
          }

          u = Math.floor(xf) % 2;
          v = Math.floor(yf) % 2;
          index = u + 2 * v;
          children = node.children;
          child = children[index];

          if (child === null) {
            child = new CacheNode();
            children[index] = child;
          }

          xf *= 2;
          yf *= 2;
          node = child;
        }

        tex_hi = tex_lo;

        if (node.state === NodeState.LOADED) {
          // 候補テクスチャを更新
          tex_hi = node;
        } else if (node.state === NodeState.NONE) {
          // 新規リクエスト
          node.state = NodeState.REQUESTED;
          node.req_power = zlimit - depth;

          this._new_requesteds.push([node, depth, Math.floor(0.5 * xf), Math.floor(0.5 * yf)]);
        } else if (node.state === NodeState.REQUESTED) {
          // 要求度を更新
          node.updateRequestPower(zlimit - depth);
        }
      } else {
        // if d_lo == d_hi

        /* assert: (d_min == d_max) || (zlimit <= d_min) || (zlimit > d_max) */
        for (;; ++depth) {
          if (node.state === NodeState.LOADED) {
            // 候補テクスチャを更新
            tex_lo = node;
          } else if (node.state === NodeState.NONE) {
            // 新規リクエスト
            node.state = NodeState.REQUESTED;
            node.req_power = zlimit - depth;

            this._new_requesteds.push([node, depth, Math.floor(0.5 * xf), Math.floor(0.5 * yf)]);
          } else if (node.state === NodeState.REQUESTED) {
            // 要求度を更新
            node.updateRequestPower(zlimit - depth);
          }

          if (depth == d_lo) {
            tex_hi = tex_lo;
            break;
          }

          u = Math.floor(xf) % 2;
          v = Math.floor(yf) % 2;
          index = u + 2 * v;
          children = node.children;
          child = children[index];

          if (child === null) {
            child = new CacheNode();
            children[index] = child;
          }

          xf *= 2;
          yf *= 2;
          node = child;
        } // assert: tex_hi === tex_lo

      }

      node.touch();
      var result = TileTextureCache._findNearestAncestors_result;
      result[0] = tex_hi !== null ? tex_hi.data : null;
      result[1] = tex_lo !== null ? tex_lo.data : null;
      return result;
    }
    /**
     * @summary フレームの最後の処理
     */

  }, {
    key: "endFrame",
    value: function endFrame() {
      this._performNewRequests();

      var counter = new NodeCounter(this._croot, this._frame_counter);
      this._max_accesses = Math.max(counter.num_accesses, this._max_accesses);

      if (counter.num_loadeds > this._upper_bound * this._max_accesses) {
        var num_nodes = Math.floor(this._lower_bound * this._max_accesses);

        this._reduceCache(num_nodes);
      }

      ++this._frame_counter;
    }
    /**
     * @summary 新規リクエストを実行
     * @private
     */

  }, {
    key: "_performNewRequests",
    value: function _performNewRequests() {
      // リクエスト数
      var num_requests = Math.min(this._max_requesteds - this._num_requesteds, this._new_requesteds.length); // 基準に基づき、新規リクエストを前半 (num_requests 個) と後半に分割

      this._new_requesteds.sort(function (a, b) {
        var anode = a[0];
        var bnode = b[0];
        return bnode.req_power - anode.req_power;
      }); // リクエストを実行


      var self = this;

      this._new_requesteds.slice(0, num_requests).forEach(function (req) {
        var node = req[0];
        var z = req[1];
        var x = req[2];
        var y = req[3];

        self._requestTileTexture(z, x, y, node);
      }); // リクエストしなかったノードを空に戻す


      this._new_requesteds.slice(num_requests).forEach(function (req) {
        var node = req[0];
        node.state = NodeState.NONE; // assert: node.data === null
      }); // 新規リクエストのリストをクリア


      this._new_requesteds.length = 0;
    }
    /**
     * @summary タイルテクスチャを要求
     * @param {number} z  地図ズームレベル
     * @param {number} x  X タイル座標
     * @param {number} y  Y タイル座標
     * @param {mapray.TileTextureCache.CacheNode} node  対象ノード
     * @private
     */

  }, {
    key: "_requestTileTexture",
    value: function _requestTileTexture(z, x, y, node) {
      var _this2 = this;

      node.data = this._provider.requestTile(z, x, y, function (image) {
        if (node.state !== NodeState.REQUESTED) {
          // キャンセルされているので無視
          return;
        }

        if (image) {
          node.data = new TileTexture(z, x, y, _this2._createTexture(image));
          node.state = NodeState.LOADED;
        } else {
          node.data = null;
          node.state = NodeState.FAILED;
        }

        --_this2._num_requesteds;
      });
      ++this._num_requesteds;
    }
    /**
     * @summary テクスチャを生成
     * @desc
     * <p>GL ステートの変更</p>
     * <ul>
     *   <li>TEXTURE_2D_BINDING:   null</li>
     *   <li>UNPACK_FLIP_Y_WEBGL:  false</li>
     * </ul>
     * @param  {Image}  image  元画像
     * @return {WebGLTexture}  生成されたテクスチャ
     * @private
     */

  }, {
    key: "_createTexture",
    value: function _createTexture(image) {
      var gl = this._glenv.context;
      var aniso_ext = this._aniso_ext;
      var target = gl.TEXTURE_2D;
      var texture = gl.createTexture();
      gl.bindTexture(target, texture);
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
      gl.texImage2D(target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);

      if (this._use_mipmap) {
        gl.generateMipmap(target);
      }

      gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
      gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, this._use_mipmap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
      gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

      if (aniso_ext) {
        gl.texParameterf(gl.TEXTURE_2D, aniso_ext.TEXTURE_MAX_ANISOTROPY_EXT, this._max_aniso);
      }

      gl.bindTexture(target, null);
      return texture;
    }
    /**
     * @summary キャッシュを削減
     * @param  {number} num_cnodes  目標ノード数
     * @private
     */

  }, {
    key: "_reduceCache",
    value: function _reduceCache(num_nodes) {
      var collector = new NodeCollector(this._croot); // 基準に基づき、ノードを前半 (num_cnodes 個) と後半に分割

      collector.nodes.sort(function (a, b) {
        var aframe = b.aframe - a.aframe;

        if (aframe == 0) {
          if (a.state === NodeState.LOADED && b.state === NodeState.LOADED) {
            return a.data.z - b.data.z;
          }
        }

        return aframe;
      }); // 後半のノードを削除

      var gl = this._glenv.context;
      collector.nodes.slice(num_nodes).forEach(function (node) {
        if (node.state === NodeState.LOADED) {
          node.data.dispose(gl);
        }

        node.state = NodeState.NONE;
        node.data = null;
      }); // NodeState.NONE の葉ノードを消去

      collector.clean();
    }
  }]);

  return TileTextureCache;
}(); // クラス定数を定義


TileTextureCache._findNearestAncestors_result = new Array(2);
/**
 * @summary キャッシュノード
 *
 * @memberof mapray.TileTextureCache
 * @private
 */

var CacheNode =
/*#__PURE__*/
function () {
  function CacheNode() {
    _classCallCheck(this, CacheNode);

    this.children = [null, null, null, null];
    this.state = NodeState.NONE;
    this.data = null; // TileTexture オブジェクト、または取り消しオブジェクト

    this.req_power = -1; // 要求度

    this.aframe = -1; // 最終アクセスフレーム
  }
  /**
   * 要求度を更新
   */


  _createClass(CacheNode, [{
    key: "updateRequestPower",
    value: function updateRequestPower(req_power) {
      if (req_power > this.req_power) {
        this.req_power = req_power;
      }
    }
    /**
     * このタイルにアクセスしたことにする
     */

  }, {
    key: "touch",
    value: function touch() {
      this.aframe = true;
    }
  }]);

  return CacheNode;
}();
/**
 * @summary ノード数の計上
 *
 * this.num_loadeds:  ロードされているタイル数
 * this.num_accesses: ロードされているタイルのうち、アクセスされたタイル数
 *
 * アクセスがあったノードに対して aframe を更新する。
 *
 * @memberof mapray.TileTextureCache
 * @private
 */


var NodeCounter =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.TileTextureCache.CacheNode} root   最上位ノード
   * @param {number}                            frame  現在のフレーム
   */
  function NodeCounter(root, frame) {
    _classCallCheck(this, NodeCounter);

    this.num_loadeds = 0;
    this.num_accesses = 0;
    this._frame = frame;

    this._traverse(root);
  }
  /**
   * @private
   */


  _createClass(NodeCounter, [{
    key: "_traverse",
    value: function _traverse(node) {
      var children = node.children;
      var isAccessed = node.aframe === true;

      for (var i = 0; i < 4; ++i) {
        var child = children[i];

        if (child !== null) {
          isAccessed = this._traverse(child) || isAccessed;
        }
      }

      if (node.state === NodeState.LOADED) {
        ++this.num_loadeds;

        if (isAccessed) {
          ++this.num_accesses;
        }
      }

      if (isAccessed) {
        // アクセスフレームを更新
        node.aframe = this._frame;
      }

      return isAccessed;
    }
  }]);

  return NodeCounter;
}();
/**
 * @summary ノード収集
 * @desc
 * <p>NodeState.LOADED または NodeState.FAILED のノードを this.nodes に収集する。</p>
 *
 * @memberof mapray.TileTextureCache
 * @private
 */


var NodeCollector =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.TileTextureCache.CacheNode} root  最上位ノード
   */
  function NodeCollector(root) {
    _classCallCheck(this, NodeCollector);

    this._root = root;
    this.nodes = [];

    this._traverse(root);
  }
  /**
   * @private
   */


  _createClass(NodeCollector, [{
    key: "_traverse",
    value: function _traverse(node) {
      var state = node.state;

      if (state === NodeState.LOADED || state === NodeState.FAILED) {
        // LOADED または FAILED なら追加
        this.nodes.push(node);
      }

      var children = node.children;

      for (var i = 0; i < 4; ++i) {
        var child = children[i];

        if (child !== null) {
          this._traverse(child);
        }
      }
    }
    /**
     * @summary NodeState.NONE の葉ノードを消去
     */

  }, {
    key: "clean",
    value: function clean() {
      this._clean_recur(this._root);
    }
    /**
     * @return 自己と子孫がすべて NodeState.NONE のとき true, それいがいのとき false
     * @private
     */

  }, {
    key: "_clean_recur",
    value: function _clean_recur(node) {
      var isNodeNone = node.state === NodeState.NONE;
      var children = node.children;

      for (var i = 0; i < 4; ++i) {
        var child = children[i];

        if (child !== null) {
          var isChildNone = this._clean_recur(child);

          if (isChildNone === true) {
            children[i] = null;
          }

          isNodeNone = isChildNone && isNodeNone;
        }
      }

      return isNodeNone;
    }
  }]);

  return NodeCollector;
}();
/**
 * @summary すべてのリクエストを取り消す
 * @memberof mapray.TileTextureCache
 * @private
 */


var NodeCanceller =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.TileTextureCache}          owner  最上位ノード
   * @param {mapray.TileTextureCache.CacheNode} root  最上位ノード
   */
  function NodeCanceller(owner, root) {
    _classCallCheck(this, NodeCanceller);

    this._owner = owner;

    this._traverse(root);
  }
  /**
   * @private
   */


  _createClass(NodeCanceller, [{
    key: "_traverse",
    value: function _traverse(node) {
      var children = node.children;

      for (var i = 0; i < 4; ++i) {
        var child = children[i];

        if (child !== null) {
          this._traverse(child);
        }
      }

      if (node.state === NodeState.REQUESTED) {
        var owner = this._owner;
        node.state = NodeState.NONE;

        owner._provider.cancelRequest(node.data);

        --owner._num_requesteds;
      }
    }
  }]);

  return NodeCanceller;
}();
/**
 * @summary ノード状態の列挙型
 * @enum {object}
 * @memberof mapray.TileTextureCache
 * @constant
 */


var NodeState = {
  /**
   * タイルが存在しない
   */
  NONE: {
    id: "NONE"
  },

  /**
   * タイルが存在する
   */
  LOADED: {
    id: "LOADED"
  },

  /**
   * タイルをリクエスト中
   */
  REQUESTED: {
    id: "REQUESTED"
  },

  /**
   * タイルのリクエストに失敗
   */
  FAILED: {
    id: "FAILED"
  }
};

var surface_vs_code = "attribute vec4 a_position;         // 位置 (地表断片座標系)\nattribute vec2 a_uv;               // uv 座標\n\nuniform mat4  u_obj_to_clip;       // 地表断片座標系からクリップ座標系への変換\n\nuniform vec4  u_texcoord_rect_hi;  // 高レベル画像 左下座標: (x, y), 座標サイズ: (z, w)\nuniform vec4  u_texcoord_rect_lo;  // 低レベル画像 左下座標: (x, y), 座標サイズ: (z, w)\nuniform vec4  u_corner_lod;        // uv = (0,0), (1,0), (0,1), (1,1) の LOD\n\nvarying vec2  v_texcoord_hi;       // 高レベル画像のテクスチャ座標\nvarying vec2  v_texcoord_lo;       // 低レベル画像のテクスチャ座標\nvarying float v_lod;               // 補間された LOD\n\nvoid main()\n{\n    gl_Position = u_obj_to_clip * a_position;\n\n    // uv 座標をテクスチャ座標に変換\n    v_texcoord_hi = u_texcoord_rect_hi.xy + u_texcoord_rect_hi.zw * a_uv;\n    v_texcoord_lo = u_texcoord_rect_lo.xy + u_texcoord_rect_lo.zw * a_uv;\n\n    // LOD の補間\n    float u = a_uv.x;\n    float v = a_uv.y;\n\n    float lod_00 = u_corner_lod.x;  // uv = (0,0) の LOD\n    float lod_10 = u_corner_lod.y;  // uv = (1,0) の LOD\n    float lod_01 = u_corner_lod.z;  // uv = (0,1) の LOD\n    float lod_11 = u_corner_lod.w;  // uv = (1,1) の LOD\n\n    float lod_u0 = mix( lod_00, lod_10, u );  // uv = (u, 0) の LOD\n    float lod_u1 = mix( lod_01, lod_11, u );  // uv = (u, 1) の LOD\n    float lod_uv = mix( lod_u0, lod_u1, v );  // uv = (u, v) の LOD\n\n    v_lod = lod_uv;\n}\n";

var surface_fs_code = "precision mediump float;\n\nvarying vec2  v_texcoord_hi;    // 高レベル画像のテクスチャ座標\nvarying vec2  v_texcoord_lo;    // 低レベル画像のテクスチャ座標\nvarying float v_lod;            // 補間された LOD\n\nuniform sampler2D u_image_hi;   // 高レベル画像\nuniform sampler2D u_image_lo;   // 低レベル画像\nuniform float     u_opacity;    // 不透明度\n\n/** 画像パラメータ\n *\n *  x = u_image_lo の LOD\n *  y = 1 / (u_image_hi の LOD - x)\n *\n *  ただし u_image_hi と u_image_lo が同じ画像のときは y = 0\n */\nuniform vec2 u_image_param;\n\n\nvoid main()\n{\n    vec4 color_hi = texture2D( u_image_hi, v_texcoord_hi );\n    vec4 color_lo = texture2D( u_image_lo, v_texcoord_lo );\n\n    // 画像の混合率\n    float lo_lod = u_image_param.x;\n    float  delta = u_image_param.y;\n    float  ratio = clamp( (v_lod - lo_lod) * delta, 0.0, 1.0 );\n\n    gl_FragColor = mix( color_lo, color_hi, ratio );\n    gl_FragColor.a *= u_opacity;  // 不透明度を適用\n}\n";

/**
 * @summary 地表面マテリアル
 * @memberof mapray.RenderStage
 * @extends mapray.RenderStage.FlakeMaterial
 * @private
 */

var SurfaceMaterial =
/*#__PURE__*/
function (_FlakeMaterial) {
  _inherits(SurfaceMaterial, _FlakeMaterial);

  /**
   * @param {mapray.Viewer} viewer  所有者である Viewer
   */
  function SurfaceMaterial(viewer) {
    var _this;

    _classCallCheck(this, SurfaceMaterial);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(SurfaceMaterial).call(this, viewer, surface_vs_code, surface_fs_code));

    _this.bindProgram();

    _this.setInteger("u_image_hi", SurfaceMaterial.TEXUNIT_IMAGE_HI);

    _this.setInteger("u_image_lo", SurfaceMaterial.TEXUNIT_IMAGE_LO);

    _this._tile_texture_cache = viewer.tile_texture_cache;
    _this._layers = viewer.layers;
    _this._dummy_tile_texture = _this._createDummyTileTexture(viewer.glenv);
    _this._image_zbias = 0;
    return _this;
  }
  /**
   * @override
   */


  _createClass(SurfaceMaterial, [{
    key: "numDrawings",
    value: function numDrawings() {
      return 1 + this._layers.numDrawingLayers();
    }
    /**
     * @override
     */

  }, {
    key: "setFlakeParameter",
    value: function setFlakeParameter(stage, rflake, mesh, index) {
      this.setCommonParameter(stage, mesh);

      var param = this._getMaterialParamater(rflake, index);

      if (param !== null) {
        this.setVector4("u_corner_lod", param.corner_lod);
        this.setVector4("u_texcoord_rect_hi", param.image_hi.texcoord_rect);
        this.setVector4("u_texcoord_rect_lo", param.image_lo.texcoord_rect);
        this.setVector2("u_image_param", [param.image_lo.lod, param.image_hi.lod == param.image_lo.lod ? 0 : 1 / (param.image_hi.lod - param.image_lo.lod)]);
        this.setFloat("u_opacity", index == 0 ? 1.0 : this._layers.getDrawingLayer(index - 1).opacity);
        this.bindTexture2D(SurfaceMaterial.TEXUNIT_IMAGE_HI, param.image_hi.texture);
        this.bindTexture2D(SurfaceMaterial.TEXUNIT_IMAGE_LO, param.image_lo.texture);
        return true;
      } else {
        return false;
      }
    }
    /**
     * @summary SurfaceMaterial のパラメータを取得
     * @desc
     * <pre>
     * オブジェクト構造
     * {
     *    // 四隅の地表詳細レベル
     *    corner_lod: [lod_00, lod_10, lod_01, lod_11],
     *
     *    // 高レベル画像の情報
     *    image_hi: { lod: (number), texture: (WebGLTexture), texcoord_rect: [s, t, w, h] },
     *
     *    // 低レベル画像の情報
     *    image_lo: { lod: (number), texture: (WebGLTexture), texcoord_rect: [s, t, w, h] }
     * }
     * </pre>
     * @private
     */

  }, {
    key: "_getMaterialParamater",
    value: function _getMaterialParamater(rflake, index) {
      var tex_cache = index == 0 ? this._tile_texture_cache : this._layers.getDrawingLayer(index - 1).tile_cache;
      this._image_zbias = tex_cache.getImageZBias();
      var flake = rflake.flake;
      var zg = flake.z;

      if (zg < tex_cache.getImageZMin()) {
        return null;
      }

      var x = flake.x;
      var y = flake.y;
      var zi = Math.ceil(rflake.lod + this._image_zbias);

      if (zg < zi) {
        return null;
      }

      var tiles = tex_cache.findNearestAncestors(zg, x, y, zi);

      if (index >= 1 && tiles[0] === null) {
        return null;
      }

      return {
        corner_lod: [rflake.lod_00, rflake.lod_10, rflake.lod_01, rflake.lod_11],
        image_hi: this._getImageParamater(tiles[0], zg, x, y, zi),
        image_lo: this._getImageParamater(tiles[1], zg, x, y, zi - 1)
      };
    }
    /**
     * @summary 画像パラメータを取得
     * @desc
     * <pre>
     * オブジェクト構造
     * {
     *    lod:           (number),
     *    texture:       (WebGLTexture),
     *    texcoord_rect: [s, t, w, h]
     * }
     * </pre>
     * @private
     */

  }, {
    key: "_getImageParamater",
    value: function _getImageParamater(tile, zg, x, y, zi) {
      var pow;

      if (tile !== null) {
        pow = Math.pow(2, tile.z - zg);
        return {
          lod: tile.z - this._image_zbias,
          texture: tile.texture,
          texcoord_rect: [x * pow - tile.x, 1 - (y + 1) * pow + tile.y, pow, pow]
        };
      } else {
        pow = Math.pow(2, -zg);
        return {
          lod: -this._image_zbias,
          texture: this._dummy_tile_texture,
          texcoord_rect: [x * pow - Math.floor(pow * (x + 0.5)), 1 - (y + 1) * pow + Math.floor(pow * (y + 0.5)), pow, pow]
        };
      }
    }
    /**
     * @private
     */

  }, {
    key: "_createDummyTileTexture",
    value: function _createDummyTileTexture(glenv) {
      var gl = glenv.context;
      var target = gl.TEXTURE_2D;
      var texture = gl.createTexture();
      var pixels = [128, 128, 128, 255];
      gl.bindTexture(target, texture);
      gl.texImage2D(target, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(pixels));
      gl.bindTexture(target, null);
      return texture;
    }
  }]);

  return SurfaceMaterial;
}(FlakeMaterial);

SurfaceMaterial.TEXUNIT_IMAGE_HI = 0; // 高レベル画像のテクスチャユニット

SurfaceMaterial.TEXUNIT_IMAGE_LO = 1; // 低レベル画像のテクスチャユニット

var wireframe_vs_code = "attribute vec4 a_position;\nattribute vec2 a_uv;\n\nuniform mat4 u_obj_to_clip;\n\nvarying vec2 v_uv;\n\nvoid main()\n{\n    gl_Position = u_obj_to_clip * a_position;\n    v_uv  = a_uv;\n}\n";

var wireframe_fs_code = "precision mediump float;\n\nvarying vec2 v_uv;\n\nvoid main()\n{\n    vec4 color = (v_uv.x < 0.005 || v_uv.y < 0.005 || v_uv.x > 0.995 || v_uv.y > 0.995) ?\n                 vec4( 1, 1, 0, 1 ) : vec4( 0.5, 0.5, 0.5, 1 );\n    gl_FragColor = color;\n}\n";

/**
 * @summary 地表ワイヤーフレームマテリアル
 * @memberof mapray.RenderStage
 * @extends mapray.RenderStage.FlakeMaterial
 * @private
 */

var WireframeMaterial =
/*#__PURE__*/
function (_FlakeMaterial) {
  _inherits(WireframeMaterial, _FlakeMaterial);

  /**
   * @param {mapray.Viewer} viewer   所有者 Viewer
   */
  function WireframeMaterial(viewer) {
    _classCallCheck(this, WireframeMaterial);

    return _possibleConstructorReturn(this, _getPrototypeOf(WireframeMaterial).call(this, viewer, wireframe_vs_code, wireframe_fs_code));
  }
  /**
   * @override
   */


  _createClass(WireframeMaterial, [{
    key: "isWireframe",
    value: function isWireframe() {
      return true;
    }
    /**
     * @override
     */

  }, {
    key: "setFlakeParameter",
    value: function setFlakeParameter(stage, rflake, mesh, index) {
      this.setCommonParameter(stage, mesh);
      return true;
    }
  }]);

  return WireframeMaterial;
}(FlakeMaterial);

/**
 * @summary 1フレーム分のレンダリングを実行
 * @desc
 * {@link mapray.Viewer} インスタンスはフレーム毎にこのクラスのインスタンスを生成してレンダリングを実行する。
 *
 * @memberof mapray
 * @private
 */

var RenderStage =
/*#__PURE__*/
function () {
  /**
   * @param viewer {mapray.Viewer}  所有者である Viewer
   */
  function RenderStage(viewer) {
    _classCallCheck(this, RenderStage);

    this._viewer = viewer;
    this._glenv = viewer.glenv;
    var canvas = viewer.canvas_element;
    this._width = canvas.width;
    this._height = canvas.height;

    if (this._width === 0 || this._height === 0) {
      // 画素がないのでレンダリングを省略
      this._rendering_cancel = true;
      return;
    }

    var camera = viewer.camera;
    var renderInfo = camera.createRenderInfo(); // _view_to_gocs, _gocs_to_view, _view_to_clip, _gocs_to_clip

    this._setupBasicMatrices(renderInfo, camera); // カメラ情報


    this._volume_planes = renderInfo.volume_planes; // 視体積の平面ベクトル配列 (視点空間)

    this._pixel_step = renderInfo.pixel_step; // 画素の変化量 (視点空間)
    // モデルシーン

    this._scene = viewer.scene; // リソースキャッシュ

    this._globe = viewer.globe;
    this._tile_texture_cache = viewer.tile_texture_cache; // フレーム間のオブジェクトキャッシュ

    if (!viewer._render_cache) {
      viewer._render_cache = {
        // 地表マテリアル
        surface_material: new SurfaceMaterial(viewer),
        wireframe_material: new WireframeMaterial(viewer)
      };
    } // 地表マテリアルの選択


    this._flake_material = viewer.render_mode === Viewer.RenderMode.WIREFRAME ? viewer._render_cache.wireframe_material : viewer._render_cache.surface_material; // デバッグ統計

    this._debug_stats = viewer.debug_stats;
  }
  /**
   * @private
   */


  _createClass(RenderStage, [{
    key: "_setupBasicMatrices",
    value: function _setupBasicMatrices(renderInfo, camera) {
      this._view_to_gocs = camera.view_to_gocs;
      this._gocs_to_view = GeoMath.createMatrix();
      GeoMath.inverse_A(this._view_to_gocs, this._gocs_to_view);
      this._view_to_clip = renderInfo.view_to_clip;
      this._gocs_to_clip = GeoMath.createMatrix();
      GeoMath.mul_PzA(this._view_to_clip, this._gocs_to_view, this._gocs_to_clip);
    }
    /**
     * @summary 1フレームのレンダリングを実行
     */

  }, {
    key: "render",
    value: function render() {
      if (this._rendering_cancel) return;
      var gl = this._glenv.context; // Canvas 全体にビューポートを設定

      gl.viewport(0, 0, this._width, this._height);
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
      gl.enable(gl.CULL_FACE);
      gl.enable(gl.DEPTH_TEST);
      gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE); // FB のα値は変えない

      gl.depthFunc(gl.LEQUAL); // 地表断片データの収集

      if (this._globe.status !== Globe.Status.READY) {
        // まだ基底タイルデータが読み込まれていないので地表をレンダリングできない
        return;
      }

      var collector = new FlakeCollector(this);
      var flake_list = collector.traverse();

      var vis_ground = this._viewer.getVisibility(Viewer.Category.GROUND);

      var vis_entity = this._viewer.getVisibility(Viewer.Category.ENTITY); // すべての地表断片を描画


      this._prepare_draw_flake();

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = flake_list[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var rflake = _step.value;
          var fro = rflake.getRenderObject();

          if (vis_ground) {
            this._draw_flake_base(rflake, fro.getBaseMesh());
          }

          if (vis_entity) {
            this._draw_entities_on_flake(fro);
          }
        } // モデルシーン描画

      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      if (vis_entity) {
        this._scene.draw(this);
      } // 描画地表断片数を記録


      var stats = this._debug_stats;

      if (stats !== null) {
        stats.num_drawing_flakes = flake_list.length;
      } // フレーム終了処理


      this._globe.endFrame();

      this._tile_texture_cache.endFrame();

      this._viewer.layers.endFrame();
    }
    /**
     * @summary 地表断片を描画する前の準備
     *
     * @private
     */

  }, {
    key: "_prepare_draw_flake",
    value: function _prepare_draw_flake() {
      // RenderFlake#getRenderObject() の前に必要な処理
      var producers = this._scene.getFlakePrimitiveProducers();

      this._globe.putNextEntityProducers(producers);
    }
    /**
     * @summary 地表とレイヤーを描画
     *
     * @param {mapray.RenderFlake} rflake  地表断片データ
     * @param {mapray.FlakeMesh}   mesh    地表断片メッシュ
     *
     * @private
     */

  }, {
    key: "_draw_flake_base",
    value: function _draw_flake_base(rflake, mesh) {
      var gl = this._glenv.context;
      var material = this._flake_material;
      material.bindProgram();
      var num_drawings = material.numDrawings(); // 一番下の不透明地表

      if (material.setFlakeParameter(this, rflake, mesh, 0)) {
        gl.disable(gl.BLEND);
        gl.depthMask(true);
        mesh.draw(material);
      } // レイヤーの地表 (半透明の可能背あり)


      for (var i = 1; i < num_drawings; ++i) {
        if (material.setFlakeParameter(this, rflake, mesh, i)) {
          gl.enable(gl.BLEND);
          gl.depthMask(false);
          mesh.draw(material);
        }
      } // 描画地表断頂点数を記録


      var stats = this._debug_stats;

      if (stats !== null) {
        stats.num_drawing_flake_vertices += mesh.num_vertices;
      }
    }
    /**
     * @summary 地表断片上のエンティティを描画
     *
     * @param {mapray.FlakeRenderObject} fro  FlakeRenderObject インスタンス
     *
     * @private
     */

  }, {
    key: "_draw_entities_on_flake",
    value: function _draw_entities_on_flake(fro) {
      var num_entities = fro.num_entities;

      if (num_entities == 0) {
        // エンティティなし
        return;
      }

      var gl = this._glenv.context;
      gl.enable(gl.POLYGON_OFFSET_FILL);
      gl.depthMask(false); // 地表に張り付いていることが前提なので深度は変更しない
      // todo: 仮のポリゴンオフセット
      // 実験で得た適切な値 (Windows, GeForce GT750)
      //   Chrome+ANGLE: -8, -8
      //   Chrome+EGL: -40, -40

      gl.polygonOffset(-8, -8);

      for (var i = 0; i < num_entities; ++i) {
        var primirive = fro.getEntityPrimitive(i, this);

        if (primirive.isTranslucent(this)) {
          gl.enable(gl.BLEND);
        } else {
          gl.disable(gl.BLEND);
        }

        primirive.draw(this);
      }

      gl.disable(gl.POLYGON_OFFSET_FILL);
    }
  }]);

  return RenderStage;
}();

/**
 * @summary クレデンシャルモード
 * @desc
 * <p>HTTP リクエストのクレデンシャルモードを表現する型である。<p>
 * @enum {object}
 * @memberof mapray
 * @constant
 * @see https://developer.mozilla.org/docs/Web/API/Request/credentials
 * @see mapray.StandardDemProvider
 */
var CredentialMode = {
  /**
   * 決してクッキーを送信しない
   */
  OMIT: {
    id: "OMIT",
    credentials: "omit"
  },

  /**
   * URL が呼び出し元のスクリプトと同一オリジンだった場合のみ、クッキーを送信
   */
  SAME_ORIGIN: {
    id: "SAME_ORIGIN",
    credentials: "same-origin"
  },

  /**
   * クロスオリジンの呼び出しであっても、常にクッキーを送信
   */
  INCLUDE: {
    id: "INCLUDE",
    credentials: "include"
  }
};

/**
 * @summary 標準地図画像プロバイダ
 * @classdesc
 * <p>汎用的な地図画像プロバイダの実装である。</p>
 * <p>構築子の引数に prefix, suffix, size, zmin, zmax を与えた場合、各メソッドの動作は以下のようになる。
 * ここで c1, c2, c3 は opts.coord_order の指定に従った第1、第2、第3の座標である。</p>
 * <pre>
 *   requestTile( z, x, y ) -> URL が prefix + c1 + '/' + c2 + '/' + c3 + suffix の画像を要求
 *   getImageSize()         -> size を返す
 *   getZoomLevelRange()    -> new ImageProvider.Range( zmin, zmax ) を返す
 * </pre>
 * @memberof mapray
 * @extends mapray.ImageProvider
 */

var StandardImageProvider =
/*#__PURE__*/
function (_ImageProvider) {
  _inherits(StandardImageProvider, _ImageProvider);

  /**
   * @param {string} prefix  URL の先頭文字列
   * @param {string} suffix  URL の末尾文字列
   * @param {number} size    地図タイル画像の寸法
   * @param {number} zmin    最小ズームレベル
   * @param {number} zmax    最大ズームレベル
   * @param {object} [opts]  オプション集合
   * @param {mapray.StandardImageProvider.CoordOrder}  [opts.coord_order=ZXY]          URL の座標順序
   * @param {mapray.StandardImageProvider.CoordSystem} [opts.coord_system=UPPER_LEFT]  タイル XY 座標系
   * @param {mapray.CredentialMode}                    [opts.credentials=SAME_ORIGIN]  クレデンシャルモード
   */
  function StandardImageProvider(prefix, suffix, size, zmin, zmax, opts) {
    var _this;

    _classCallCheck(this, StandardImageProvider);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(StandardImageProvider).call(this));
    _this._prefix = prefix;
    _this._suffix = suffix;
    _this._size = size;
    _this._min_level = zmin;
    _this._max_level = zmax; // タイル座標を並び替える関数

    var orderCoords;

    if (opts && opts.coord_order) {
      if (opts.coord_order === CoordOrder.ZYX) {
        orderCoords = function orderCoords(z, x, y) {
          return z + "/" + y + "/" + x;
        };
      } else if (opts.coord_order === CoordOrder.XYZ) {
        orderCoords = function orderCoords(z, x, y) {
          return x + "/" + y + "/" + z;
        };
      }
    }

    if (!orderCoords) {
      // その他の場合は既定値 COORD_ORDER_ZXY を使う
      orderCoords = function orderCoords(z, x, y) {
        return z + "/" + x + "/" + y;
      };
    } // XY 座標を変換する関数


    var convCoords;

    if (opts && opts.coord_system) {
      if (opts.coord_system === CoordSystem.LOWER_LEFT) {
        convCoords = function convCoords(z, x, y) {
          var size = Math.round(Math.pow(2, z));
          return orderCoords(z, x, size - y - 1);
        };
      }
    }

    if (!convCoords) {
      // その他の場合は既定値 UPPER_LEFT (無変換) を使う
      convCoords = orderCoords;
    } // 座標部分の URL を取得する関数


    _this._coords_part = convCoords; // crossorigin 属性の値

    _this._crossOrigin = "anonymous";

    if (opts && opts.credentials) {
      if (opts.credentials === CredentialMode.OMIT) {
        _this._crossOrigin = null;
      } else if (opts.credentials === CredentialMode.INCLUDE) {
        _this._crossOrigin = "use-credentials";
      }
    }

    return _this;
  }
  /**
   * @override
   */


  _createClass(StandardImageProvider, [{
    key: "requestTile",
    value: function requestTile(z, x, y, callback) {
      var image = new Image();

      image.onload = function () {
        callback(image);
      };

      image.onerror = function () {
        callback(null);
      };

      if (this._crossOrigin !== null) {
        image.crossOrigin = this._crossOrigin;
      }

      image.src = this._makeURL(z, x, y);
      return image; // 要求 ID (実態は Image)
    }
    /**
     * @override
     */

  }, {
    key: "cancelRequest",
    value: function cancelRequest(id) {} // TODO: Image 読み込みの取り消し方法は不明

    /**
     * @override
     */

  }, {
    key: "getImageSize",
    value: function getImageSize() {
      return this._size;
    }
    /**
     * @override
     */

  }, {
    key: "getZoomLevelRange",
    value: function getZoomLevelRange() {
      return new ImageProvider.Range(this._min_level, this._max_level);
    }
    /**
     * URL を作成
     * @private
     */

  }, {
    key: "_makeURL",
    value: function _makeURL(z, x, y) {
      return this._prefix + this._coords_part(z, x, y) + this._suffix;
    }
  }]);

  return StandardImageProvider;
}(ImageProvider);
/**
 * @summary URL 座標順序の列挙型
 * @desc
 * {@link mapray.StandardImageProvider} の構築子で opts.coord_order パラメータに指定する値の型である。
 * @enum {object}
 * @memberof mapray.StandardImageProvider
 * @constant
 */


var CoordOrder = {
  /**
   * 座標順序 Z/X/Y (既定値)
   */
  ZXY: {
    id: "ZXY"
  },

  /**
   * 座標順序 Z/Y/X
   */
  ZYX: {
    id: "ZYX"
  },

  /**
   * 座標順序 Z/X/Y
   */
  XYZ: {
    id: "XYZ"
  }
};
/**
 * @summary タイル XY 座標系の列挙型
 * @desc
 * {@link mapray.StandardImageProvider} の構築子で opts.coord_system パラメータに指定する値の型である。
 * @enum {object}
 * @memberof mapray.StandardImageProvider
 * @constant
 */

var CoordSystem = {
  /**
   * 原点:左上, X軸:右方向, Y軸:下方向 (既定値)
   */
  UPPER_LEFT: {
    id: "UPPER_LEFT"
  },

  /**
   * 原点:左下, X軸:右方向, Y軸:上方向
   */
  LOWER_LEFT: {
    id: "LOWER_LEFT"
  }
}; // クラス定数の定義

{
  StandardImageProvider.CoordOrder = CoordOrder;
  StandardImageProvider.CoordSystem = CoordSystem;
}

var nativeAssign = Object.assign;
var defineProperty$9 = Object.defineProperty; // `Object.assign` method
// https://tc39.github.io/ecma262/#sec-object.assign

var objectAssign = !nativeAssign || fails(function () {
  // should have correct order of operations (Edge bug)
  if (descriptors && nativeAssign({
    b: 1
  }, nativeAssign(defineProperty$9({}, 'a', {
    enumerable: true,
    get: function () {
      defineProperty$9(this, 'b', {
        value: 3,
        enumerable: false
      });
    }
  }), {
    b: 2
  })).b !== 1) return true; // should work with symbols and should have deterministic property order (V8 bug)

  var A = {};
  var B = {}; // eslint-disable-next-line no-undef

  var symbol = Symbol();
  var alphabet = 'abcdefghijklmnopqrst';
  A[symbol] = 7;
  alphabet.split('').forEach(function (chr) {
    B[chr] = chr;
  });
  return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet;
}) ? function assign(target, source) {
  // eslint-disable-line no-unused-vars
  var T = toObject(target);
  var argumentsLength = arguments.length;
  var index = 1;
  var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
  var propertyIsEnumerable = objectPropertyIsEnumerable.f;

  while (argumentsLength > index) {
    var S = indexedObject(arguments[index++]);
    var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
    var length = keys.length;
    var j = 0;
    var key;

    while (length > j) {
      key = keys[j++];
      if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
    }
  }

  return T;
} : nativeAssign;

// https://tc39.github.io/ecma262/#sec-object.assign

_export({
  target: 'Object',
  stat: true,
  forced: Object.assign !== objectAssign
}, {
  assign: objectAssign
});

var nativePromiseConstructor = global_1.Promise;

var engineIsIos = /(iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent);

var location = global_1.location;
var set$2 = global_1.setImmediate;
var clear = global_1.clearImmediate;
var process$1 = global_1.process;
var MessageChannel = global_1.MessageChannel;
var Dispatch = global_1.Dispatch;
var counter = 0;
var queue = {};
var ONREADYSTATECHANGE = 'onreadystatechange';
var defer, channel, port;

var run = function (id) {
  // eslint-disable-next-line no-prototype-builtins
  if (queue.hasOwnProperty(id)) {
    var fn = queue[id];
    delete queue[id];
    fn();
  }
};

var runner = function (id) {
  return function () {
    run(id);
  };
};

var listener = function (event) {
  run(event.data);
};

var post = function (id) {
  // old engines have not location.origin
  global_1.postMessage(id + '', location.protocol + '//' + location.host);
}; // Node.js 0.9+ & IE10+ has setImmediate, otherwise:


if (!set$2 || !clear) {
  set$2 = function setImmediate(fn) {
    var args = [];
    var i = 1;

    while (arguments.length > i) args.push(arguments[i++]);

    queue[++counter] = function () {
      // eslint-disable-next-line no-new-func
      (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
    };

    defer(counter);
    return counter;
  };

  clear = function clearImmediate(id) {
    delete queue[id];
  }; // Node.js 0.8-


  if (classofRaw(process$1) == 'process') {
    defer = function (id) {
      process$1.nextTick(runner(id));
    }; // Sphere (JS game engine) Dispatch API

  } else if (Dispatch && Dispatch.now) {
    defer = function (id) {
      Dispatch.now(runner(id));
    }; // Browsers with MessageChannel, includes WebWorkers
    // except iOS - https://github.com/zloirock/core-js/issues/624

  } else if (MessageChannel && !engineIsIos) {
    channel = new MessageChannel();
    port = channel.port2;
    channel.port1.onmessage = listener;
    defer = functionBindContext(port.postMessage, port, 1); // Browsers with postMessage, skip WebWorkers
    // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
  } else if (global_1.addEventListener && typeof postMessage == 'function' && !global_1.importScripts && !fails(post)) {
    defer = post;
    global_1.addEventListener('message', listener, false); // IE8-
  } else if (ONREADYSTATECHANGE in documentCreateElement('script')) {
    defer = function (id) {
      html.appendChild(documentCreateElement('script'))[ONREADYSTATECHANGE] = function () {
        html.removeChild(this);
        run(id);
      };
    }; // Rest old browsers

  } else {
    defer = function (id) {
      setTimeout(runner(id), 0);
    };
  }
}

var task = {
  set: set$2,
  clear: clear
};

var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
var macrotask = task.set;
var MutationObserver = global_1.MutationObserver || global_1.WebKitMutationObserver;
var process$2 = global_1.process;
var Promise$1 = global_1.Promise;
var IS_NODE = classofRaw(process$2) == 'process'; // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`

var queueMicrotaskDescriptor = getOwnPropertyDescriptor$3(global_1, 'queueMicrotask');
var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
var flush, head, last, notify, toggle, node, promise, then; // modern engines have queueMicrotask method

if (!queueMicrotask) {
  flush = function () {
    var parent, fn;
    if (IS_NODE && (parent = process$2.domain)) parent.exit();

    while (head) {
      fn = head.fn;
      head = head.next;

      try {
        fn();
      } catch (error) {
        if (head) notify();else last = undefined;
        throw error;
      }
    }

    last = undefined;
    if (parent) parent.enter();
  }; // Node.js


  if (IS_NODE) {
    notify = function () {
      process$2.nextTick(flush);
    }; // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339

  } else if (MutationObserver && !engineIsIos) {
    toggle = true;
    node = document.createTextNode('');
    new MutationObserver(flush).observe(node, {
      characterData: true
    });

    notify = function () {
      node.data = toggle = !toggle;
    }; // environments with maybe non-completely correct, but existent Promise

  } else if (Promise$1 && Promise$1.resolve) {
    // Promise.resolve without an argument throws an error in LG WebOS 2
    promise = Promise$1.resolve(undefined);
    then = promise.then;

    notify = function () {
      then.call(promise, flush);
    }; // for other environments - macrotask based on:
    // - setImmediate
    // - MessageChannel
    // - window.postMessag
    // - onreadystatechange
    // - setTimeout

  } else {
    notify = function () {
      // strange IE + webpack dev server bug - use .call(global)
      macrotask.call(global_1, flush);
    };
  }
}

var microtask = queueMicrotask || function (fn) {
  var task = {
    fn: fn,
    next: undefined
  };
  if (last) last.next = task;

  if (!head) {
    head = task;
    notify();
  }

  last = task;
};

var PromiseCapability = function (C) {
  var resolve, reject;
  this.promise = new C(function ($$resolve, $$reject) {
    if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
    resolve = $$resolve;
    reject = $$reject;
  });
  this.resolve = aFunction$1(resolve);
  this.reject = aFunction$1(reject);
}; // 25.4.1.5 NewPromiseCapability(C)


var f$7 = function (C) {
  return new PromiseCapability(C);
};

var newPromiseCapability = {
  f: f$7
};

var promiseResolve = function (C, x) {
  anObject(C);
  if (isObject(x) && x.constructor === C) return x;
  var promiseCapability = newPromiseCapability.f(C);
  var resolve = promiseCapability.resolve;
  resolve(x);
  return promiseCapability.promise;
};

var hostReportErrors = function (a, b) {
  var console = global_1.console;

  if (console && console.error) {
    arguments.length === 1 ? console.error(a) : console.error(a, b);
  }
};

var perform = function (exec) {
  try {
    return {
      error: false,
      value: exec()
    };
  } catch (error) {
    return {
      error: true,
      value: error
    };
  }
};

var task$1 = task.set;
var SPECIES$6 = wellKnownSymbol('species');
var PROMISE = 'Promise';
var getInternalState$4 = internalState.get;
var setInternalState$5 = internalState.set;
var getInternalPromiseState = internalState.getterFor(PROMISE);
var PromiseConstructor = nativePromiseConstructor;
var TypeError$1 = global_1.TypeError;
var document$2 = global_1.document;
var process$3 = global_1.process;
var $fetch = getBuiltIn('fetch');
var newPromiseCapability$1 = newPromiseCapability.f;
var newGenericPromiseCapability = newPromiseCapability$1;
var IS_NODE$1 = classofRaw(process$3) == 'process';
var DISPATCH_EVENT = !!(document$2 && document$2.createEvent && global_1.dispatchEvent);
var UNHANDLED_REJECTION = 'unhandledrejection';
var REJECTION_HANDLED = 'rejectionhandled';
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
var HANDLED = 1;
var UNHANDLED = 2;
var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
var FORCED$6 = isForced_1(PROMISE, function () {
  var GLOBAL_CORE_JS_PROMISE = inspectSource(PromiseConstructor) !== String(PromiseConstructor);

  if (!GLOBAL_CORE_JS_PROMISE) {
    // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
    // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
    // We can't detect it synchronously, so just check versions
    if (engineV8Version === 66) return true; // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test

    if (!IS_NODE$1 && typeof PromiseRejectionEvent != 'function') return true;
  } // We need Promise#finally in the pure version for preventing prototype pollution
  // deoptimization and performance degradation
  // https://github.com/zloirock/core-js/issues/679

  if (engineV8Version >= 51 && /native code/.test(PromiseConstructor)) return false; // Detect correctness of subclassing with @@species support

  var promise = PromiseConstructor.resolve(1);

  var FakePromise = function (exec) {
    exec(function () {
      /* empty */
    }, function () {
      /* empty */
    });
  };

  var constructor = promise.constructor = {};
  constructor[SPECIES$6] = FakePromise;
  return !(promise.then(function () {
    /* empty */
  }) instanceof FakePromise);
});
var INCORRECT_ITERATION$1 = FORCED$6 || !checkCorrectnessOfIteration(function (iterable) {
  PromiseConstructor.all(iterable)['catch'](function () {
    /* empty */
  });
}); // helpers

var isThenable = function (it) {
  var then;
  return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
};

var notify$1 = function (promise, state, isReject) {
  if (state.notified) return;
  state.notified = true;
  var chain = state.reactions;
  microtask(function () {
    var value = state.value;
    var ok = state.state == FULFILLED;
    var index = 0; // variable length - can't use forEach

    while (chain.length > index) {
      var reaction = chain[index++];
      var handler = ok ? reaction.ok : reaction.fail;
      var resolve = reaction.resolve;
      var reject = reaction.reject;
      var domain = reaction.domain;
      var result, then, exited;

      try {
        if (handler) {
          if (!ok) {
            if (state.rejection === UNHANDLED) onHandleUnhandled(promise, state);
            state.rejection = HANDLED;
          }

          if (handler === true) result = value;else {
            if (domain) domain.enter();
            result = handler(value); // can throw

            if (domain) {
              domain.exit();
              exited = true;
            }
          }

          if (result === reaction.promise) {
            reject(TypeError$1('Promise-chain cycle'));
          } else if (then = isThenable(result)) {
            then.call(result, resolve, reject);
          } else resolve(result);
        } else reject(value);
      } catch (error) {
        if (domain && !exited) domain.exit();
        reject(error);
      }
    }

    state.reactions = [];
    state.notified = false;
    if (isReject && !state.rejection) onUnhandled(promise, state);
  });
};

var dispatchEvent = function (name, promise, reason) {
  var event, handler;

  if (DISPATCH_EVENT) {
    event = document$2.createEvent('Event');
    event.promise = promise;
    event.reason = reason;
    event.initEvent(name, false, true);
    global_1.dispatchEvent(event);
  } else event = {
    promise: promise,
    reason: reason
  };

  if (handler = global_1['on' + name]) handler(event);else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
};

var onUnhandled = function (promise, state) {
  task$1.call(global_1, function () {
    var value = state.value;
    var IS_UNHANDLED = isUnhandled(state);
    var result;

    if (IS_UNHANDLED) {
      result = perform(function () {
        if (IS_NODE$1) {
          process$3.emit('unhandledRejection', value, promise);
        } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
      }); // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should

      state.rejection = IS_NODE$1 || isUnhandled(state) ? UNHANDLED : HANDLED;
      if (result.error) throw result.value;
    }
  });
};

var isUnhandled = function (state) {
  return state.rejection !== HANDLED && !state.parent;
};

var onHandleUnhandled = function (promise, state) {
  task$1.call(global_1, function () {
    if (IS_NODE$1) {
      process$3.emit('rejectionHandled', promise);
    } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
  });
};

var bind = function (fn, promise, state, unwrap) {
  return function (value) {
    fn(promise, state, value, unwrap);
  };
};

var internalReject = function (promise, state, value, unwrap) {
  if (state.done) return;
  state.done = true;
  if (unwrap) state = unwrap;
  state.value = value;
  state.state = REJECTED;
  notify$1(promise, state, true);
};

var internalResolve = function (promise, state, value, unwrap) {
  if (state.done) return;
  state.done = true;
  if (unwrap) state = unwrap;

  try {
    if (promise === value) throw TypeError$1("Promise can't be resolved itself");
    var then = isThenable(value);

    if (then) {
      microtask(function () {
        var wrapper = {
          done: false
        };

        try {
          then.call(value, bind(internalResolve, promise, wrapper, state), bind(internalReject, promise, wrapper, state));
        } catch (error) {
          internalReject(promise, wrapper, error, state);
        }
      });
    } else {
      state.value = value;
      state.state = FULFILLED;
      notify$1(promise, state, false);
    }
  } catch (error) {
    internalReject(promise, {
      done: false
    }, error, state);
  }
}; // constructor polyfill


if (FORCED$6) {
  // 25.4.3.1 Promise(executor)
  PromiseConstructor = function Promise(executor) {
    anInstance(this, PromiseConstructor, PROMISE);
    aFunction$1(executor);
    Internal.call(this);
    var state = getInternalState$4(this);

    try {
      executor(bind(internalResolve, this, state), bind(internalReject, this, state));
    } catch (error) {
      internalReject(this, state, error);
    }
  }; // eslint-disable-next-line no-unused-vars


  Internal = function Promise(executor) {
    setInternalState$5(this, {
      type: PROMISE,
      done: false,
      notified: false,
      parent: false,
      reactions: [],
      rejection: false,
      state: PENDING,
      value: undefined
    });
  };

  Internal.prototype = redefineAll(PromiseConstructor.prototype, {
    // `Promise.prototype.then` method
    // https://tc39.github.io/ecma262/#sec-promise.prototype.then
    then: function then(onFulfilled, onRejected) {
      var state = getInternalPromiseState(this);
      var reaction = newPromiseCapability$1(speciesConstructor(this, PromiseConstructor));
      reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
      reaction.fail = typeof onRejected == 'function' && onRejected;
      reaction.domain = IS_NODE$1 ? process$3.domain : undefined;
      state.parent = true;
      state.reactions.push(reaction);
      if (state.state != PENDING) notify$1(this, state, false);
      return reaction.promise;
    },
    // `Promise.prototype.catch` method
    // https://tc39.github.io/ecma262/#sec-promise.prototype.catch
    'catch': function (onRejected) {
      return this.then(undefined, onRejected);
    }
  });

  OwnPromiseCapability = function () {
    var promise = new Internal();
    var state = getInternalState$4(promise);
    this.promise = promise;
    this.resolve = bind(internalResolve, promise, state);
    this.reject = bind(internalReject, promise, state);
  };

  newPromiseCapability.f = newPromiseCapability$1 = function (C) {
    return C === PromiseConstructor || C === PromiseWrapper ? new OwnPromiseCapability(C) : newGenericPromiseCapability(C);
  };

  if ( typeof nativePromiseConstructor == 'function') {
    nativeThen = nativePromiseConstructor.prototype.then; // wrap native Promise#then for native async functions

    redefine(nativePromiseConstructor.prototype, 'then', function then(onFulfilled, onRejected) {
      var that = this;
      return new PromiseConstructor(function (resolve, reject) {
        nativeThen.call(that, resolve, reject);
      }).then(onFulfilled, onRejected); // https://github.com/zloirock/core-js/issues/640
    }, {
      unsafe: true
    }); // wrap fetch result

    if (typeof $fetch == 'function') _export({
      global: true,
      enumerable: true,
      forced: true
    }, {
      // eslint-disable-next-line no-unused-vars
      fetch: function fetch(input
      /* , init */
      ) {
        return promiseResolve(PromiseConstructor, $fetch.apply(global_1, arguments));
      }
    });
  }
}

_export({
  global: true,
  wrap: true,
  forced: FORCED$6
}, {
  Promise: PromiseConstructor
});
setToStringTag(PromiseConstructor, PROMISE, false);
setSpecies(PROMISE);
PromiseWrapper = getBuiltIn(PROMISE); // statics

_export({
  target: PROMISE,
  stat: true,
  forced: FORCED$6
}, {
  // `Promise.reject` method
  // https://tc39.github.io/ecma262/#sec-promise.reject
  reject: function reject(r) {
    var capability = newPromiseCapability$1(this);
    capability.reject.call(undefined, r);
    return capability.promise;
  }
});
_export({
  target: PROMISE,
  stat: true,
  forced:  FORCED$6
}, {
  // `Promise.resolve` method
  // https://tc39.github.io/ecma262/#sec-promise.resolve
  resolve: function resolve(x) {
    return promiseResolve( this, x);
  }
});
_export({
  target: PROMISE,
  stat: true,
  forced: INCORRECT_ITERATION$1
}, {
  // `Promise.all` method
  // https://tc39.github.io/ecma262/#sec-promise.all
  all: function all(iterable) {
    var C = this;
    var capability = newPromiseCapability$1(C);
    var resolve = capability.resolve;
    var reject = capability.reject;
    var result = perform(function () {
      var $promiseResolve = aFunction$1(C.resolve);
      var values = [];
      var counter = 0;
      var remaining = 1;
      iterate_1(iterable, function (promise) {
        var index = counter++;
        var alreadyCalled = false;
        values.push(undefined);
        remaining++;
        $promiseResolve.call(C, promise).then(function (value) {
          if (alreadyCalled) return;
          alreadyCalled = true;
          values[index] = value;
          --remaining || resolve(values);
        }, reject);
      });
      --remaining || resolve(values);
    });
    if (result.error) reject(result.value);
    return capability.promise;
  },
  // `Promise.race` method
  // https://tc39.github.io/ecma262/#sec-promise.race
  race: function race(iterable) {
    var C = this;
    var capability = newPromiseCapability$1(C);
    var reject = capability.reject;
    var result = perform(function () {
      var $promiseResolve = aFunction$1(C.resolve);
      iterate_1(iterable, function (promise) {
        $promiseResolve.call(C, promise).then(capability.resolve, reject);
      });
    });
    if (result.error) reject(result.value);
    return capability.promise;
  }
});

/**
 * @summary DEM データプロバイダ
 * @classdesc
 * <p>レンダラーに DEM データを与えるための抽象クラスである。</p>
 * <p>以下の抽象メソッドは既定の動作がないので、利用者はこれらのメソッドをオーバライドした具象クラスを使用しなければならない。</p>
 * <ul>
 *   <li>[requestTile()]{@link mapray.DemProvider#requestTile}</li>
 *   <li>[cancelRequest()]{@link mapray.DemProvider#cancelRequest}</li>
 * </ul>
 * <p>[getResolutionPower()]{@link mapray.DemProvider#getResolutionPower} の既定の実装は 8 を返す。DEM タイルの解像度が 256 以外のときはこのメソッドをオーバーロードする必要がある。</p>
 * @memberof mapray
 * @abstract
 * @protected
 * @see mapray.StandardDemProvider
 * @see mapray.Viewer
 */
var DemProvider =
/*#__PURE__*/
function () {
  function DemProvider() {
    _classCallCheck(this, DemProvider);
  }

  _createClass(DemProvider, [{
    key: "requestTile",

    /**
     * @summary DEM タイルデータを要求
     * @desc
     * <p>座標が (z, x, y) の DEM タイルデータを要求する。</p>
     * <p>指定したタイルデータの取得が成功または失敗したときに callback が非同期に呼び出されなければならない。</p>
     * <p>だたし [cancelRequest()]{@link mapray.DemProvider#cancelRequest} により要求が取り消されたとき、callback は呼び出しても呼び出さなくてもよい。また非同期呼び出しである必要もない。</p>
     * @param  {number}   z  ズームレベル
     * @param  {number}   x  X タイル座標
     * @param  {number}   y  Y タイル座標
     * @param  {mapray.DemProvider.RequestCallback} callback  要求コールバック関数
     * @return {object}   要求 ID ([cancelRequest()]{@link mapray.DemProvider#cancelRequest} に与えるオブジェクト)
     * @abstract
     */
    value: function requestTile(z, x, y, callback) {
      throw new Error("mapray.DemProvider#requestTile() method has not been overridden.");
    }
    /**
     * @summary DEM タイルデータの要求を取り消す
     * <p>[requestTile()]{@link mapray.DemProvider#requestTile} による要求を可能であれば取り消す。</p>
     * @param {object} id  要求 ID ([requestTile()]{@link mapray.DemProvider#requestTile} から得たオブジェクト)
     * @abstract
     */

  }, {
    key: "cancelRequest",
    value: function cancelRequest(id) {
      throw new Error("mapray.DemProvider#cancelRequest() method has not been overridden.");
    }
    /**
     * @summary 解像度の指数を取得
     * @desc
     * <p>DEM タイルデータ解像度の、2 を底とする対数を取得する。DEM タイルデータの解像度は必ず 2 のべき乗である。</p>
     * <p>制限: this が同じなら常に同じ値を返さなければならない。</p>
     * @return {number}  解像度指数
     * @abstract
     */

  }, {
    key: "getResolutionPower",
    value: function getResolutionPower() {
      return 8;
    }
  }]);

  return DemProvider;
}();

/**
 * @summary 標準 DEM プロバイダ
 * @classdesc
 * <p>汎用的な DEM プロバイダの実装である。</p>
 * <p>構築子の引数に prefix を与えた場合、各メソッドの動作は以下のようになる。
 * <pre>
 *   requestTile( z, x, y ) -> URL が prefix + z + '/' + x + '/' + y + suffix のデータを要求
 * </pre>
 * @memberof mapray
 * @extends mapray.DemProvider
 */

var StandardDemProvider =
/*#__PURE__*/
function (_DemProvider) {
  _inherits(StandardDemProvider, _DemProvider);

  /**
   * @param {string} prefix     URL の先頭文字列
   * @param {string} suffix     URL の末尾文字列
   * @param {object} [options]  オプション集合
   * @param {mapray.CredentialMode} [options.credentials=OMIT]  クレデンシャルモード
   * @param {object} [options.headers={}]  リクエストに追加するヘッダーの辞書
   */
  function StandardDemProvider(prefix, suffix, options) {
    var _this;

    _classCallCheck(this, StandardDemProvider);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(StandardDemProvider).call(this));
    var opts = options || {};
    _this._prefix = prefix;
    _this._suffix = suffix;
    _this._credentials = (opts.credentials || CredentialMode.OMIT).credentials;
    _this._headers = Object.assign({}, opts.headers);
    return _this;
  }
  /**
   * @override
   */


  _createClass(StandardDemProvider, [{
    key: "requestTile",
    value: function requestTile(z, x, y, callback) {
      var actrl = new AbortController();
      fetch(this._makeURL(z, x, y), {
        credentials: this._credentials,
        headers: this._headers,
        signal: actrl.signal
      }).then(function (response) {
        return response.ok ? response.arrayBuffer() : Promise.reject(Error(response.statusText));
      }).then(function (buffer) {
        // データ取得に成功
        callback(buffer);
      })["catch"](function () {
        // データ取得に失敗または取り消し
        callback(null);
      });
      return actrl;
    }
    /**
     * @override
     */

  }, {
    key: "cancelRequest",
    value: function cancelRequest(id) {
      var actrl = id; // 要求 ID を AbortController に変換

      actrl.abort(); // 取り消したので要求を中止
    }
    /**
     * URL を作成
     * @private
     */

  }, {
    key: "_makeURL",
    value: function _makeURL(z, x, y) {
      return this._prefix + z + '/' + x + '/' + y + this._suffix;
    }
  }]);

  return StandardDemProvider;
}(DemProvider);

/**
 * @summary 地図レイヤー
 * @classdesc
 * <p>地図レイヤーを表現するオブジェクトである。</p>
 *
 * @hideconstructor
 * @memberof mapray
 * @see mapray.LayerCollection
 */

var Layer =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.LayerCollection}      owner         地図レイヤー管理
   * @param {object|mapray.ImageProvider} init          初期化プロパティ
   * @param {mapray.ImageProvider} init.image_provider  画像プロバイダ
   * @param {boolean}              [init.visibility]    可視性フラグ
   * @param {number}               [init.opacity]       不透明度
   * @package
   */
  function Layer(owner, init) {
    _classCallCheck(this, Layer);

    this._owner = owner;
    this._glenv = owner.glenv;
    var props = init instanceof ImageProvider ? {
      image_provider: init
    } : init;
    this._image_provider = props.image_provider;
    this._visibility = props.visibility || true;
    this._opacity = props.opacity || 1.0;
    this._tile_cache = new TileTextureCache(this._glenv, this._image_provider); // プロバイダの状態が変化したら描画レイヤーを更新

    this._image_provider.status(function (status) {
      owner.dirtyDrawingLayers();
    });
  }
  /**
   * @summary 画像プロバイダを取得
   * @type {mapray.ImageProvider}
   * @readonly
   */


  _createClass(Layer, [{
    key: "setImageProvider",

    /**
     * @summary 画像プロバイダを設定
     *
     * @param {mapray.ImageProvider} provider  画像プロバイダ
     */
    value: function setImageProvider(provider) {
      var _this = this;

      if (this._image_provider !== provider) {
        // プロバイダを変更またはプロバイダの状態が変化したら描画レイヤーを更新
        this._owner.dirtyDrawingLayers();

        provider.status(function (status) {
          _this._owner.dirtyDrawingLayers();
        });
      }

      this._image_provider = provider; // タイルキャッシュを再構築

      this._tile_cache.cancel();

      this._tile_cache = new TileTextureCache(this._glenv, provider);
    }
    /**
     * @summary 可視性フラグを設定
     *
     * @param {boolean} visibility  可視性フラグ
     */

  }, {
    key: "setVisibility",
    value: function setVisibility(visibility) {
      if (this._visibility != visibility) {
        // レイヤーの可視性が変化したら描画レイヤーを更新
        this._owner.dirtyDrawingLayers();
      }

      this._visibility = visibility;
    }
    /**
     * @summary 不透明度を設定
     *
     * @param {number} opacity  不透明度
     */

  }, {
    key: "setOpacity",
    value: function setOpacity(opacity) {
      this._opacity = opacity;
    }
  }, {
    key: "image_provider",
    get: function get() {
      return this._image_provider;
    }
    /**
     * @summary 可視性フラグを取得
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "visibility",
    get: function get() {
      return this._visibility;
    }
    /**
     * @summary 不透明度を取得
     * @type {number}
     * @readonly
     */

  }, {
    key: "opacity",
    get: function get() {
      return this._opacity;
    }
    /**
     * @summary タイルテクスチャキャッシュを取得
     * @type {mapray.TileTextureCache}
     * @readonly
     * @package
     */

  }, {
    key: "tile_cache",
    get: function get() {
      return this._tile_cache;
    }
  }]);

  return Layer;
}();

/**
 * @summary 地図レイヤー管理
 * @classdesc
 * <p>地図レイヤーを管理するオブジェクトである。</p>
 * <p>インスタンスは {@link mapray.Viewer#layers} から得ることができる。</p>
 *
 * @hideconstructor
 * @memberof mapray
 * @see mapray.Layer
 */

var LayerCollection =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.GLEnv} glenv   WebGL 環境
   * @param {array}      layers  初期化プロパティ配列
   * @package
   */
  function LayerCollection(glenv, layers) {
    _classCallCheck(this, LayerCollection);

    this._glenv = glenv;
    this._layers = [];
    this._draw_layers = null; // 初期レイヤーを追加

    for (var i = 0; i < layers.length; ++i) {
      this.add(layers[i]);
    }
  }
  /**
   * @summary WebGL 環境を取得
   * @type {mapray.GLEnv}
   * @readonly
   * @package
   */


  _createClass(LayerCollection, [{
    key: "getLayer",

    /**
     * @summary レイヤーを取得
     *
     * @param  {number} index  レイヤーの場所
     * @return {mapray.Layer}    レイヤー
     */
    value: function getLayer(index) {
      return this._layers[index];
    }
    /**
     * @summary すべてのレイヤーを削除
     */

  }, {
    key: "clear",
    value: function clear() {
      while (this.num_layers() > 0) {
        this.remove(0);
      }
    }
    /**
     * @summary レイヤーを末尾に追加
     *
     * @param {object|mapray.ImageProvider} layer          レイヤーのプロパティ
     * @param {mapray.ImageProvider} layer.image_provider  画像プロバイダ
     * @param {boolean}              [layer.visibility]    可視性フラグ
     * @param {number}               [layer.opacity]       不透明度
     */

  }, {
    key: "add",
    value: function add(layer) {
      this.insert(this.num_layers, layer);
    }
    /**
     * @summary レイヤーを末尾に追加
     *
     * @param {number}                      index          挿入場所
     * @param {object|mapray.ImageProvider} layer          レイヤーのプロパティ
     * @param {mapray.ImageProvider} layer.image_provider  画像プロバイダ
     * @param {boolean}              [layer.visibility]    可視性フラグ
     * @param {number}               [layer.opacity]       不透明度
     */

  }, {
    key: "insert",
    value: function insert(index, layer) {
      this._layers.splice(index, 0, new Layer(this, layer));

      this.dirtyDrawingLayers();
    }
    /**
     * @summary 特定のレイヤーを削除
     *
     * @param {number} index  削除場所
     */

  }, {
    key: "remove",
    value: function remove(index) {
      this._layers.splice(index, 1);

      this.dirtyDrawingLayers();
    }
    /**
     * @summary 描画レイヤー数を取得
     *
     * @return {number}  描画レイヤー数
     * @package
     */

  }, {
    key: "numDrawingLayers",
    value: function numDrawingLayers() {
      if (this._draw_layers === null) {
        this._updataDrawingLayers();
      }

      return this._draw_layers.length;
    }
    /**
     * @summary 描画レイヤーを取得
     *
     * @param  {number} index  レイヤーの場所
     * @return {mapray.Layer}  レイヤー
     * @package
     */

  }, {
    key: "getDrawingLayer",
    value: function getDrawingLayer(index) {
      if (this._draw_layers === null) {
        this._updataDrawingLayers();
      }

      return this._draw_layers[index];
    }
    /**
     * @summary フレームの最後の処理
     * @package
     */

  }, {
    key: "endFrame",
    value: function endFrame() {
      var layers = this._layers;

      for (var i = 0; i < layers.length; ++i) {
        layers[i].tile_cache.endFrame();
      }
    }
    /**
     * @summary 取り消し処理
     * @package
     */

  }, {
    key: "cancel",
    value: function cancel() {
      var layers = this._layers;

      for (var i = 0; i < layers.length; ++i) {
        layers[i].tile_cache.cancel();
      }
    }
    /**
     * @summary 描画レイヤー配列を無効化
     * @package
     */

  }, {
    key: "dirtyDrawingLayers",
    value: function dirtyDrawingLayers() {
      this._draw_layers = null;
    }
    /**
     * @summary 描画レイヤー配列を更新
     * @private
     */

  }, {
    key: "_updataDrawingLayers",
    value: function _updataDrawingLayers() {
      var num_layers = this.num_layers;
      var draw_layers = [];

      for (var i = 0; i < num_layers; ++i) {
        var layer = this._layers[i];

        if (layer.image_provider.status() === ImageProvider.Status.READY && layer.visibility === true) {
          draw_layers.push(layer);
        }
      }

      this._draw_layers = draw_layers;
    }
  }, {
    key: "glenv",
    get: function get() {
      return this._glenv;
    }
    /**
     * @summary レイヤー数
     * @type {number}
     * @readonly
     */

  }, {
    key: "num_layers",
    get: function get() {
      return this._layers.length;
    }
  }]);

  return LayerCollection;
}();

/**
 * @summary レンダリングコールバック
 * @classdesc
 * <p>レンダリングループでの各箇所で呼び出されるコールバック関数を実装するための抽象クラスである。</p>
 * <p>サブクラスでは以下のメソッドをオーバーライドすることができる。オーバーライドしないメソッドは何もしない。</p>
 * <ul>
 *   <li>[onStart()]{@link mapray.RenderCallback#onStart}</li>
 *   <li>[onUpdateFrame()]{@link mapray.RenderCallback#onUpdateFrame}</li>
 *   <li>[onStop()]{@link mapray.RenderCallback#onStop}</li>
 * </ul>
 * @memberof mapray
 * @protected
 * @abstract
 * @see mapray.Viewer
 */
var RenderCallback =
/*#__PURE__*/
function () {
  function RenderCallback() {
    _classCallCheck(this, RenderCallback);

    this._viewer = null;
    this._is_started_ = false;
  }
  /**
   * View に取り付ける
   * @package
   */


  _createClass(RenderCallback, [{
    key: "attach",
    value: function attach(viewer) {
      if (this._viewer) {
        throw new Error("RenderCallback instance is already attached");
      }

      this._viewer = viewer;
      this._is_started_ = false;
    }
    /**
     * View から切り離す
     * すでに onStart() を呼び出してい場合、onStop() を呼び出す。
     * @package
     */

  }, {
    key: "detach",
    value: function detach() {
      if (this._is_started_) {
        this.onStop();
        this._is_started_ = false;
      }

      this._viewer = null;
    }
    /**
     * フレーム onUpdateFrame() の呼び出し
     * 取り付けてから最初のフレームのときは onStart() を呼び出す。
     * @package
     */

  }, {
    key: "onUpdateFrameInner",
    value: function onUpdateFrameInner(delta_time) {
      if (!this._is_started_) {
        this.onStart();
        this._is_started_ = true;
      }

      this.onUpdateFrame(delta_time);
    }
    /**
     * @summary 保有者 Viewer
     * @desc
     * <p>この RenderCallback インスタンスが設定されている Viewer インスタンスを示す。</p>
     * <p>ただし RenderCallback インスタンスがどの Viewer インスタンスにも設定されていない状態では null となる。</p>
     * @type {?mapray.Viewer}
     * @readonly
     */

  }, {
    key: "onStart",

    /**
     * @summary レンダリングループ開始の処理
     * @abstract
     */
    value: function onStart() {}
    /**
     * @summary フレームレンダリング前の処理
     * @param {number} delta_time  前フレームからの経過時間 (秒)
     * @abstract
     */

  }, {
    key: "onUpdateFrame",
    value: function onUpdateFrame(delta_time) {}
    /**
     * @summary レンダリングループ終了の処理
     * @abstract
     */

  }, {
    key: "onStop",
    value: function onStop() {}
  }, {
    key: "viewer",
    get: function get() {
      return this._viewer;
    }
  }]);

  return RenderCallback;
}();

/**
 * @summary 無機能 RenderCallback
 * @desc
 * <p>Viewer に RenderCallback が設定されていないときに使用する内部クラスである。</p>
 * @memberof mapray
 * @extends mapray.RenderCallback
 * @private
 */

var NullRenderCallback =
/*#__PURE__*/
function (_RenderCallback) {
  _inherits(NullRenderCallback, _RenderCallback);

  function NullRenderCallback() {
    _classCallCheck(this, NullRenderCallback);

    return _possibleConstructorReturn(this, _getPrototypeOf(NullRenderCallback).call(this));
  }

  return NullRenderCallback;
}(RenderCallback);

var $indexOf$1 = arrayIncludes.indexOf;
var nativeIndexOf = [].indexOf;
var NEGATIVE_ZERO$1 = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
var STRICT_METHOD$3 = arrayMethodIsStrict('indexOf');
var USES_TO_LENGTH$7 = arrayMethodUsesToLength('indexOf', {
  ACCESSORS: true,
  1: 0
}); // `Array.prototype.indexOf` method
// https://tc39.github.io/ecma262/#sec-array.prototype.indexof

_export({
  target: 'Array',
  proto: true,
  forced: NEGATIVE_ZERO$1 || !STRICT_METHOD$3 || !USES_TO_LENGTH$7
}, {
  indexOf: function indexOf(searchElement
  /* , fromIndex = 0 */
  ) {
    return NEGATIVE_ZERO$1 // convert -0 to +0
    ? nativeIndexOf.apply(this, arguments) || 0 : $indexOf$1(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
  }
});

/**
 * @summary モデルシーン
 *
 * @classdesc
 * <p>表示するエンティティを管理するクラスである。</p>
 * <p>インスタンスは {@link mapray.Viewer#scene} から得ることができる。</p>
 *
 * @hideconstructor
 * @memberof mapray
 * @see mapray.SceneLoader
 */

var Scene =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Viewer}  viewer  Viewer インスタンス (未構築)
   * @param {mapray.GLEnv}   glenv   GLEnv インスタンス
   */
  function Scene(viewer, glenv) {
    var _this = this;

    _classCallCheck(this, Scene);

    this._viewer = viewer;
    this._glenv = glenv;
    this._enode_list = []; // ENode のリスト

    this._loaders = []; // 現在読み込み中の SceneLoader (取り消し用)
    // animation.BindingBlock

    this._animation = new EasyBindingBlock();

    this._animation.addDescendantUnbinder(function () {
      _this._unbindDescendantAnimations();
    });
  }
  /**
   * WebGL レンダリングコンテキスト情報
   * @type {mapray.GLEnv}
   * @readonly
   * @package
   */


  _createClass(Scene, [{
    key: "clearEntities",

    /**
     * @summary すべてのエンティティを削除
     */
    value: function clearEntities() {
      this._enode_list = [];
    }
    /**
     * @summary エンティティを末尾に追加
     * @param {mapray.Entity} entity  エンティティ
     */

  }, {
    key: "addEntity",
    value: function addEntity(entity) {
      if (entity.scene !== this) {
        throw new Error("invalid entity");
      }

      this._enode_list.push(new ENode(entity));
    }
    /**
     * @summary エンティティを削除
     * @param {mapray.Entity} entity  エンティティ
     */

  }, {
    key: "removeEntity",
    value: function removeEntity(entity) {
      var array = this._enode_list;

      for (var i = 0; i < array.length; ++i) {
        if (array[i].entity === entity) {
          array.splice(i, 1);
          break;
        }
      }
    }
    /**
     * @summary エンティティを取得
     * @param  {number} index    インデックス
     * @return {mapray.Entity}   エンティティ
     */

  }, {
    key: "getEntity",
    value: function getEntity(index) {
      return this._enode_list[index].entity;
    }
    /**
     * @summary シーンを描画
     * @param {mapray.RenderStage} stage  レンダリングステージ
     * @package
     */

  }, {
    key: "draw",
    value: function draw(stage) {
      this._prepare_entities(); // プリミティブの配列を生成


      var op_prims = []; // 不透明プリミティブ

      var tp_prims = []; // 半透明プリミティブ

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this._enode_list[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var entity = _step.value.entity;

          this._add_primitives(stage, entity, op_prims, tp_prims);
        } // プリミティブ配列を整列してから描画

      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      this._draw_opaque_primitives(stage, op_prims);

      this._draw_translucent_primitives(stage, tp_prims);
    }
    /**
     * @summary 描画前のエンティティの準備
     * @private
     */

  }, {
    key: "_prepare_entities",
    value: function _prepare_entities() {
      var dem_area_updated = this._viewer.globe.dem_area_updated;
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this._enode_list[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var enode = _step2.value;
          var producer = enode.entity.getPrimitiveProducer();

          if (producer === null || !producer.needsElevation()) {
            // producer が存在しないとき、または
            // producer が標高を必要としないときは何もしない
            continue;
          }

          if (producer.checkToCreateRegions() || enode.regions === null) {
            // 領域情報が分からない、または領域情報が変化した可能性があるとき
            enode.regions = producer.createRegions();

            if (enode.regions.length > 0) {
              enode.regions.forEach(function (region) {
                region.compile();
              });
              producer.onChangeElevation(enode.regions);
            }
          } else {
            if (dem_area_updated.isEmpty()) {
              // 更新された DEM 領域は存在しない
              // 標高の変化はないので以下の処理を省く
              continue;
            }

            var regions = []; // 標高に変化があった領域

            enode.regions.forEach(function (region) {
              if (region.intersectsWith(dem_area_updated)) {
                // 領域の標高に変化があった
                regions.push(region);
              }
            });

            if (regions.length > 0) {
              // 標高が変化した可能性がある領域を通知
              producer.onChangeElevation(regions);
            }
          }
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
    }
    /**
     * 視体積に含まれるプリミティブを追加
     * @private
     */

  }, {
    key: "_add_primitives",
    value: function _add_primitives(stage, entity, op_prims, tp_prims) {
      var producer = entity.getPrimitiveProducer();
      if (producer === null) return;
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = producer.getPrimitives(stage)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var primitive = _step3.value;

          if (primitive.isVisible(stage)) {
            var dst_prims = primitive.isTranslucent(stage) ? tp_prims : op_prims;
            dst_prims.push(primitive);
          }
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }
    }
    /**
     * 不透明プリミティブを整列してから描画
     * @private
     */

  }, {
    key: "_draw_opaque_primitives",
    value: function _draw_opaque_primitives(stage, primitives) {
      // 不透明プリミティブの整列: 近接 -> 遠方 (Z 降順)
      primitives.sort(function (a, b) {
        return b.sort_z - a.sort_z;
      });
      var gl = this._glenv.context;
      gl.disable(gl.BLEND);
      gl.depthMask(true);

      for (var i = 0; i < primitives.length; ++i) {
        primitives[i].draw(stage);
      }
    }
    /**
     * 半透明プリミティブを整列してから描画
     * @private
     */

  }, {
    key: "_draw_translucent_primitives",
    value: function _draw_translucent_primitives(stage, primitives) {
      // 半透明プリミティブの整列: 遠方 -> 近接 (Z 昇順)
      primitives.sort(function (a, b) {
        return a.sort_z - b.sort_z;
      });
      var gl = this._glenv.context;
      gl.enable(gl.BLEND);
      gl.depthMask(false);

      for (var i = 0; i < primitives.length; ++i) {
        primitives[i].draw(stage);
      }
    }
    /**
     * すべての SceneLoader の読み込みを取り消す
     * @package
     */

  }, {
    key: "cancelLoaders",
    value: function cancelLoaders() {
      var loaders = this._loaders.concat(); // 複製


      for (var i = 0; i < loaders.length; ++i) {
        loaders[i].cancel();
      }
    }
    /**
     * 読み込み中の SceneLoader を登録
     * @param {mapray.SceneLoader} loader  登録するローダー
     * @package
     */

  }, {
    key: "addLoader",
    value: function addLoader(loader) {
      this._loaders.push(loader);
    }
    /**
     * 読み込み中の SceneLoader を削除
     * @param {mapray.SceneLoader} loader  削除するローダー
     * @package
     */

  }, {
    key: "removeLoader",
    value: function removeLoader(loader) {
      var index = this._loaders.indexOf(loader);

      if (index >= 0) {
        this._loaders.splice(index, 1);
      }
    }
    /**
     * @summary FlakePrimitiveProducer の反復可能オブジェクトを取得
     *
     * @return {iterable.<mapray.Entity.FlakePrimitiveProducer>}
     *
     * @package
     */

  }, {
    key: "getFlakePrimitiveProducers",
    value: function getFlakePrimitiveProducers() {
      var producers = [];
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = this._enode_list[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var entity = _step4.value.entity;
          var prod = entity.getFlakePrimitiveProducer();

          if (prod !== null) {
            producers.push(prod);
          }
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) {
            _iterator4["return"]();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }

      return producers;
    }
    /**
     * EasyBindingBlock.DescendantUnbinder 処理
     *
     * @private
     */

  }, {
    key: "_unbindDescendantAnimations",
    value: function _unbindDescendantAnimations() {
      // すべてのエンティティを解除
      var _iteratorNormalCompletion5 = true;
      var _didIteratorError5 = false;
      var _iteratorError5 = undefined;

      try {
        for (var _iterator5 = this._enode_list[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
          var entity = _step5.value.entity;
          entity.animation.unbindAllRecursively();
        }
      } catch (err) {
        _didIteratorError5 = true;
        _iteratorError5 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion5 && _iterator5["return"] != null) {
            _iterator5["return"]();
          }
        } finally {
          if (_didIteratorError5) {
            throw _iteratorError5;
          }
        }
      }
    }
  }, {
    key: "glenv",
    get: function get() {
      return this._glenv;
    }
    /**
     * this を保有する親オブジェクト
     * @type {mapray.Viewer}
     * @readonly
     */

  }, {
    key: "viewer",
    get: function get() {
      return this._viewer;
    }
    /**
     * @summary アニメーションパラメータ設定
     *
     * @type {mapray.animation.BindingBlock}
     * @readonly
     */

  }, {
    key: "animation",
    get: function get() {
      return this._animation;
    }
    /**
     * エンティティ数
     * @type {number}
     * @readonly
     */

  }, {
    key: "num_entities",
    get: function get() {
      return this._enode_list.length;
    }
  }]);

  return Scene;
}();
/**
 * エンティティ管理用ノード
 *
 * @memberof mapray.Scene
 * @private
 */


var ENode =
/**
 * @param {mapray.Entity} entity  管理対象のエンティティ
 */
function ENode(entity) {
  _classCallCheck(this, ENode);

  /**
   * @summary 管理対象のエンティティ
   * @member mapray.Scene.ENode#entity
   * @type {mapray.Entity}
   * @readonly
   */
  this.entity = entity;
  this.regions = null;
};

var FAILS_ON_PRIMITIVES = fails(function () {
  objectKeys(1);
}); // `Object.keys` method
// https://tc39.github.io/ecma262/#sec-object.keys

_export({
  target: 'Object',
  stat: true,
  forced: FAILS_ON_PRIMITIVES
}, {
  keys: function keys(it) {
    return objectKeys(toObject(it));
  }
});

var quot = /"/g; // B.2.3.2.1 CreateHTML(string, tag, attribute, value)
// https://tc39.github.io/ecma262/#sec-createhtml

var createHtml = function (string, tag, attribute, value) {
  var S = String(requireObjectCoercible(string));
  var p1 = '<' + tag;
  if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '&quot;') + '"';
  return p1 + '>' + S + '</' + tag + '>';
};

// of a tag and escaping quotes in arguments

var stringHtmlForced = function (METHOD_NAME) {
  return fails(function () {
    var test = ''[METHOD_NAME]('"');
    return test !== test.toLowerCase() || test.split('"').length > 3;
  });
};

// https://tc39.github.io/ecma262/#sec-string.prototype.link


_export({
  target: 'String',
  proto: true,
  forced: stringHtmlForced('link')
}, {
  link: function link(url) {
    return createHtml(this, 'a', 'href', url);
  }
});

// https://tc39.github.io/ecma262/#sec-array.prototype.lastindexof

_export({
  target: 'Array',
  proto: true,
  forced: arrayLastIndexOf !== [].lastIndexOf
}, {
  lastIndexOf: arrayLastIndexOf
});

var nativeJoin = [].join;
var ES3_STRINGS = indexedObject != Object;
var STRICT_METHOD$4 = arrayMethodIsStrict('join', ','); // `Array.prototype.join` method
// https://tc39.github.io/ecma262/#sec-array.prototype.join

_export({
  target: 'Array',
  proto: true,
  forced: ES3_STRINGS || !STRICT_METHOD$4
}, {
  join: function join(separator) {
    return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
  }
});

var TO_STRING$1 = 'toString';
var RegExpPrototype = RegExp.prototype;
var nativeToString = RegExpPrototype[TO_STRING$1];
var NOT_GENERIC = fails(function () {
  return nativeToString.call({
    source: 'a',
    flags: 'b'
  }) != '/a/b';
}); // FF44- RegExp#toString has a wrong name

var INCORRECT_NAME = nativeToString.name != TO_STRING$1; // `RegExp.prototype.toString` method
// https://tc39.github.io/ecma262/#sec-regexp.prototype.tostring

if (NOT_GENERIC || INCORRECT_NAME) {
  redefine(RegExp.prototype, TO_STRING$1, function toString() {
    var R = anObject(this);
    var p = String(R.source);
    var rf = R.flags;
    var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? regexpFlags.call(R) : rf);
    return '/' + p + '/' + f;
  }, {
    unsafe: true
  });
}

var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
var nativeStartsWith = ''.startsWith;
var min$5 = Math.min;
var CORRECT_IS_REGEXP_LOGIC = correctIsRegexpLogic('startsWith'); // https://github.com/zloirock/core-js/pull/702

var MDN_POLYFILL_BUG =  !CORRECT_IS_REGEXP_LOGIC && !!function () {
  var descriptor = getOwnPropertyDescriptor$4(String.prototype, 'startsWith');
  return descriptor && !descriptor.writable;
}(); // `String.prototype.startsWith` method
// https://tc39.github.io/ecma262/#sec-string.prototype.startswith

_export({
  target: 'String',
  proto: true,
  forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC
}, {
  startsWith: function startsWith(searchString
  /* , position = 0 */
  ) {
    var that = String(requireObjectCoercible(this));
    notARegexp(searchString);
    var index = toLength(min$5(arguments.length > 1 ? arguments[1] : undefined, that.length));
    var search = String(searchString);
    return nativeStartsWith ? nativeStartsWith.call(that, search, index) : that.slice(index, index + search.length) === search;
  }
});

var HTTP =
/*#__PURE__*/
function () {
  function HTTP() {
    _classCallCheck(this, HTTP);
  }

  _createClass(HTTP, null, [{
    key: "get",
    value: function get(url, query) {
      var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      return this.fetch(HTTP.METHOD.GET, url, query, null, option);
    }
  }, {
    key: "post",
    value: function post(url, query, body) {
      var option = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
      return this.fetch(HTTP.METHOD.POST, url, query, body, option);
    }
  }, {
    key: "patch",
    value: function patch(url, query, body) {
      var option = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
      return this.fetch(HTTP.METHOD.PATCH, url, query, body, option);
    }
  }, {
    key: "put",
    value: function put(url, query, body) {
      var option = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
      return this.fetch(HTTP.METHOD.PUT, url, query, body, option);
    }
  }, {
    key: "delete",
    value: function _delete(url, query) {
      var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      return this.fetch(HTTP.METHOD.DELETE, url, query, null, option);
    }
  }, {
    key: "fetch",
    value: function (_fetch) {
      function fetch(_x, _x2, _x3, _x4) {
        return _fetch.apply(this, arguments);
      }

      fetch.toString = function () {
        return _fetch.toString();
      };

      return fetch;
    }(function (method, url, query, body) {
      var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
      var queryText = !query ? "" : "?" + Object.keys(query).map(function (k) {
        return k + "=" + query[k];
      }).join("&");
      option.method = method;
      if (body) option.body = body;
      return fetch(url + queryText, option)["catch"](function (error) {
        throw new FetchError("Failed to fetch", url, null, error);
      }).then(function (response) {
        if (!response.ok) {
          throw new FetchError("Failed to fetch: " + response.statusText, url, response);
        }

        return response;
      });
    })
  }, {
    key: "isJson",
    value: function isJson(mimeType) {
      return mimeType.startsWith("application/json") || mimeType === "model/gltf+json";
    }
  }]);

  return HTTP;
}();

HTTP.METHOD = {
  GET: "GET",
  POST: "POST",
  PATCH: "PATCH",
  PUT: "PUT",
  DELETE: "DELETE"
};
HTTP.CONTENT_TYPE = "Content-Type";
HTTP.RESPONSE_STATUS = {
  NO_CONTENT: 204
};
HTTP.CREDENTIAL_MODE = {
  /**
   * 決してクッキーを送信しない
   */
  OMIT: {
    id: "OMIT",
    credentials: "omit"
  },

  /**
   * URL が呼び出し元のスクリプトと同一オリジンだった場合のみ、クッキーを送信
   */
  SAME_ORIGIN: {
    id: "SAME_ORIGIN",
    credentials: "same-origin"
  },

  /**
   * クロスオリジンの呼び出しであっても、常にクッキーを送信
   */
  INCLUDE: {
    id: "INCLUDE",
    credentials: "include"
  }
};

var FetchError =
/*#__PURE__*/
function (_Error) {
  _inherits(FetchError, _Error);

  function FetchError(message, url, response, cause) {
    var _this;

    _classCallCheck(this, FetchError);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(FetchError).call(this, message + " " + url));

    if (Error.captureStackTrace) {
      Error.captureStackTrace(_assertThisInitialized(_this), FetchError);
    }

    _this.name = "FetchError";
    _this.url = url;
    _this.response = response;
    _this.cause = cause;

    if (cause) {
      _this.stack += "\nCaused-By: " + cause.stack;
    }

    return _this;
  }

  return FetchError;
}(_wrapNativeSuper(Error));

var defineProperty$a = objectDefineProperty.f;
var getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;
var setInternalState$6 = internalState.set;
var MATCH$2 = wellKnownSymbol('match');
var NativeRegExp = global_1.RegExp;
var RegExpPrototype$1 = NativeRegExp.prototype;
var re1 = /a/g;
var re2 = /a/g; // "new" should create a new object, old webkit bug

var CORRECT_NEW = new NativeRegExp(re1) !== re1;
var UNSUPPORTED_Y$2 = regexpStickyHelpers.UNSUPPORTED_Y;
var FORCED$7 = descriptors && isForced_1('RegExp', !CORRECT_NEW || UNSUPPORTED_Y$2 || fails(function () {
  re2[MATCH$2] = false; // RegExp constructor can alter flags and IsRegExp works correct with @@match

  return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
})); // `RegExp` constructor
// https://tc39.github.io/ecma262/#sec-regexp-constructor

if (FORCED$7) {
  var RegExpWrapper = function RegExp(pattern, flags) {
    var thisIsRegExp = this instanceof RegExpWrapper;
    var patternIsRegExp = isRegexp(pattern);
    var flagsAreUndefined = flags === undefined;
    var sticky;

    if (!thisIsRegExp && patternIsRegExp && pattern.constructor === RegExpWrapper && flagsAreUndefined) {
      return pattern;
    }

    if (CORRECT_NEW) {
      if (patternIsRegExp && !flagsAreUndefined) pattern = pattern.source;
    } else if (pattern instanceof RegExpWrapper) {
      if (flagsAreUndefined) flags = regexpFlags.call(pattern);
      pattern = pattern.source;
    }

    if (UNSUPPORTED_Y$2) {
      sticky = !!flags && flags.indexOf('y') > -1;
      if (sticky) flags = flags.replace(/y/g, '');
    }

    var result = inheritIfRequired(CORRECT_NEW ? new NativeRegExp(pattern, flags) : NativeRegExp(pattern, flags), thisIsRegExp ? this : RegExpPrototype$1, RegExpWrapper);
    if (UNSUPPORTED_Y$2 && sticky) setInternalState$6(result, {
      sticky: sticky
    });
    return result;
  };

  var proxy = function (key) {
    key in RegExpWrapper || defineProperty$a(RegExpWrapper, key, {
      configurable: true,
      get: function () {
        return NativeRegExp[key];
      },
      set: function (it) {
        NativeRegExp[key] = it;
      }
    });
  };

  var keys$3 = getOwnPropertyNames$2(NativeRegExp);
  var index = 0;

  while (keys$3.length > index) proxy(keys$3[index++]);

  RegExpPrototype$1.constructor = RegExpWrapper;
  RegExpWrapper.prototype = RegExpPrototype$1;
  redefine(global_1, 'RegExp', RegExpWrapper);
} // https://tc39.github.io/ecma262/#sec-get-regexp-@@species


setSpecies('RegExp');

var ITERATOR$7 = wellKnownSymbol('iterator');
var nativeUrl = !fails(function () {
  var url = new URL('b?a=1&b=2&c=3', 'http://a');
  var searchParams = url.searchParams;
  var result = '';
  url.pathname = 'c%20d';
  searchParams.forEach(function (value, key) {
    searchParams['delete']('b');
    result += key + value;
  });
  return isPure && !url.toJSON || !searchParams.sort || url.href !== 'http://a/c%20d?a=1&c=3' || searchParams.get('c') !== '3' || String(new URLSearchParams('?a=1')) !== 'a=1' || !searchParams[ITERATOR$7] // throws in Edge
  || new URL('https://a@b').username !== 'a' || new URLSearchParams(new URLSearchParams('a=b')).get('a') !== 'b' // not punycoded in Edge
  || new URL('http://тест').host !== 'xn--e1aybc' // not escaped in Chrome 62-
  || new URL('http://a#б').hash !== '#%D0%B1' // fails in Chrome 66-
  || result !== 'a1c3' // throws in Safari
  || new URL('http://x', undefined).host !== 'x';
});

var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1

var base = 36;
var tMin = 1;
var tMax = 26;
var skew = 38;
var damp = 700;
var initialBias = 72;
var initialN = 128; // 0x80

var delimiter = '-'; // '\x2D'

var regexNonASCII = /[^\0-\u007E]/; // non-ASCII chars

var regexSeparators = /[.\u3002\uFF0E\uFF61]/g; // RFC 3490 separators

var OVERFLOW_ERROR = 'Overflow: input needs wider integers to process';
var baseMinusTMin = base - tMin;
var floor$3 = Math.floor;
var stringFromCharCode = String.fromCharCode;
/**
 * Creates an array containing the numeric code points of each Unicode
 * character in the string. While JavaScript uses UCS-2 internally,
 * this function will convert a pair of surrogate halves (each of which
 * UCS-2 exposes as separate characters) into a single code point,
 * matching UTF-16.
 */

var ucs2decode = function (string) {
  var output = [];
  var counter = 0;
  var length = string.length;

  while (counter < length) {
    var value = string.charCodeAt(counter++);

    if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
      // It's a high surrogate, and there is a next character.
      var extra = string.charCodeAt(counter++);

      if ((extra & 0xFC00) == 0xDC00) {
        // Low surrogate.
        output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
      } else {
        // It's an unmatched surrogate; only append this code unit, in case the
        // next code unit is the high surrogate of a surrogate pair.
        output.push(value);
        counter--;
      }
    } else {
      output.push(value);
    }
  }

  return output;
};
/**
 * Converts a digit/integer into a basic code point.
 */


var digitToBasic = function (digit) {
  //  0..25 map to ASCII a..z or A..Z
  // 26..35 map to ASCII 0..9
  return digit + 22 + 75 * (digit < 26);
};
/**
 * Bias adaptation function as per section 3.4 of RFC 3492.
 * https://tools.ietf.org/html/rfc3492#section-3.4
 */


var adapt = function (delta, numPoints, firstTime) {
  var k = 0;
  delta = firstTime ? floor$3(delta / damp) : delta >> 1;
  delta += floor$3(delta / numPoints);

  for (; delta > baseMinusTMin * tMax >> 1; k += base) {
    delta = floor$3(delta / baseMinusTMin);
  }

  return floor$3(k + (baseMinusTMin + 1) * delta / (delta + skew));
};
/**
 * Converts a string of Unicode symbols (e.g. a domain name label) to a
 * Punycode string of ASCII-only symbols.
 */
// eslint-disable-next-line  max-statements


var encode = function (input) {
  var output = []; // Convert the input in UCS-2 to an array of Unicode code points.

  input = ucs2decode(input); // Cache the length.

  var inputLength = input.length; // Initialize the state.

  var n = initialN;
  var delta = 0;
  var bias = initialBias;
  var i, currentValue; // Handle the basic code points.

  for (i = 0; i < input.length; i++) {
    currentValue = input[i];

    if (currentValue < 0x80) {
      output.push(stringFromCharCode(currentValue));
    }
  }

  var basicLength = output.length; // number of basic code points.

  var handledCPCount = basicLength; // number of code points that have been handled;
  // Finish the basic string with a delimiter unless it's empty.

  if (basicLength) {
    output.push(delimiter);
  } // Main encoding loop:


  while (handledCPCount < inputLength) {
    // All non-basic code points < n have been handled already. Find the next larger one:
    var m = maxInt;

    for (i = 0; i < input.length; i++) {
      currentValue = input[i];

      if (currentValue >= n && currentValue < m) {
        m = currentValue;
      }
    } // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, but guard against overflow.


    var handledCPCountPlusOne = handledCPCount + 1;

    if (m - n > floor$3((maxInt - delta) / handledCPCountPlusOne)) {
      throw RangeError(OVERFLOW_ERROR);
    }

    delta += (m - n) * handledCPCountPlusOne;
    n = m;

    for (i = 0; i < input.length; i++) {
      currentValue = input[i];

      if (currentValue < n && ++delta > maxInt) {
        throw RangeError(OVERFLOW_ERROR);
      }

      if (currentValue == n) {
        // Represent delta as a generalized variable-length integer.
        var q = delta;

        for (var k = base;;
        /* no condition */
        k += base) {
          var t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
          if (q < t) break;
          var qMinusT = q - t;
          var baseMinusT = base - t;
          output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT)));
          q = floor$3(qMinusT / baseMinusT);
        }

        output.push(stringFromCharCode(digitToBasic(q)));
        bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
        delta = 0;
        ++handledCPCount;
      }
    }

    ++delta;
    ++n;
  }

  return output.join('');
};

var stringPunycodeToAscii = function (input) {
  var encoded = [];
  var labels = input.toLowerCase().replace(regexSeparators, '\u002E').split('.');
  var i, label;

  for (i = 0; i < labels.length; i++) {
    label = labels[i];
    encoded.push(regexNonASCII.test(label) ? 'xn--' + encode(label) : label);
  }

  return encoded.join('.');
};

var getIterator = function (it) {
  var iteratorMethod = getIteratorMethod(it);

  if (typeof iteratorMethod != 'function') {
    throw TypeError(String(it) + ' is not iterable');
  }

  return anObject(iteratorMethod.call(it));
};

var $fetch$1 = getBuiltIn('fetch');
var Headers = getBuiltIn('Headers');
var ITERATOR$8 = wellKnownSymbol('iterator');
var URL_SEARCH_PARAMS = 'URLSearchParams';
var URL_SEARCH_PARAMS_ITERATOR = URL_SEARCH_PARAMS + 'Iterator';
var setInternalState$7 = internalState.set;
var getInternalParamsState = internalState.getterFor(URL_SEARCH_PARAMS);
var getInternalIteratorState = internalState.getterFor(URL_SEARCH_PARAMS_ITERATOR);
var plus = /\+/g;
var sequences = Array(4);

var percentSequence = function (bytes) {
  return sequences[bytes - 1] || (sequences[bytes - 1] = RegExp('((?:%[\\da-f]{2}){' + bytes + '})', 'gi'));
};

var percentDecode = function (sequence) {
  try {
    return decodeURIComponent(sequence);
  } catch (error) {
    return sequence;
  }
};

var deserialize = function (it) {
  var result = it.replace(plus, ' ');
  var bytes = 4;

  try {
    return decodeURIComponent(result);
  } catch (error) {
    while (bytes) {
      result = result.replace(percentSequence(bytes--), percentDecode);
    }

    return result;
  }
};

var find = /[!'()~]|%20/g;
var replace = {
  '!': '%21',
  "'": '%27',
  '(': '%28',
  ')': '%29',
  '~': '%7E',
  '%20': '+'
};

var replacer = function (match) {
  return replace[match];
};

var serialize = function (it) {
  return encodeURIComponent(it).replace(find, replacer);
};

var parseSearchParams = function (result, query) {
  if (query) {
    var attributes = query.split('&');
    var index = 0;
    var attribute, entry;

    while (index < attributes.length) {
      attribute = attributes[index++];

      if (attribute.length) {
        entry = attribute.split('=');
        result.push({
          key: deserialize(entry.shift()),
          value: deserialize(entry.join('='))
        });
      }
    }
  }
};

var updateSearchParams = function (query) {
  this.entries.length = 0;
  parseSearchParams(this.entries, query);
};

var validateArgumentsLength = function (passed, required) {
  if (passed < required) throw TypeError('Not enough arguments');
};

var URLSearchParamsIterator = createIteratorConstructor(function Iterator(params, kind) {
  setInternalState$7(this, {
    type: URL_SEARCH_PARAMS_ITERATOR,
    iterator: getIterator(getInternalParamsState(params).entries),
    kind: kind
  });
}, 'Iterator', function next() {
  var state = getInternalIteratorState(this);
  var kind = state.kind;
  var step = state.iterator.next();
  var entry = step.value;

  if (!step.done) {
    step.value = kind === 'keys' ? entry.key : kind === 'values' ? entry.value : [entry.key, entry.value];
  }

  return step;
}); // `URLSearchParams` constructor
// https://url.spec.whatwg.org/#interface-urlsearchparams

var URLSearchParamsConstructor = function URLSearchParams()
/* init */
{
  anInstance(this, URLSearchParamsConstructor, URL_SEARCH_PARAMS);
  var init = arguments.length > 0 ? arguments[0] : undefined;
  var that = this;
  var entries = [];
  var iteratorMethod, iterator, next, step, entryIterator, entryNext, first, second, key;
  setInternalState$7(that, {
    type: URL_SEARCH_PARAMS,
    entries: entries,
    updateURL: function () {
      /* empty */
    },
    updateSearchParams: updateSearchParams
  });

  if (init !== undefined) {
    if (isObject(init)) {
      iteratorMethod = getIteratorMethod(init);

      if (typeof iteratorMethod === 'function') {
        iterator = iteratorMethod.call(init);
        next = iterator.next;

        while (!(step = next.call(iterator)).done) {
          entryIterator = getIterator(anObject(step.value));
          entryNext = entryIterator.next;
          if ((first = entryNext.call(entryIterator)).done || (second = entryNext.call(entryIterator)).done || !entryNext.call(entryIterator).done) throw TypeError('Expected sequence with length 2');
          entries.push({
            key: first.value + '',
            value: second.value + ''
          });
        }
      } else for (key in init) if (has(init, key)) entries.push({
        key: key,
        value: init[key] + ''
      });
    } else {
      parseSearchParams(entries, typeof init === 'string' ? init.charAt(0) === '?' ? init.slice(1) : init : init + '');
    }
  }
};

var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
redefineAll(URLSearchParamsPrototype, {
  // `URLSearchParams.prototype.appent` method
  // https://url.spec.whatwg.org/#dom-urlsearchparams-append
  append: function append(name, value) {
    validateArgumentsLength(arguments.length, 2);
    var state = getInternalParamsState(this);
    state.entries.push({
      key: name + '',
      value: value + ''
    });
    state.updateURL();
  },
  // `URLSearchParams.prototype.delete` method
  // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
  'delete': function (name) {
    validateArgumentsLength(arguments.length, 1);
    var state = getInternalParamsState(this);
    var entries = state.entries;
    var key = name + '';
    var index = 0;

    while (index < entries.length) {
      if (entries[index].key === key) entries.splice(index, 1);else index++;
    }

    state.updateURL();
  },
  // `URLSearchParams.prototype.get` method
  // https://url.spec.whatwg.org/#dom-urlsearchparams-get
  get: function get(name) {
    validateArgumentsLength(arguments.length, 1);
    var entries = getInternalParamsState(this).entries;
    var key = name + '';
    var index = 0;

    for (; index < entries.length; index++) {
      if (entries[index].key === key) return entries[index].value;
    }

    return null;
  },
  // `URLSearchParams.prototype.getAll` method
  // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
  getAll: function getAll(name) {
    validateArgumentsLength(arguments.length, 1);
    var entries = getInternalParamsState(this).entries;
    var key = name + '';
    var result = [];
    var index = 0;

    for (; index < entries.length; index++) {
      if (entries[index].key === key) result.push(entries[index].value);
    }

    return result;
  },
  // `URLSearchParams.prototype.has` method
  // https://url.spec.whatwg.org/#dom-urlsearchparams-has
  has: function has(name) {
    validateArgumentsLength(arguments.length, 1);
    var entries = getInternalParamsState(this).entries;
    var key = name + '';
    var index = 0;

    while (index < entries.length) {
      if (entries[index++].key === key) return true;
    }

    return false;
  },
  // `URLSearchParams.prototype.set` method
  // https://url.spec.whatwg.org/#dom-urlsearchparams-set
  set: function set(name, value) {
    validateArgumentsLength(arguments.length, 1);
    var state = getInternalParamsState(this);
    var entries = state.entries;
    var found = false;
    var key = name + '';
    var val = value + '';
    var index = 0;
    var entry;

    for (; index < entries.length; index++) {
      entry = entries[index];

      if (entry.key === key) {
        if (found) entries.splice(index--, 1);else {
          found = true;
          entry.value = val;
        }
      }
    }

    if (!found) entries.push({
      key: key,
      value: val
    });
    state.updateURL();
  },
  // `URLSearchParams.prototype.sort` method
  // https://url.spec.whatwg.org/#dom-urlsearchparams-sort
  sort: function sort() {
    var state = getInternalParamsState(this);
    var entries = state.entries; // Array#sort is not stable in some engines

    var slice = entries.slice();
    var entry, entriesIndex, sliceIndex;
    entries.length = 0;

    for (sliceIndex = 0; sliceIndex < slice.length; sliceIndex++) {
      entry = slice[sliceIndex];

      for (entriesIndex = 0; entriesIndex < sliceIndex; entriesIndex++) {
        if (entries[entriesIndex].key > entry.key) {
          entries.splice(entriesIndex, 0, entry);
          break;
        }
      }

      if (entriesIndex === sliceIndex) entries.push(entry);
    }

    state.updateURL();
  },
  // `URLSearchParams.prototype.forEach` method
  forEach: function forEach(callback
  /* , thisArg */
  ) {
    var entries = getInternalParamsState(this).entries;
    var boundFunction = functionBindContext(callback, arguments.length > 1 ? arguments[1] : undefined, 3);
    var index = 0;
    var entry;

    while (index < entries.length) {
      entry = entries[index++];
      boundFunction(entry.value, entry.key, this);
    }
  },
  // `URLSearchParams.prototype.keys` method
  keys: function keys() {
    return new URLSearchParamsIterator(this, 'keys');
  },
  // `URLSearchParams.prototype.values` method
  values: function values() {
    return new URLSearchParamsIterator(this, 'values');
  },
  // `URLSearchParams.prototype.entries` method
  entries: function entries() {
    return new URLSearchParamsIterator(this, 'entries');
  }
}, {
  enumerable: true
}); // `URLSearchParams.prototype[@@iterator]` method

redefine(URLSearchParamsPrototype, ITERATOR$8, URLSearchParamsPrototype.entries); // `URLSearchParams.prototype.toString` method
// https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior

redefine(URLSearchParamsPrototype, 'toString', function toString() {
  var entries = getInternalParamsState(this).entries;
  var result = [];
  var index = 0;
  var entry;

  while (index < entries.length) {
    entry = entries[index++];
    result.push(serialize(entry.key) + '=' + serialize(entry.value));
  }

  return result.join('&');
}, {
  enumerable: true
});
setToStringTag(URLSearchParamsConstructor, URL_SEARCH_PARAMS);
_export({
  global: true,
  forced: !nativeUrl
}, {
  URLSearchParams: URLSearchParamsConstructor
}); // Wrap `fetch` for correct work with polyfilled `URLSearchParams`
// https://github.com/zloirock/core-js/issues/674

if (!nativeUrl && typeof $fetch$1 == 'function' && typeof Headers == 'function') {
  _export({
    global: true,
    enumerable: true,
    forced: true
  }, {
    fetch: function fetch(input
    /* , init */
    ) {
      var args = [input];
      var init, body, headers;

      if (arguments.length > 1) {
        init = arguments[1];

        if (isObject(init)) {
          body = init.body;

          if (classof(body) === URL_SEARCH_PARAMS) {
            headers = init.headers ? new Headers(init.headers) : new Headers();

            if (!headers.has('content-type')) {
              headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
            }

            init = objectCreate(init, {
              body: createPropertyDescriptor(0, String(body)),
              headers: createPropertyDescriptor(0, headers)
            });
          }
        }

        args.push(init);
      }

      return $fetch$1.apply(this, args);
    }
  });
}

var web_urlSearchParams = {
  URLSearchParams: URLSearchParamsConstructor,
  getState: getInternalParamsState
};

var codeAt = stringMultibyte.codeAt;
var NativeURL = global_1.URL;
var URLSearchParams$1 = web_urlSearchParams.URLSearchParams;
var getInternalSearchParamsState = web_urlSearchParams.getState;
var setInternalState$8 = internalState.set;
var getInternalURLState = internalState.getterFor('URL');
var floor$4 = Math.floor;
var pow$1 = Math.pow;
var INVALID_AUTHORITY = 'Invalid authority';
var INVALID_SCHEME = 'Invalid scheme';
var INVALID_HOST = 'Invalid host';
var INVALID_PORT = 'Invalid port';
var ALPHA = /[A-Za-z]/;
var ALPHANUMERIC = /[\d+\-.A-Za-z]/;
var DIGIT = /\d/;
var HEX_START = /^(0x|0X)/;
var OCT = /^[0-7]+$/;
var DEC = /^\d+$/;
var HEX = /^[\dA-Fa-f]+$/; // eslint-disable-next-line no-control-regex

var FORBIDDEN_HOST_CODE_POINT = /[\u0000\u0009\u000A\u000D #%/:?@[\\]]/; // eslint-disable-next-line no-control-regex

var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\u0000\u0009\u000A\u000D #/:?@[\\]]/; // eslint-disable-next-line no-control-regex

var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g; // eslint-disable-next-line no-control-regex

var TAB_AND_NEW_LINE = /[\u0009\u000A\u000D]/g;
var EOF;

var parseHost = function (url, input) {
  var result, codePoints, index;

  if (input.charAt(0) == '[') {
    if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
    result = parseIPv6(input.slice(1, -1));
    if (!result) return INVALID_HOST;
    url.host = result; // opaque host
  } else if (!isSpecial(url)) {
    if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
    result = '';
    codePoints = arrayFrom(input);

    for (index = 0; index < codePoints.length; index++) {
      result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
    }

    url.host = result;
  } else {
    input = stringPunycodeToAscii(input);
    if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
    result = parseIPv4(input);
    if (result === null) return INVALID_HOST;
    url.host = result;
  }
};

var parseIPv4 = function (input) {
  var parts = input.split('.');
  var partsLength, numbers, index, part, radix, number, ipv4;

  if (parts.length && parts[parts.length - 1] == '') {
    parts.pop();
  }

  partsLength = parts.length;
  if (partsLength > 4) return input;
  numbers = [];

  for (index = 0; index < partsLength; index++) {
    part = parts[index];
    if (part == '') return input;
    radix = 10;

    if (part.length > 1 && part.charAt(0) == '0') {
      radix = HEX_START.test(part) ? 16 : 8;
      part = part.slice(radix == 8 ? 1 : 2);
    }

    if (part === '') {
      number = 0;
    } else {
      if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
      number = parseInt(part, radix);
    }

    numbers.push(number);
  }

  for (index = 0; index < partsLength; index++) {
    number = numbers[index];

    if (index == partsLength - 1) {
      if (number >= pow$1(256, 5 - partsLength)) return null;
    } else if (number > 255) return null;
  }

  ipv4 = numbers.pop();

  for (index = 0; index < numbers.length; index++) {
    ipv4 += numbers[index] * pow$1(256, 3 - index);
  }

  return ipv4;
}; // eslint-disable-next-line max-statements


var parseIPv6 = function (input) {
  var address = [0, 0, 0, 0, 0, 0, 0, 0];
  var pieceIndex = 0;
  var compress = null;
  var pointer = 0;
  var value, length, numbersSeen, ipv4Piece, number, swaps, swap;

  var char = function () {
    return input.charAt(pointer);
  };

  if (char() == ':') {
    if (input.charAt(1) != ':') return;
    pointer += 2;
    pieceIndex++;
    compress = pieceIndex;
  }

  while (char()) {
    if (pieceIndex == 8) return;

    if (char() == ':') {
      if (compress !== null) return;
      pointer++;
      pieceIndex++;
      compress = pieceIndex;
      continue;
    }

    value = length = 0;

    while (length < 4 && HEX.test(char())) {
      value = value * 16 + parseInt(char(), 16);
      pointer++;
      length++;
    }

    if (char() == '.') {
      if (length == 0) return;
      pointer -= length;
      if (pieceIndex > 6) return;
      numbersSeen = 0;

      while (char()) {
        ipv4Piece = null;

        if (numbersSeen > 0) {
          if (char() == '.' && numbersSeen < 4) pointer++;else return;
        }

        if (!DIGIT.test(char())) return;

        while (DIGIT.test(char())) {
          number = parseInt(char(), 10);
          if (ipv4Piece === null) ipv4Piece = number;else if (ipv4Piece == 0) return;else ipv4Piece = ipv4Piece * 10 + number;
          if (ipv4Piece > 255) return;
          pointer++;
        }

        address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
        numbersSeen++;
        if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
      }

      if (numbersSeen != 4) return;
      break;
    } else if (char() == ':') {
      pointer++;
      if (!char()) return;
    } else if (char()) return;

    address[pieceIndex++] = value;
  }

  if (compress !== null) {
    swaps = pieceIndex - compress;
    pieceIndex = 7;

    while (pieceIndex != 0 && swaps > 0) {
      swap = address[pieceIndex];
      address[pieceIndex--] = address[compress + swaps - 1];
      address[compress + --swaps] = swap;
    }
  } else if (pieceIndex != 8) return;

  return address;
};

var findLongestZeroSequence = function (ipv6) {
  var maxIndex = null;
  var maxLength = 1;
  var currStart = null;
  var currLength = 0;
  var index = 0;

  for (; index < 8; index++) {
    if (ipv6[index] !== 0) {
      if (currLength > maxLength) {
        maxIndex = currStart;
        maxLength = currLength;
      }

      currStart = null;
      currLength = 0;
    } else {
      if (currStart === null) currStart = index;
      ++currLength;
    }
  }

  if (currLength > maxLength) {
    maxIndex = currStart;
    maxLength = currLength;
  }

  return maxIndex;
};

var serializeHost = function (host) {
  var result, index, compress, ignore0; // ipv4

  if (typeof host == 'number') {
    result = [];

    for (index = 0; index < 4; index++) {
      result.unshift(host % 256);
      host = floor$4(host / 256);
    }

    return result.join('.'); // ipv6
  } else if (typeof host == 'object') {
    result = '';
    compress = findLongestZeroSequence(host);

    for (index = 0; index < 8; index++) {
      if (ignore0 && host[index] === 0) continue;
      if (ignore0) ignore0 = false;

      if (compress === index) {
        result += index ? ':' : '::';
        ignore0 = true;
      } else {
        result += host[index].toString(16);
        if (index < 7) result += ':';
      }
    }

    return '[' + result + ']';
  }

  return host;
};

var C0ControlPercentEncodeSet = {};
var fragmentPercentEncodeSet = objectAssign({}, C0ControlPercentEncodeSet, {
  ' ': 1,
  '"': 1,
  '<': 1,
  '>': 1,
  '`': 1
});
var pathPercentEncodeSet = objectAssign({}, fragmentPercentEncodeSet, {
  '#': 1,
  '?': 1,
  '{': 1,
  '}': 1
});
var userinfoPercentEncodeSet = objectAssign({}, pathPercentEncodeSet, {
  '/': 1,
  ':': 1,
  ';': 1,
  '=': 1,
  '@': 1,
  '[': 1,
  '\\': 1,
  ']': 1,
  '^': 1,
  '|': 1
});

var percentEncode = function (char, set) {
  var code = codeAt(char, 0);
  return code > 0x20 && code < 0x7F && !has(set, char) ? char : encodeURIComponent(char);
};

var specialSchemes = {
  ftp: 21,
  file: null,
  http: 80,
  https: 443,
  ws: 80,
  wss: 443
};

var isSpecial = function (url) {
  return has(specialSchemes, url.scheme);
};

var includesCredentials = function (url) {
  return url.username != '' || url.password != '';
};

var cannotHaveUsernamePasswordPort = function (url) {
  return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
};

var isWindowsDriveLetter = function (string, normalized) {
  var second;
  return string.length == 2 && ALPHA.test(string.charAt(0)) && ((second = string.charAt(1)) == ':' || !normalized && second == '|');
};

var startsWithWindowsDriveLetter = function (string) {
  var third;
  return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (string.length == 2 || (third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#');
};

var shortenURLsPath = function (url) {
  var path = url.path;
  var pathSize = path.length;

  if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
    path.pop();
  }
};

var isSingleDot = function (segment) {
  return segment === '.' || segment.toLowerCase() === '%2e';
};

var isDoubleDot = function (segment) {
  segment = segment.toLowerCase();
  return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
}; // States:


var SCHEME_START = {};
var SCHEME = {};
var NO_SCHEME = {};
var SPECIAL_RELATIVE_OR_AUTHORITY = {};
var PATH_OR_AUTHORITY = {};
var RELATIVE = {};
var RELATIVE_SLASH = {};
var SPECIAL_AUTHORITY_SLASHES = {};
var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
var AUTHORITY = {};
var HOST = {};
var HOSTNAME = {};
var PORT = {};
var FILE = {};
var FILE_SLASH = {};
var FILE_HOST = {};
var PATH_START = {};
var PATH = {};
var CANNOT_BE_A_BASE_URL_PATH = {};
var QUERY = {};
var FRAGMENT = {}; // eslint-disable-next-line max-statements

var parseURL = function (url, input, stateOverride, base) {
  var state = stateOverride || SCHEME_START;
  var pointer = 0;
  var buffer = '';
  var seenAt = false;
  var seenBracket = false;
  var seenPasswordToken = false;
  var codePoints, char, bufferCodePoints, failure;

  if (!stateOverride) {
    url.scheme = '';
    url.username = '';
    url.password = '';
    url.host = null;
    url.port = null;
    url.path = [];
    url.query = null;
    url.fragment = null;
    url.cannotBeABaseURL = false;
    input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
  }

  input = input.replace(TAB_AND_NEW_LINE, '');
  codePoints = arrayFrom(input);

  while (pointer <= codePoints.length) {
    char = codePoints[pointer];

    switch (state) {
      case SCHEME_START:
        if (char && ALPHA.test(char)) {
          buffer += char.toLowerCase();
          state = SCHEME;
        } else if (!stateOverride) {
          state = NO_SCHEME;
          continue;
        } else return INVALID_SCHEME;

        break;

      case SCHEME:
        if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
          buffer += char.toLowerCase();
        } else if (char == ':') {
          if (stateOverride && (isSpecial(url) != has(specialSchemes, buffer) || buffer == 'file' && (includesCredentials(url) || url.port !== null) || url.scheme == 'file' && !url.host)) return;
          url.scheme = buffer;

          if (stateOverride) {
            if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
            return;
          }

          buffer = '';

          if (url.scheme == 'file') {
            state = FILE;
          } else if (isSpecial(url) && base && base.scheme == url.scheme) {
            state = SPECIAL_RELATIVE_OR_AUTHORITY;
          } else if (isSpecial(url)) {
            state = SPECIAL_AUTHORITY_SLASHES;
          } else if (codePoints[pointer + 1] == '/') {
            state = PATH_OR_AUTHORITY;
            pointer++;
          } else {
            url.cannotBeABaseURL = true;
            url.path.push('');
            state = CANNOT_BE_A_BASE_URL_PATH;
          }
        } else if (!stateOverride) {
          buffer = '';
          state = NO_SCHEME;
          pointer = 0;
          continue;
        } else return INVALID_SCHEME;

        break;

      case NO_SCHEME:
        if (!base || base.cannotBeABaseURL && char != '#') return INVALID_SCHEME;

        if (base.cannotBeABaseURL && char == '#') {
          url.scheme = base.scheme;
          url.path = base.path.slice();
          url.query = base.query;
          url.fragment = '';
          url.cannotBeABaseURL = true;
          state = FRAGMENT;
          break;
        }

        state = base.scheme == 'file' ? FILE : RELATIVE;
        continue;

      case SPECIAL_RELATIVE_OR_AUTHORITY:
        if (char == '/' && codePoints[pointer + 1] == '/') {
          state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
          pointer++;
        } else {
          state = RELATIVE;
          continue;
        }

        break;

      case PATH_OR_AUTHORITY:
        if (char == '/') {
          state = AUTHORITY;
          break;
        } else {
          state = PATH;
          continue;
        }

      case RELATIVE:
        url.scheme = base.scheme;

        if (char == EOF) {
          url.username = base.username;
          url.password = base.password;
          url.host = base.host;
          url.port = base.port;
          url.path = base.path.slice();
          url.query = base.query;
        } else if (char == '/' || char == '\\' && isSpecial(url)) {
          state = RELATIVE_SLASH;
        } else if (char == '?') {
          url.username = base.username;
          url.password = base.password;
          url.host = base.host;
          url.port = base.port;
          url.path = base.path.slice();
          url.query = '';
          state = QUERY;
        } else if (char == '#') {
          url.username = base.username;
          url.password = base.password;
          url.host = base.host;
          url.port = base.port;
          url.path = base.path.slice();
          url.query = base.query;
          url.fragment = '';
          state = FRAGMENT;
        } else {
          url.username = base.username;
          url.password = base.password;
          url.host = base.host;
          url.port = base.port;
          url.path = base.path.slice();
          url.path.pop();
          state = PATH;
          continue;
        }

        break;

      case RELATIVE_SLASH:
        if (isSpecial(url) && (char == '/' || char == '\\')) {
          state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
        } else if (char == '/') {
          state = AUTHORITY;
        } else {
          url.username = base.username;
          url.password = base.password;
          url.host = base.host;
          url.port = base.port;
          state = PATH;
          continue;
        }

        break;

      case SPECIAL_AUTHORITY_SLASHES:
        state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
        if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
        pointer++;
        break;

      case SPECIAL_AUTHORITY_IGNORE_SLASHES:
        if (char != '/' && char != '\\') {
          state = AUTHORITY;
          continue;
        }

        break;

      case AUTHORITY:
        if (char == '@') {
          if (seenAt) buffer = '%40' + buffer;
          seenAt = true;
          bufferCodePoints = arrayFrom(buffer);

          for (var i = 0; i < bufferCodePoints.length; i++) {
            var codePoint = bufferCodePoints[i];

            if (codePoint == ':' && !seenPasswordToken) {
              seenPasswordToken = true;
              continue;
            }

            var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
            if (seenPasswordToken) url.password += encodedCodePoints;else url.username += encodedCodePoints;
          }

          buffer = '';
        } else if (char == EOF || char == '/' || char == '?' || char == '#' || char == '\\' && isSpecial(url)) {
          if (seenAt && buffer == '') return INVALID_AUTHORITY;
          pointer -= arrayFrom(buffer).length + 1;
          buffer = '';
          state = HOST;
        } else buffer += char;

        break;

      case HOST:
      case HOSTNAME:
        if (stateOverride && url.scheme == 'file') {
          state = FILE_HOST;
          continue;
        } else if (char == ':' && !seenBracket) {
          if (buffer == '') return INVALID_HOST;
          failure = parseHost(url, buffer);
          if (failure) return failure;
          buffer = '';
          state = PORT;
          if (stateOverride == HOSTNAME) return;
        } else if (char == EOF || char == '/' || char == '?' || char == '#' || char == '\\' && isSpecial(url)) {
          if (isSpecial(url) && buffer == '') return INVALID_HOST;
          if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
          failure = parseHost(url, buffer);
          if (failure) return failure;
          buffer = '';
          state = PATH_START;
          if (stateOverride) return;
          continue;
        } else {
          if (char == '[') seenBracket = true;else if (char == ']') seenBracket = false;
          buffer += char;
        }

        break;

      case PORT:
        if (DIGIT.test(char)) {
          buffer += char;
        } else if (char == EOF || char == '/' || char == '?' || char == '#' || char == '\\' && isSpecial(url) || stateOverride) {
          if (buffer != '') {
            var port = parseInt(buffer, 10);
            if (port > 0xFFFF) return INVALID_PORT;
            url.port = isSpecial(url) && port === specialSchemes[url.scheme] ? null : port;
            buffer = '';
          }

          if (stateOverride) return;
          state = PATH_START;
          continue;
        } else return INVALID_PORT;

        break;

      case FILE:
        url.scheme = 'file';
        if (char == '/' || char == '\\') state = FILE_SLASH;else if (base && base.scheme == 'file') {
          if (char == EOF) {
            url.host = base.host;
            url.path = base.path.slice();
            url.query = base.query;
          } else if (char == '?') {
            url.host = base.host;
            url.path = base.path.slice();
            url.query = '';
            state = QUERY;
          } else if (char == '#') {
            url.host = base.host;
            url.path = base.path.slice();
            url.query = base.query;
            url.fragment = '';
            state = FRAGMENT;
          } else {
            if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
              url.host = base.host;
              url.path = base.path.slice();
              shortenURLsPath(url);
            }

            state = PATH;
            continue;
          }
        } else {
          state = PATH;
          continue;
        }
        break;

      case FILE_SLASH:
        if (char == '/' || char == '\\') {
          state = FILE_HOST;
          break;
        }

        if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
          if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);else url.host = base.host;
        }

        state = PATH;
        continue;

      case FILE_HOST:
        if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
          if (!stateOverride && isWindowsDriveLetter(buffer)) {
            state = PATH;
          } else if (buffer == '') {
            url.host = '';
            if (stateOverride) return;
            state = PATH_START;
          } else {
            failure = parseHost(url, buffer);
            if (failure) return failure;
            if (url.host == 'localhost') url.host = '';
            if (stateOverride) return;
            buffer = '';
            state = PATH_START;
          }

          continue;
        } else buffer += char;

        break;

      case PATH_START:
        if (isSpecial(url)) {
          state = PATH;
          if (char != '/' && char != '\\') continue;
        } else if (!stateOverride && char == '?') {
          url.query = '';
          state = QUERY;
        } else if (!stateOverride && char == '#') {
          url.fragment = '';
          state = FRAGMENT;
        } else if (char != EOF) {
          state = PATH;
          if (char != '/') continue;
        }

        break;

      case PATH:
        if (char == EOF || char == '/' || char == '\\' && isSpecial(url) || !stateOverride && (char == '?' || char == '#')) {
          if (isDoubleDot(buffer)) {
            shortenURLsPath(url);

            if (char != '/' && !(char == '\\' && isSpecial(url))) {
              url.path.push('');
            }
          } else if (isSingleDot(buffer)) {
            if (char != '/' && !(char == '\\' && isSpecial(url))) {
              url.path.push('');
            }
          } else {
            if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
              if (url.host) url.host = '';
              buffer = buffer.charAt(0) + ':'; // normalize windows drive letter
            }

            url.path.push(buffer);
          }

          buffer = '';

          if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
            while (url.path.length > 1 && url.path[0] === '') {
              url.path.shift();
            }
          }

          if (char == '?') {
            url.query = '';
            state = QUERY;
          } else if (char == '#') {
            url.fragment = '';
            state = FRAGMENT;
          }
        } else {
          buffer += percentEncode(char, pathPercentEncodeSet);
        }

        break;

      case CANNOT_BE_A_BASE_URL_PATH:
        if (char == '?') {
          url.query = '';
          state = QUERY;
        } else if (char == '#') {
          url.fragment = '';
          state = FRAGMENT;
        } else if (char != EOF) {
          url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
        }

        break;

      case QUERY:
        if (!stateOverride && char == '#') {
          url.fragment = '';
          state = FRAGMENT;
        } else if (char != EOF) {
          if (char == "'" && isSpecial(url)) url.query += '%27';else if (char == '#') url.query += '%23';else url.query += percentEncode(char, C0ControlPercentEncodeSet);
        }

        break;

      case FRAGMENT:
        if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
        break;
    }

    pointer++;
  }
}; // `URL` constructor
// https://url.spec.whatwg.org/#url-class


var URLConstructor = function URL(url
/* , base */
) {
  var that = anInstance(this, URLConstructor, 'URL');
  var base = arguments.length > 1 ? arguments[1] : undefined;
  var urlString = String(url);
  var state = setInternalState$8(that, {
    type: 'URL'
  });
  var baseState, failure;

  if (base !== undefined) {
    if (base instanceof URLConstructor) baseState = getInternalURLState(base);else {
      failure = parseURL(baseState = {}, String(base));
      if (failure) throw TypeError(failure);
    }
  }

  failure = parseURL(state, urlString, null, baseState);
  if (failure) throw TypeError(failure);
  var searchParams = state.searchParams = new URLSearchParams$1();
  var searchParamsState = getInternalSearchParamsState(searchParams);
  searchParamsState.updateSearchParams(state.query);

  searchParamsState.updateURL = function () {
    state.query = String(searchParams) || null;
  };

  if (!descriptors) {
    that.href = serializeURL.call(that);
    that.origin = getOrigin.call(that);
    that.protocol = getProtocol.call(that);
    that.username = getUsername.call(that);
    that.password = getPassword.call(that);
    that.host = getHost.call(that);
    that.hostname = getHostname.call(that);
    that.port = getPort.call(that);
    that.pathname = getPathname.call(that);
    that.search = getSearch.call(that);
    that.searchParams = getSearchParams.call(that);
    that.hash = getHash.call(that);
  }
};

var URLPrototype = URLConstructor.prototype;

var serializeURL = function () {
  var url = getInternalURLState(this);
  var scheme = url.scheme;
  var username = url.username;
  var password = url.password;
  var host = url.host;
  var port = url.port;
  var path = url.path;
  var query = url.query;
  var fragment = url.fragment;
  var output = scheme + ':';

  if (host !== null) {
    output += '//';

    if (includesCredentials(url)) {
      output += username + (password ? ':' + password : '') + '@';
    }

    output += serializeHost(host);
    if (port !== null) output += ':' + port;
  } else if (scheme == 'file') output += '//';

  output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
  if (query !== null) output += '?' + query;
  if (fragment !== null) output += '#' + fragment;
  return output;
};

var getOrigin = function () {
  var url = getInternalURLState(this);
  var scheme = url.scheme;
  var port = url.port;
  if (scheme == 'blob') try {
    return new URL(scheme.path[0]).origin;
  } catch (error) {
    return 'null';
  }
  if (scheme == 'file' || !isSpecial(url)) return 'null';
  return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
};

var getProtocol = function () {
  return getInternalURLState(this).scheme + ':';
};

var getUsername = function () {
  return getInternalURLState(this).username;
};

var getPassword = function () {
  return getInternalURLState(this).password;
};

var getHost = function () {
  var url = getInternalURLState(this);
  var host = url.host;
  var port = url.port;
  return host === null ? '' : port === null ? serializeHost(host) : serializeHost(host) + ':' + port;
};

var getHostname = function () {
  var host = getInternalURLState(this).host;
  return host === null ? '' : serializeHost(host);
};

var getPort = function () {
  var port = getInternalURLState(this).port;
  return port === null ? '' : String(port);
};

var getPathname = function () {
  var url = getInternalURLState(this);
  var path = url.path;
  return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
};

var getSearch = function () {
  var query = getInternalURLState(this).query;
  return query ? '?' + query : '';
};

var getSearchParams = function () {
  return getInternalURLState(this).searchParams;
};

var getHash = function () {
  var fragment = getInternalURLState(this).fragment;
  return fragment ? '#' + fragment : '';
};

var accessorDescriptor = function (getter, setter) {
  return {
    get: getter,
    set: setter,
    configurable: true,
    enumerable: true
  };
};

if (descriptors) {
  objectDefineProperties(URLPrototype, {
    // `URL.prototype.href` accessors pair
    // https://url.spec.whatwg.org/#dom-url-href
    href: accessorDescriptor(serializeURL, function (href) {
      var url = getInternalURLState(this);
      var urlString = String(href);
      var failure = parseURL(url, urlString);
      if (failure) throw TypeError(failure);
      getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
    }),
    // `URL.prototype.origin` getter
    // https://url.spec.whatwg.org/#dom-url-origin
    origin: accessorDescriptor(getOrigin),
    // `URL.prototype.protocol` accessors pair
    // https://url.spec.whatwg.org/#dom-url-protocol
    protocol: accessorDescriptor(getProtocol, function (protocol) {
      var url = getInternalURLState(this);
      parseURL(url, String(protocol) + ':', SCHEME_START);
    }),
    // `URL.prototype.username` accessors pair
    // https://url.spec.whatwg.org/#dom-url-username
    username: accessorDescriptor(getUsername, function (username) {
      var url = getInternalURLState(this);
      var codePoints = arrayFrom(String(username));
      if (cannotHaveUsernamePasswordPort(url)) return;
      url.username = '';

      for (var i = 0; i < codePoints.length; i++) {
        url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
      }
    }),
    // `URL.prototype.password` accessors pair
    // https://url.spec.whatwg.org/#dom-url-password
    password: accessorDescriptor(getPassword, function (password) {
      var url = getInternalURLState(this);
      var codePoints = arrayFrom(String(password));
      if (cannotHaveUsernamePasswordPort(url)) return;
      url.password = '';

      for (var i = 0; i < codePoints.length; i++) {
        url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
      }
    }),
    // `URL.prototype.host` accessors pair
    // https://url.spec.whatwg.org/#dom-url-host
    host: accessorDescriptor(getHost, function (host) {
      var url = getInternalURLState(this);
      if (url.cannotBeABaseURL) return;
      parseURL(url, String(host), HOST);
    }),
    // `URL.prototype.hostname` accessors pair
    // https://url.spec.whatwg.org/#dom-url-hostname
    hostname: accessorDescriptor(getHostname, function (hostname) {
      var url = getInternalURLState(this);
      if (url.cannotBeABaseURL) return;
      parseURL(url, String(hostname), HOSTNAME);
    }),
    // `URL.prototype.port` accessors pair
    // https://url.spec.whatwg.org/#dom-url-port
    port: accessorDescriptor(getPort, function (port) {
      var url = getInternalURLState(this);
      if (cannotHaveUsernamePasswordPort(url)) return;
      port = String(port);
      if (port == '') url.port = null;else parseURL(url, port, PORT);
    }),
    // `URL.prototype.pathname` accessors pair
    // https://url.spec.whatwg.org/#dom-url-pathname
    pathname: accessorDescriptor(getPathname, function (pathname) {
      var url = getInternalURLState(this);
      if (url.cannotBeABaseURL) return;
      url.path = [];
      parseURL(url, pathname + '', PATH_START);
    }),
    // `URL.prototype.search` accessors pair
    // https://url.spec.whatwg.org/#dom-url-search
    search: accessorDescriptor(getSearch, function (search) {
      var url = getInternalURLState(this);
      search = String(search);

      if (search == '') {
        url.query = null;
      } else {
        if ('?' == search.charAt(0)) search = search.slice(1);
        url.query = '';
        parseURL(url, search, QUERY);
      }

      getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
    }),
    // `URL.prototype.searchParams` getter
    // https://url.spec.whatwg.org/#dom-url-searchparams
    searchParams: accessorDescriptor(getSearchParams),
    // `URL.prototype.hash` accessors pair
    // https://url.spec.whatwg.org/#dom-url-hash
    hash: accessorDescriptor(getHash, function (hash) {
      var url = getInternalURLState(this);
      hash = String(hash);

      if (hash == '') {
        url.fragment = null;
        return;
      }

      if ('#' == hash.charAt(0)) hash = hash.slice(1);
      url.fragment = '';
      parseURL(url, hash, FRAGMENT);
    })
  });
} // `URL.prototype.toJSON` method
// https://url.spec.whatwg.org/#dom-url-tojson


redefine(URLPrototype, 'toJSON', function toJSON() {
  return serializeURL.call(this);
}, {
  enumerable: true
}); // `URL.prototype.toString` method
// https://url.spec.whatwg.org/#URL-stringification-behavior

redefine(URLPrototype, 'toString', function toString() {
  return serializeURL.call(this);
}, {
  enumerable: true
});

if (NativeURL) {
  var nativeCreateObjectURL = NativeURL.createObjectURL;
  var nativeRevokeObjectURL = NativeURL.revokeObjectURL; // `URL.createObjectURL` method
  // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
  // eslint-disable-next-line no-unused-vars

  if (nativeCreateObjectURL) redefine(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
    return nativeCreateObjectURL.apply(NativeURL, arguments);
  }); // `URL.revokeObjectURL` method
  // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
  // eslint-disable-next-line no-unused-vars

  if (nativeRevokeObjectURL) redefine(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
    return nativeRevokeObjectURL.apply(NativeURL, arguments);
  });
}

setToStringTag(URLConstructor, 'URL');
_export({
  global: true,
  forced: !nativeUrl,
  sham: !descriptors
}, {
  URL: URLConstructor
});

var DATA_URL_PATTERN = new RegExp("^data:");
var ABSOLUTE_URL_PATTERN = new RegExp("^https?://");
/**
 * @summary Utility Class for DOM
 * @memberof mapray
 */

var Dom =
/*#__PURE__*/
function () {
  function Dom() {
    _classCallCheck(this, Dom);
  }

  _createClass(Dom, null, [{
    key: "createCanvasContext",

    /**
     * @param  {number}  width
     * @param  {number}  height
     * @return {CanvasRenderingContext2D}
     */
    value: function createCanvasContext(width, height) {
      var canvas = document.createElement("canvas");
      canvas.width = width;
      canvas.height = height;
      return canvas.getContext("2d");
    }
    /**
     * 画像を読み込みます。
     * @param  {string|Blob}  src
     * @param  {string}  options.crossOrigin
     */

  }, {
    key: "loadImage",
    value: function loadImage(src) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      return new Promise(function (resolve, reject) {
        var image = new Image();

        image.onload = function (event) {
          return resolve(event.target);
        };

        image.onerror = function (event) {
          return reject(new Error("Failed to load image"));
        };

        if (options.crossOrigin !== undefined) {
          image.crossOrigin = options.crossOrigin;
        }

        if (src instanceof Blob) {
          image.src = URL.createObjectURL(src);
        } else {
          image.src = src;
        }
      });
    }
    /**
     * 画像が読み込まれるまで待ちます。
     * @param  {HTMLImageElement}  image
     */

  }, {
    key: "waitForLoad",
    value: function waitForLoad(image) {
      if (!image.src) return Promise.reject(new Error("src was not set"));

      if (image.complete) {
        return Promise.resolve(image);
      }

      return new Promise(function (resolve, reject) {
        var prevOnLoad = image.onload;
        var prevOnError = image.onerror;

        image.onload = function (event) {
          if (prevOnLoad) prevOnLoad(event);
          resolve(event.target);
        };

        image.onerror = function (event) {
          if (prevOnError) prevOnError(event);
          reject(new Error("Failed to load image"));
        };
      });
    }
  }, {
    key: "resolveUrl",
    value: function resolveUrl(baseUrl, url) {
      if (DATA_URL_PATTERN.test(url) || ABSOLUTE_URL_PATTERN.test(url)) {
        // url がデータ url または絶対 url のときは
        // そのまま url をリクエスト
        return url;
      } else {
        // それ以外のときは url を相対 url と解釈し
        // 基底 url と結合した url をリクエスト
        return baseUrl + url;
      }
    }
  }]);

  return Dom;
}();

Dom.SYSTEM_FONT_FAMILY = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'";

/**
 * @summary リソースクラス
 * URLやDB、クラウドサービス等、各種リソースへのアクセスを同一インターフェースで提供することを目的とした抽象クラスです。
 * 基本機能:
 * ・コンストラクタ等によりあらかじめURLやデータの位置を示すプロパティを設定
 * ・load()によりリソースを読み込む
 * ・loadSubResource()によりサブリソースを読み込む
 *
 * サブリソースの読み込みについて、
 * @memberof mapray
 */

var Resource =
/*#__PURE__*/
function () {
  function Resource() {
    _classCallCheck(this, Resource);
  }

  _createClass(Resource, [{
    key: "load",
    value: function load(resourceType) {
      return Promise.reject(new Error("Not Implemented"));
    }
  }, {
    key: "cancel",
    value: function cancel() {}
  }, {
    key: "loadSubResourceSupported",
    value: function loadSubResourceSupported(resourceType) {
      return false;
    }
  }, {
    key: "loadSubResource",
    value: function loadSubResource(url, resourceType) {
      return Promise.reject(new Error("Not Supported"));
    }
  }, {
    key: "resolveResourceSupported",
    value: function resolveResourceSupported(resourceType) {
      return false;
    }
  }, {
    key: "resolveResource",
    value: function resolveResource(url, resourceType) {
      return Promise.reject(new Error("Not Supported"));
    }
  }]);

  return Resource;
}();

var URLResource =
/*#__PURE__*/
function (_Resource) {
  _inherits(URLResource, _Resource);

  function URLResource(url) {
    var _this;

    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    _classCallCheck(this, URLResource);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(URLResource).call(this));
    _this._url = url;
    var index = url.lastIndexOf('/');
    if (index === -1) throw new Error("invalid url");
    _this._base_url = _this._url.substr(0, index + 1);
    _this._type = options.type || "json";
    _this._transform = options.transform || defaultTransformCallback;
    _this._abort_ctrl = new AbortController();
    return _this;
  }

  _createClass(URLResource, [{
    key: "load",
    value: function load(resourceType) {
      var _this2 = this;

      var tr = this._transform(this._url, resourceType);

      return HTTP.get(tr.url, null, this._make_fetch_params(tr)).then(function (response) {
        if (!response.ok) throw new Error(response.statusText);

        if (_this2._type !== "json") {
          throw new Error("unsupported type: " + _this2._type);
        }

        return response.json();
      });
    }
  }, {
    key: "cancel",
    value: function cancel() {
      this._abort_ctrl.abort();
    }
  }, {
    key: "loadSubResourceSupported",
    value: function loadSubResourceSupported() {
      return true;
    }
  }, {
    key: "loadSubResource",
    value: function loadSubResource(subUrl, resourceType) {
      var url = Dom.resolveUrl(this._base_url, subUrl);

      var tr = this._transform(url, resourceType);

      if (resourceType === SceneLoader.ResourceType.BINARY) {
        return HTTP.get(tr.url, null, tr.init).then(function (response) {
          if (!response.ok) throw new Error(response.statusText);
          return response;
        }).then(function (response) {
          return response.arrayBuffer();
        });
      } else if (resourceType === SceneLoader.ResourceType.IMAGE) {
        return Dom.loadImage(tr.url, {
          crossOrigin: tr.crossOrigin
        });
      } else {
        return HTTP.get(tr.url, null, this._make_fetch_params(tr)).then(function (response) {
          if (!response.ok) throw new Error(response.statusText);
          return response.json();
        });
      }
    }
  }, {
    key: "resolveResourceSupported",
    value: function resolveResourceSupported() {
      return true;
    }
  }, {
    key: "resolveResource",
    value: function resolveResource(subUrl) {
      var url = Dom.resolveUrl(this._base_url, subUrl);
      return new URLResource(url, {
        transform: this._transform
      });
    }
    /**
     * fetch() の init 引数に与えるオブジェクトを生成
     * @private
     */

  }, {
    key: "_make_fetch_params",
    value: function _make_fetch_params(tr) {
      var init = {
        signal: this._abort_ctrl.signal,
        credentials: (tr.credentials || HTTP.CREDENTIAL_MODE.OMIT).credentials
      };

      if (tr.headers) {
        init.headers = tr.headers;
      }

      return init;
    }
    /**
     * バイナリを取得するときの fetch 関数のパラメータを取得
     *
     * @param  {string} url  バイナリの URL
     * @return {object}      { url: URL, init: fetch() に与える init オブジェクト }
     */

  }, {
    key: "makeBinaryFetchParams",
    value: function makeBinaryFetchParams(url, resourceType) {
      var tr = this._transform(url, resourceType);

      var init = {
        credentials: (tr.credentials || CredentialMode.OMIT).credentials
      };

      if (tr.headers) {
        init.headers = tr.headers;
      }

      return {
        url: tr.url,
        init: init
      };
    }
    /**
     * イメージを取得するときの Image のプロパティを取得
     *
     * @param  {string} url  バイナリの URL
     * @return {object}      { url: URL, crossOrigin: Image#crossOrigin }
     */

  }, {
    key: "_makeImageLoadParams",
    value: function _makeImageLoadParams(url, resourceType) {
      var tr = this._transform(url, resourceType);

      var params = {
        url: tr.url
      }; // crossorigin 属性の値

      if (tr.credentials === CredentialMode.SAME_ORIGIN) {
        params.crossOrigin = "anonymous";
      } else if (tr.credentials === CredentialMode.INCLUDE) {
        params.crossOrigin = "use-credentials";
      }

      return params;
    }
  }]);

  return URLResource;
}(Resource);

function defaultTransformCallback(url, type) {
  return {
    url: url
  };
}

/**
 * @summary ローダークラス
 * @memberof mapray
 */

var Loader =
/*#__PURE__*/
function () {
  function Loader(scene, resource) {
    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

    _classCallCheck(this, Loader);

    this._scene = scene;

    if (!(resource instanceof Resource)) {
      throw new Error("Unsupported Resource Type: " + resource);
    }

    this._resource = resource;
    this._status = Loader.Status.NOT_LOADED;
    this._onLoad = options.onLoad || defaultOnLoadCallback;
  }
  /**
   * @summary 読み込み先のシーン
   * @type {mapray.Scene}
   * @readonly
   */


  _createClass(Loader, [{
    key: "_setStatus",
    value: function _setStatus(status) {
      this._status = status;
    }
  }, {
    key: "load",
    value: function load() {
      var _this = this;

      if (this.status !== Loader.Status.NOT_LOADED) {
        return Promise.reject(new Error("Illegal Status: " + this.status));
      }

      return Promise.resolve().then(function () {
        _this._setStatus(Loader.Status.LOADING);

        _this.scene.addLoader(_this);

        return _this._load();
      })["catch"](function (error) {
        // JSON データの取得に失敗 (キャンセルによる失敗の可能性あり)
        console.log(error);

        _this._scene.removeLoader(_this);

        _this._onLoad(_this, false);

        if (_this._status !== Loader.Status.CANCELED) {
          _this._setStatus(Loader.Status.ABORTED);
        }

        throw error;
      }).then(function (value) {
        _this._scene.removeLoader(_this);

        if (_this._status === Loader.Status.CANCELED) {
          _this._onLoad(_this, false);

          throw new Error("canceled");
        } else {
          _this._setStatus(Loader.Status.LOADED);

          _this._onLoad(_this, true);

          return value;
        }
      });
    }
  }, {
    key: "_load",
    value: function _load() {
      throw new Error("_load() is not implemented in " + this.constructor.name);
    }
    /**
     * @summary 読み込みの取り消し
     * @desc
     * <p>終了コールバック関数は isSuccess == false で呼び出される。</p>
     */

  }, {
    key: "cancel",
    value: function cancel() {
      if (this._status === Loader.Status.LOADING || this._status === Loader.Status.LOADED) {
        this._setStatus(Loader.Status.CANCELED);

        this._resource.cancel();

        this._cancel(); // this._scene.removeLoader( this );
        // this._onLoad( this, false );

      }
    }
  }, {
    key: "_cancel",
    value: function _cancel() {}
    /**
     * 取り消し状態のとき例外を投げる
     * @private
     */

  }, {
    key: "_check_cancel",
    value: function _check_cancel() {
      if (this.status === Loader.Status.CANCELED) {
        throw new Error("canceled");
      }
    }
  }, {
    key: "scene",
    get: function get() {
      return this._scene;
    }
    /**
     * @summary シーンリソース
     * @type {string}
     * @readonly
     */

  }, {
    key: "resource",
    get: function get() {
      return this._resource;
    }
    /**
     * ローダー読み込みの状態
     * @readonly
     */

  }, {
    key: "status",
    get: function get() {
      return this._status;
    }
  }]);

  return Loader;
}();

Loader.Status = {
  NOT_LOADED: "Not Loaded",
  LOADING: "Loading",
  LOADED: "Loaded",
  CANCELED: "Canceled",
  ERROR: "ERROR"
};

function defaultOnLoadCallback(loader, isSuccess) {}

// このようにする理由は GeoMath.js の最後を参照

/**
 * @summary glTF オブジェクトの共通データ
 *
 * @classdesc
 * <p>多くの glTF オブジェクトに共通に存在する、次のプロパティの値を取得する。<p>
 * <pre>
 *   - name
 *   - extensions
 *   - extras
 * </pre>
 *
 * @memberof mapray.gltf
 * @private
 */
var CommonData =
/*#__PURE__*/
function () {
  /**
   * @param {object}             json  JSON オブジェクト
   * @param {mapray.gltf.Context} ctx  読み込みコンテキスト
   */
  function CommonData(json, ctx) {
    _classCallCheck(this, CommonData);

    // specification/2.0/schema/glTFChildOfRootProperty.schema.json
    this._name = json.name || null;
    this._extensions = ctx.extractUsedExtensions(json.extensions || {});
    this._extras = json.extras || {};
  }
  /**
   * @summary オブジェクト名を取得
   *
   * @return {?string}  オブジェクト名
   */


  _createClass(CommonData, [{
    key: "getName",
    value: function getName() {
      return this._name;
    }
    /**
     * @summary 拡張機能固有オブジェクトを取得
     *
     * @param {string} id  拡張機能の識別子
     *
     * @return {?object}  拡張機能固有オブジェクト
     */

  }, {
    key: "getExtensions",
    value: function getExtensions(id) {
      var extension = this._extensions[id];
      return extension !== undefined ? extension : null;
    }
    /**
     * @summary アプリケーション固有データを取得
     *
     * @param {string} id  アプリケーション固有データの識別子
     *
     * @return {?object}  アプリケーション固有データ
     */

  }, {
    key: "getExtras",
    value: function getExtras(id) {
      var extra = this._extras[id];
      return extra !== undefined ? extra : null;
    }
  }]);

  return CommonData;
}();

/**
 * 読み込んだ glTF データの内容
 *
 * @memberof mapray.gltf
 * @private
 */

var Content =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.gltf.Context}    ctx  読み込みコンテキスト
   * @param {mapray.gltf.Scene[]} scenes  シーンの配列
   * @param {number} default_scene_index  既定シーンの索引 (既定シーンがないときは -1)
   */
  function Content(ctx, scenes, default_scene_index) {
    _classCallCheck(this, Content);

    this._commonData = new CommonData(ctx.gjson, ctx);
    this._scenes = scenes;
    this._default_scene_index = default_scene_index;
  }
  /**
   * glTF オブジェクトの共通データ
   *
   * @type {mapray.gltf.CommonData}
   * @readonly
   */


  _createClass(Content, [{
    key: "commonData",
    get: function get() {
      return this._commonData;
    }
    /**
     * @summary シーンの配列
     *
     * @type {mapray.gltf.Scene[]}
     * @readonly
     */

  }, {
    key: "scenes",
    get: function get() {
      return this._scenes;
    }
    /**
     * @summary 既定シーンの索引
     *
     * <p>既定シーンの索引を返す。ただし既定シーンがないときは -1 を返す。</p>
     *
     * @type {number}
     * @readonly
     */

  }, {
    key: "default_scene_index",
    get: function get() {
      return this._default_scene_index;
    }
  }]);

  return Content;
}();

/**
 * @summary モデルテクスチャ
 * @memberof mapray
 * @package
 */
var Texture =
/*#__PURE__*/
function () {
  /**
   * <p>オプション mag_filter, min_filter, wrap_s, wrap_t は WebGL の定数と同じ値を指定する。
   *    これらのうち、指定がなかったオプションは usage オプションにより決定される。</p>
   *
   * @param {mapray.GLEnv}                          glenv   WebGL 環境
   * @param {?(HTMLImageElement|HTMLCanvasElement)} image   元画像 (usage=COLOR のときは null)
   * @param {object}                             [options]  オプション集合
   * @param {mapray.Texture.Usage} [options.usage=GENERAL]    テクスチャ用途
   * @param {number}               [options.mag_filter]       拡大フィルタ (NEAREST | LINEAR)
   * @param {number}               [options.min_filter]       縮小フィルタ (NEAREST | LINEAR | NEAREST_MIPMAP_NEAREST |
   *                                                          LINEAR_MIPMAP_NEAREST | NEAREST_MIPMAP_LINEAR | LINEAR_MIPMAP_LINEAR)
   * @param {number}               [options.wrap_s]           S Wrap (CLAMP_TO_EDGE | MIRRORED_REPEAT | REPEAT)
   * @param {number}               [options.wrap_t]           T Wrap (CLAMP_TO_EDGE | MIRRORED_REPEAT | REPEAT)
   * @param {boolean}              [options.flip_y=true]      画像読み込み時に上下を反転するか?
   * @param {mapray.Vector4}       [options.color=[1,1,1,1]]  usage=COLOR のときの色指定
   */
  function Texture(glenv, image, options) {
    _classCallCheck(this, Texture);

    var opts = options || {};
    this._glenv = glenv;
    this._handle = this._createTexture(image, opts);
  }
  /**
   * @summary テクスチャのハンドル
   * @type {WebGLTexture}
   * @readonly
   */


  _createClass(Texture, [{
    key: "dispose",

    /**
     * @summary リソースを破棄
     */
    value: function dispose() {
      var gl = this._glenv.context;
      gl.deleteTexture(this._handle);
      this._handle = null;
    }
    /**
     * WebGL テクスチャオブジェクトを生成
     *
     * @param  {?(HTMLImageElement|HTMLCanvasElement)} image  元画像
     * @param  {object}                                opts   オプション集合
     * @return {WebGLTexture}  WebGL テクスチャオブジェクト
     * @private
     */

  }, {
    key: "_createTexture",
    value: function _createTexture(image, opts) {
      var gl = this._glenv.context;
      var target = gl.TEXTURE_2D;
      var texture = gl.createTexture();

      var params = Texture._getParameters(gl, opts);

      gl.bindTexture(target, texture);
      var flip_y = opts.flip_y !== undefined ? opts.flip_y : true;
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flip_y);

      if (opts.usage === Texture.Usage.COLOR) {
        // 均一色テクスチャー
        gl.texImage2D(target, 0, params.format, 1, 1, 0, params.format, params.type, Texture._getColorArray(opts));
      } else {
        // 画像テクスチャー
        gl.texImage2D(target, 0, params.format, params.format, params.type, image);
      }

      if (flip_y) {
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
      }

      if (Texture._generateMipmapQ(gl, params)) {
        gl.generateMipmap(target);
      }

      gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, params.mag_filter);
      gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, params.min_filter);
      gl.texParameteri(target, gl.TEXTURE_WRAP_S, params.wrap_s);
      gl.texParameteri(target, gl.TEXTURE_WRAP_T, params.wrap_t);
      gl.bindTexture(target, null);
      return texture;
    }
    /**
     * テクスチャの生成パラメータを取得
     *
     * @param  {WebGLRenderingContext} gl    WebGL コンテキスト
     * @param  {object}                opts  オプション集合
     * @return {object}  生成パラメータ
     * @private
     */

  }, {
    key: "handle",
    get: function get() {
      return this._handle;
    }
  }], [{
    key: "_getParameters",
    value: function _getParameters(gl, opts) {
      var params = {
        format: gl.RGBA,
        type: gl.UNSIGNED_BYTE,
        mag_filter: gl.LINEAR,
        min_filter: gl.LINEAR_MIPMAP_LINEAR,
        wrap_s: gl.REPEAT,
        wrap_t: gl.REPEAT
      };

      if (opts.usage === Texture.Usage.SIMPLETEXT) {
        params.format = gl.ALPHA;
        params.min_filter = gl.LINEAR;
        params.wrap_s = gl.CLAMP_TO_EDGE;
        params.wrap_t = gl.CLAMP_TO_EDGE;
      } else if (opts.usage === Texture.Usage.TEXT) {
        params.min_filter = gl.LINEAR;
        params.wrap_s = gl.CLAMP_TO_EDGE;
        params.wrap_t = gl.CLAMP_TO_EDGE;
      } else if (opts.usage === Texture.Usage.COLOR) {
        params.mag_filter = gl.NEAREST;
        params.min_filter = gl.NEAREST;
      } else if (opts.usage === Texture.Usage.ICON) {
        params.min_filter = gl.LINEAR;
        params.wrap_s = gl.CLAMP_TO_EDGE;
        params.wrap_t = gl.CLAMP_TO_EDGE;
      } // オプション指定による上書き


      if (opts.mag_filter !== undefined) {
        params.mag_filter = opts.mag_filter;
      }

      if (opts.min_filter !== undefined) {
        params.min_filter = opts.min_filter;
      }

      if (opts.wrap_s !== undefined) {
        params.wrap_s = opts.wrap_s;
      }

      if (opts.wrap_t !== undefined) {
        params.wrap_t = opts.wrap_t;
      }

      return params;
    }
    /**
     * テクスチャの生成パラメータを取得
     *
     * @param  {object} opts  オプション集合
     * @return {Uint8Array}   均一色用の画像データ
     * @private
     */

  }, {
    key: "_getColorArray",
    value: function _getColorArray(opts) {
      var color = opts.color || [1, 1, 1, 1];
      var pixels = color.map(function (value) {
        return Math.round(255 * value);
      });
      return new Uint8Array(pixels);
    }
    /**
     * ミップマップを生成するか?
     *
     * @param  {WebGLRenderingContext} gl      WebGL コンテキスト
     * @param  {object}                params  生成パラメータ
     * @return {boolean}  ミップマップを生成するとき true, それ以外のとき false
     * @private
     */

  }, {
    key: "_generateMipmapQ",
    value: function _generateMipmapQ(gl, params) {
      var filter = params.min_filter;
      return filter == gl.NEAREST_MIPMAP_NEAREST || filter == gl.LINEAR_MIPMAP_NEAREST || filter == gl.NEAREST_MIPMAP_LINEAR || filter == gl.LINEAR_MIPMAP_LINEAR;
    }
  }]);

  return Texture;
}();
/**
 * @summary テクスチャの用途
 * @desc
 * {@link mapray.Texture} の構築子で opts.usage パラメータに指定する値の型である。
 * @enum {object}
 * @memberof mapray.Texture
 * @constant
 */


var Usage = {
  /**
   * 一般用途 (既定値)
   */
  GENERAL: {
    id: "GENERAL"
  },

  /**
   * 均一色
   */
  COLOR: {
    id: "COLOR"
  },

  /**
   * テキスト表示
   */
  TEXT: {
    id: "TEXT"
  },

  /**
   * シンプルテキスト表示
   */
  SIMPLETEXT: {
    id: "SIMPLETEXT"
  },

  /**
   * アイコン
   */
  ICON: {
    id: "ICON"
  }
}; // クラス定数の定義

{
  Texture.Usage = Usage;
}

/**
 * @summary エンティティ・マテリアル
 * @memberof mapray
 * @extends mapray.Material
 * @private
 */

var EntityMaterial =
/*#__PURE__*/
function (_Material) {
  _inherits(EntityMaterial, _Material);

  /**
   * @param {mapray.GLEnv} glenv    WebGL 環境
   * @param {string}     vs_code  頂点シェーダのソースコード
   * @param {string}     fs_code  フラグメントシェーダのソースコード
   */
  function EntityMaterial(glenv, vs_code, fs_code) {
    _classCallCheck(this, EntityMaterial);

    return _possibleConstructorReturn(this, _getPrototypeOf(EntityMaterial).call(this, glenv, vs_code, fs_code));
  }
  /**
   * @summary 背景との混合が必要か?
   * @param  {mapray.RenderStage} stage      レンダリングステージ
   * @param  {mapray.Primitive}   primitive  プリミティブ
   * @return {boolean}                     背景との混合が必要なとき true, それ以外のとき false
   * @default false
   * @abstract
   */


  _createClass(EntityMaterial, [{
    key: "isTranslucent",
    value: function isTranslucent(stage, primitive) {
      return false;
    }
    /**
     * @summary マテリアルパラメータを設定
     * @desc
     * <p>事前に material.bindProgram() すること。</p>
     * @param {mapray.RenderStage} stage      レンダリングステージ
     * @param {mapray.Primitive}   primitive  プリミティブ
     * @abstract
     */

  }, {
    key: "setParameters",
    value: function setParameters(stage, primitive) {}
    /**
     * @summary u_obj_to_clip 変数を設定
     * @param {mapray.RenderStage} stage      レンダリングステージ
     * @param {mapray.Primitive}   primitive  プリミティブ
     * @protected
     */

  }, {
    key: "setObjToClip",
    value: function setObjToClip(stage, primitive) {
      var obj_to_gocs = primitive.transform;
      var obj_to_clip = EntityMaterial._obj_to_clip; // obj_to_clip = gocs_to_clip * obj_to_gocs

      GeoMath.mul_GA(stage._gocs_to_clip, obj_to_gocs, obj_to_clip);
      this.setMatrix("u_obj_to_clip", obj_to_clip);
    }
    /**
     * @summary u_obj_to_view 変数を設定
     * @param {mapray.RenderStage} stage      レンダリングステージ
     * @param {mapray.Primitive}   primitive  プリミティブ
     * @protected
     */

  }, {
    key: "setObjToView",
    value: function setObjToView(stage, primitive) {
      var obj_to_gocs = primitive.transform;
      var obj_to_view = EntityMaterial._obj_to_view; // obj_to_view = gocs_to_view * obj_to_gocs

      GeoMath.mul_AA(stage._gocs_to_view, obj_to_gocs, obj_to_view);
      this.setMatrix("u_obj_to_view", obj_to_view);
    }
  }]);

  return EntityMaterial;
}(Material); // クラス定数の定義


{
  EntityMaterial._obj_to_clip = GeoMath.createMatrixf(); // 計算用一時領域

  EntityMaterial._obj_to_view = GeoMath.createMatrixf(); // 計算用一時領域
}

var model_vs_code = "attribute vec4 a_position;    // 位置 (モデル座標系)\nattribute vec3 a_normal;      // 法線 (モデル座標系)\nattribute vec2 a_texcoord;    // テクスチャ座標\n\nuniform mat4  u_obj_to_clip;  // モデル座標系からクリップ座標系への変換\nuniform mat4  u_obj_to_view;  // モデル座標系から視点座標系への変換\n\nvarying vec3  v_normal;       // 法線 (視点座標系)\nvarying vec2  v_texcoord;     // テクスチャ座標\n\n\nvoid\nmain()\n{\n    gl_Position = u_obj_to_clip * a_position;\n\n#ifndef UNLIT\n    v_normal = normalize( vec3( u_obj_to_view * vec4( a_normal, 0.0 ) ) );  // 法線 (視点座標系)\n#endif\n\n    v_texcoord = a_texcoord;\n}\n";

var model_fs_code = "precision highp float;\n\nvarying vec3  v_normal;    // 法線 (視点座標系)\nvarying vec2  v_texcoord;  // テクスチャ座標\n\nuniform vec3      u_light_dir;   // ライト逆方向 (視点座標系) と強さ\nuniform vec4      u_base_color;  // 基本色係数\nuniform sampler2D u_base_image;  // 基本色画像\n\n\nvoid\nmain()\n{\n#ifndef UNLIT\n    vec3 normal = normalize( v_normal );  // 法線 (視点座標系)\n\n    vec3 dlit = vec3( dot( normal, u_light_dir ) );  // 拡散光の強さ\n#else\n    vec3 dlit = vec3( 1.0 );\n#endif\n\n    gl_FragColor = u_base_color * texture2D( u_base_image, v_texcoord ) * vec4( dlit, 1.0 );\n}\n";

/**
 * @summary 基本マテリアル
 * @memberof mapray
 * @extends mapray.EntityMaterial
 * @private
 */

var ModelMaterial =
/*#__PURE__*/
function (_EntityMaterial) {
  _inherits(ModelMaterial, _EntityMaterial);

  /**
   * @param {mapray.GLEnv} glenv
   * @param {object}  [options]  オプション指定
   * @param {boolean} [options.is_unlit=false]  無照光か?
   */
  function ModelMaterial(glenv) {
    var _this;

    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    _classCallCheck(this, ModelMaterial);

    var preamble = ModelMaterial._getPreamble(options);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(ModelMaterial).call(this, glenv, preamble + model_vs_code, preamble + model_fs_code)); // 均一色テクスチャ

    _this._white_texture = new Texture(glenv, null, {
      usage: Texture.Usage.COLOR,
      color: [1, 1, 1, 1]
    }); // 不変パラメータを事前設定

    _this.bindProgram();

    _this.setInteger("u_base_image", ModelMaterial.TEXUNIT_BASE_IMAGE);

    return _this;
  }
  /**
   * @override
   */


  _createClass(ModelMaterial, [{
    key: "setParameters",
    value: function setParameters(stage, primitive) {
      var props = primitive.properties;
      var pbrMR = props.pbrMetallicRoughness; // u_obj_to_clip, u_obj_to_view

      this.setObjToClip(stage, primitive);
      this.setObjToView(stage, primitive); // 基本色係数

      this.setVector4("u_base_color", pbrMR["baseColorFactor"]); // ライト逆方向 (視点座標系) と強さ

      this.setVector3("u_light_dir", [0, 0, 1]); // テクスチャのバインド

      var base_image_texture = this._selectTexture(pbrMR["baseColorTexture"], this._white_texture);

      this.bindTexture2D(ModelMaterial.TEXUNIT_BASE_IMAGE, base_image_texture.handle);
    }
    /**
     * テクスチャを選択
     * @param  {object}         texinfo
     * @param  {mapray.Texture} alt_texure
     * @return {mapray.Texture}
     * @private
     */

  }, {
    key: "_selectTexture",
    value: function _selectTexture(texinfo, alt_texure) {
      if (texinfo !== null) {
        return texinfo.texture;
      } else {
        return alt_texure;
      }
    }
    /**
     * @summary シェーダの前文を取得
     *
     * @param {object}  options  オプション指定
     * @param {boolean} [options.is_unlit=false]  無照光か?
     *
     * @private
     */

  }], [{
    key: "_getPreamble",
    value: function _getPreamble(options) {
      var is_unlit = options.is_unlit !== undefined ? options.is_unlit : false;
      var lines = []; // UNLIT マクロの定義

      if (is_unlit) {
        lines.push("#define UNLIT");
      } // lines を文字列にして返す


      return lines.join("\n") + "\n\n";
    }
  }]);

  return ModelMaterial;
}(EntityMaterial); // クラス定数の定義


{
  ModelMaterial.TEXUNIT_BASE_IMAGE = 0; // 基本色画像のテクスチャユニット
}

/**
 * glTF の sampler に対応
 * @memberof mapray.gltf
 * @private
 */
var Sampler =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {object}              index  サンプラー索引 (非数の場合は既定値サンプラー)
   */
  function Sampler(ctx, index) {
    _classCallCheck(this, Sampler);

    // specification/2.0/schema/sampler.schema.json
    // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#samplers
    var jsampler = typeof index == 'number' ? ctx.gjson.samplers[index] : {};
    this._magFilter = jsampler.magFilter; // フィルタの既定値は実装依存

    this._minFilter = jsampler.minFilter; // ↑↑↑

    this._wrapS = jsampler.wrapS !== undefined ? jsampler.wrapS : Sampler.WRAP_DEFAULT;
    this._wrapT = jsampler.wrapT !== undefined ? jsampler.wrapT : Sampler.WRAP_DEFAULT;
  }
  /**
   * 拡大フィルタ
   * @type {number|undefined}
   * @readonly
   */


  _createClass(Sampler, [{
    key: "magFilter",
    get: function get() {
      return this._magFilter;
    }
    /**
     * 縮小フィルタ
     * @type {number|undefined}
     * @readonly
     */

  }, {
    key: "minFilter",
    get: function get() {
      return this._minFilter;
    }
    /**
     * S-wrap
     * @type {number}
     * @readonly
     */

  }, {
    key: "wrapS",
    get: function get() {
      return this._wrapS;
    }
    /**
     * T-wrap
     * @type {number}
     * @readonly
     */

  }, {
    key: "wrapT",
    get: function get() {
      return this._wrapT;
    }
  }]);

  return Sampler;
}();

Sampler.WRAP_DEFAULT = 10497; // REPEAT

/**
 * glTF の texture に対応
 * @memberof mapray.gltf
 * @private
 */

var Texture$1 =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {object}              index  テクスチャ索引
   */
  function Texture(ctx, index) {
    _classCallCheck(this, Texture);

    // specification/2.0/schema/texture.schema.json
    var jtexture = ctx.gjson.textures[index];
    this._sampler = new Sampler(ctx, jtexture.sampler);
    this._source = ctx.findImage(jtexture.source);
  }
  /**
   * イメージを取得
   * @type {mapray.gltf.Image}
   * @readonly
   */


  _createClass(Texture, [{
    key: "source",
    get: function get() {
      return this._source;
    }
    /**
     * サンプラを取得
     * @type {mapray.gltf.Sampler}
     * @readonly
     */

  }, {
    key: "sampler",
    get: function get() {
      return this._sampler;
    }
  }]);

  return Texture;
}();

/**
 * glTF の textureInfo に対応
 * @memberof mapray.gltf
 * @private
 */

var TextureInfo =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {object}              jtexinfo  テクスチャ情報
   * @param {mapray.gltf.Context} ctx       読み込みコンテキスト
   */
  function TextureInfo(jtexinfo, ctx) {
    _classCallCheck(this, TextureInfo);

    // specification/2.0/schema/textureInfo.schema.json
    this._texture = new Texture$1(ctx, jtexinfo.index);
    this._texCoord = jtexinfo.texCoord !== undefined ? jtexinfo.texCoord : 0;
  }
  /**
   * 参照するテクスチャを取得
   * @type {mapray.gltf.Texture}
   */


  _createClass(TextureInfo, [{
    key: "texture",
    get: function get() {
      return this._texture;
    }
    /**
     * 参照するテクスチャを設定
     * @type {mapray.gltf.Texture}
     */
    ,
    set: function set(value) {
      this._texture = value;
    }
    /**
     * テクスチャ座標のインデックス
     * @type {number}
     * @readonly
     */

  }, {
    key: "texCoord",
    get: function get() {
      return this._texCoord;
    }
  }]);

  return TextureInfo;
}();

/**
 * glTF の normalTextureInfo に対応
 * @memberof mapray.gltf
 * @private
 */

var NormalTextureInfo =
/*#__PURE__*/
function (_TextureInfo) {
  _inherits(NormalTextureInfo, _TextureInfo);

  /**
   * 初期化
   * @param {object}              jtexinfo  テクスチャ情報
   * @param {mapray.gltf.Context} ctx       読み込みコンテキスト
   */
  function NormalTextureInfo(jtexinfo, ctx) {
    var _this;

    _classCallCheck(this, NormalTextureInfo);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(NormalTextureInfo).call(this, jtexinfo, ctx)); // specification/2.0/schema/material.normalTextureInfo.schema.json

    _this._scale = jtexinfo.scale !== undefined ? jtexinfo.scale : 1.0;
    return _this;
  }
  /**
   * 法線スケール
   * @type {number}
   * @readonly
   */


  _createClass(NormalTextureInfo, [{
    key: "texCoord",
    get: function get() {
      return this._scale;
    }
  }]);

  return NormalTextureInfo;
}(TextureInfo);

/**
 * glTF の occlusionTextureInfo に対応
 * @memberof mapray.gltf
 * @private
 */

var OcclusionTextureInfo =
/*#__PURE__*/
function (_TextureInfo) {
  _inherits(OcclusionTextureInfo, _TextureInfo);

  /**
   * 初期化
   * @param {object}              jtexinfo  テクスチャ情報
   * @param {mapray.gltf.Context} ctx       読み込みコンテキスト
   */
  function OcclusionTextureInfo(jtexinfo, ctx) {
    var _this;

    _classCallCheck(this, OcclusionTextureInfo);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(OcclusionTextureInfo).call(this, jtexinfo, ctx)); // specification/2.0/schema/material.occlusionTextureInfo.schema.json

    _this._strength = jtexinfo.strength !== undefined ? jtexinfo.strength : 1.0;
    return _this;
  }
  /**
   * 遮蔽強度
   * @type {number}
   * @readonly
   */


  _createClass(OcclusionTextureInfo, [{
    key: "strength",
    get: function get() {
      return this._strength;
    }
  }]);

  return OcclusionTextureInfo;
}(TextureInfo);

/**
 * @summary エンティティ用のモデルデータを格納
 *
 * @classdesc
 * <p>エンティティが使用するモデルデータを格納するクラスである。</p>
 *
 * @memberof mapray
 * @private
 * @see mapray.ModelEntity
 */

var ModelContainer =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Scene}        scene    エンティティが所属するシーン
   * @param {mapray.gltf.Content} content  入力モデルデータ
   */
  function ModelContainer(scene, content) {
    _classCallCheck(this, ModelContainer);

    this._entries = []; // 辞書: 整数 -> Entry

    this._name_map = {}; // 辞書: 名前 -> Entry

    this._default = null; // 既定モデルの Entry

    this._offset_transform = GeoMath.setIdentity(GeoMath.createMatrix());
    var share = {};
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
      for (var _iterator = content.scenes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
        var gltf_scene = _step.value;
        var entry = new Entry$1(scene, gltf_scene, share);

        this._entries.push(entry);

        if (gltf_scene.name !== null) {
          this._name_map[gltf_scene.name] = entry;
        }
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator["return"] != null) {
          _iterator["return"]();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }

    if (content.default_scene_index >= 0) {
      if (content.default_scene_index < this._entries.length) {
        this._default = this._entries[content.default_scene_index];
      } else {
        throw new Error("default_scene_index is out of range");
      }
    } else {
      if (this._entries.length >= 1) {
        this._default = this._entries[0];
      }
    }
  }
  /**
   * @summary 対応可能な glTF 拡張機能の配列を取得
   *
   * @desc
   * <p>例えば {@link mapray.gltf.Tools.load} の supported_extensions オプションのために使用する。</p>
   * <p>glTF のコンテンツがこれらの拡張機能だけで対応できないとき、読み込みに失敗することがある。</p>
   *
   * @return {string[]}
   */


  _createClass(ModelContainer, [{
    key: "setOffsetTransform",

    /**
     * @summary オフセット用の変換行列を設定
     *
     * @param {mapray.Matrix} matrix  モデルの頂点座標を変換する変換行列
     */
    value: function setOffsetTransform(matrix) {
      GeoMath.copyMatrix(matrix, this._offset_transform);
    }
    /**
     * @summary モデルデータを生成
     *
     * @desc
     * <p>id で指定したモデルのプリミティブを生成する。ただし id を省略したときは既定のモデルが選択される。</p>
     * <p>id で指定したモデルが存在しないとき、または id を省略したがモデルがまったく存在しないとき null を返す。</p>
     *
     * @param  {number|string} [id]   モデル ID
     * @return {?mapray.Primitive[]}  モデルのプリミティブ配列
     */

  }, {
    key: "createPrimitives",
    value: function createPrimitives(id) {
      var entry = this._getEntry(id);

      if (entry === null) return null;
      var primitives = [];
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = entry.primitives[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var prim = _step2.value;
          var cloned_prim = prim.fastClone();
          GeoMath.mul_AA(this._offset_transform, cloned_prim.transform, cloned_prim.transform); // オフセット変換行列を適用

          cloned_prim.properties = Builder.fastCloneProperties(cloned_prim.properties);
          primitives.push(cloned_prim);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      return primitives;
    }
    /**
     * @summary エントリーを取得
     *
     * @param  {number|string} [id]            モデル ID
     * @return {?mapray.ModelContainer.Entry}  モデルエントリー
     * @private
     */

  }, {
    key: "_getEntry",
    value: function _getEntry(id) {
      if (typeof id == 'number') {
        // id を整数で指定
        if (0 <= id && id < this._entries.length) {
          return this._entries[id];
        }
      } else if (typeof id == 'string') {
        // id を名前で指定
        if (this._name_map.hasOwnProperty(id)) {
          return this._name_map[id];
        }
      } else {
        // id 指定なし
        if (this._entries.length > 0) {
          return this._entries[0];
        }
      }

      return null;
    }
  }], [{
    key: "getSupportedExtensions_glTF",
    value: function getSupportedExtensions_glTF() {
      return ["KHR_materials_unlit"];
    }
  }]);

  return ModelContainer;
}();
/**
 * @summary モデルエントリー
 *
 * @memberof mapray.ModelContainer
 * @private
 */


var Entry$1 =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Scene}      mr_scene    Mapray シーン
   * @param {mapray.gltf.Scene} gltf_scene  glTF シーン
   * @param {object}            share       Builder インスタンス間の共有情報
   */
  function Entry(mr_scene, gltf_scene, share) {
    _classCallCheck(this, Entry);

    var builer = new Builder(mr_scene, gltf_scene, share);
    this._primitives = builer.primitives;
  }
  /**
   * @summary mapray.Primitive の配列を取得
   * @desc
   * <p>transform プロパティはプリミティブ座標系からエンティティ座標系への変換になっている。</p>
   * @type {mapray.Primitive[]}
   * @readonly
   */


  _createClass(Entry, [{
    key: "primitives",
    get: function get() {
      return this._primitives;
    }
  }]);

  return Entry;
}();
/**
 * @summary glTF シーンから mapray.Primitive の配列を構築
 *
 * @memberof mapray.ModelContainer
 * @private
 */


var Builder =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.Scene}      mr_scene    Mapray シーン
   * @param {mapray.gltf.Scene} gltf_scene  glTF シーン
   * @param {object}            share       Builder インスタンス間の共有情報
   */
  function Builder(mr_scene, gltf_scene, share) {
    _classCallCheck(this, Builder);

    // share を初期化
    if (!share.buffer_map) {
      share.buffer_map = new Map(); // gltf.Buffer  -> MeshBuffer

      share.texture_map = new Map(); // gltf.Texture -> Texture
    }

    this._mr_scene = mr_scene;
    this._glenv = mr_scene.glenv;
    this._primitives = [];
    this._buffer_map = share.buffer_map;
    this._texture_map = share.texture_map;
    var identity = GeoMath.setIdentity(GeoMath.createMatrix()); // シーンからシーンへの変換 (恒等行列)

    var _iteratorNormalCompletion3 = true;
    var _didIteratorError3 = false;
    var _iteratorError3 = undefined;

    try {
      for (var _iterator3 = gltf_scene.root_nodes[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
        var node = _step3.value;

        this._addNode(node, identity);
      }
    } catch (err) {
      _didIteratorError3 = true;
      _iteratorError3 = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
          _iterator3["return"]();
        }
      } finally {
        if (_didIteratorError3) {
          throw _iteratorError3;
        }
      }
    }
  }
  /**
   * @summary mapray.Primitive の配列を取得
   * @desc
   * <p>transform プロパティはプリミティブ座標系からエンティティ座標系への変換になっている。</p>
   * @type {mapray.Primitive[]}
   * @readonly
   */


  _createClass(Builder, [{
    key: "_addNode",

    /**
     * ノードを追加
     *
     * @param {mapray.gltf.Node} node  追加対象のノード
     * @param {mapray.Matrix}    ptos  親ノード座標系からシーン座標系への変換
     * @private
     */
    value: function _addNode(node, ptos) {
      var ntos = Builder._getNodeToScene(node, ptos);

      if (node.mesh !== null) {
        var _iteratorNormalCompletion4 = true;
        var _didIteratorError4 = false;
        var _iteratorError4 = undefined;

        try {
          for (var _iterator4 = node.mesh.primitives[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
            var primitive = _step4.value;

            // プリミティブを追加
            this._primitives.push(this._createPrimitive(primitive, ntos));
          }
        } catch (err) {
          _didIteratorError4 = true;
          _iteratorError4 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) {
              _iterator4["return"]();
            }
          } finally {
            if (_didIteratorError4) {
              throw _iteratorError4;
            }
          }
        }
      } // 子孫の処理


      var _iteratorNormalCompletion5 = true;
      var _didIteratorError5 = false;
      var _iteratorError5 = undefined;

      try {
        for (var _iterator5 = node.children[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
          var child = _step5.value;

          this._addNode(child, ntos);
        }
      } catch (err) {
        _didIteratorError5 = true;
        _iteratorError5 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion5 && _iterator5["return"] != null) {
            _iterator5["return"]();
          }
        } finally {
          if (_didIteratorError5) {
            throw _iteratorError5;
          }
        }
      }
    }
    /**
     * node 座標系からシーン座標系の変換行列を取得
     *
     * @param  {mapray.gltf.Node} node  追加対象のノード
     * @param  {mapray.Matrix}    ptos  親ノード座標系からシーン座標系への変換行列
     * @return {mapray.Matrix}          node 座標系からシーン座標系の変換行列
     * @private
     */

  }, {
    key: "_createPrimitive",

    /**
     * プリミティブを生成
     *
     * @param  {mapray.gltf.Primitive} iprim  入力プリミティブ
     * @param {mapray.Matrix}          ntos   ノード座標系からシーン座標系への変換
     * @return {mapray.Primitive}             出力プリミティブ
     * @private
     */
    value: function _createPrimitive(iprim, ntos) {
      var mesh = this._createMesh(iprim);

      var material = this._createMaterial(iprim);

      var oprim = new Primitive(this._glenv, mesh, material, GeoMath.createMatrix(ntos));
      oprim.pivot = this._createMeshPivot(iprim);
      oprim.bbox = this._createBoundingBox(iprim);
      oprim.properties = this._createProperties(iprim);
      return oprim;
    }
    /**
     * メッシュを生成
     *
     * @param  {mapray.gltf.Primitive} iprim  入力プリミティブ
     * @return {mapray.Mesh}                  メッシュ
     * @private
     */

  }, {
    key: "_createMesh",
    value: function _createMesh(iprim) {
      var init = new Mesh.Initializer(Builder._convertPrimitiveMode(iprim), Builder._calcNumVertices(iprim));
      var attributes = iprim.attributes;

      for (var name in attributes) {
        this._addAttribToInit(init, name, attributes[name]);
      }

      var indices = iprim.indices;

      if (indices !== null) {
        this._addIndexToInit(init, indices);
      }

      return new Mesh(this._glenv, init);
    }
    /**
     * 描画モードに変換
     *
     * @param  {mapray.gltf.Primitive} iprim  入力プリミティブ
     * @return {mapray.Mesh.DrawMode}         描画モード
     * @private
     */

  }, {
    key: "_addAttribToInit",

    /**
     * 頂点属性をイニシャライザに追加
     *
     * @param {mapray.Mesh.Initializer} init      追加先
     * @param {string}                  name      属性名
     * @param {mapray.gltf.Accessor}    accessor  アクセサ
     * @private
     */
    value: function _addAttribToInit(init, name, accessor) {
      var buffer = this._findMeshBuffer(accessor.bufferView.buffer, MeshBuffer.Target.ATTRIBUTE);

      var num_components = Builder._NumComponents[accessor.type];
      var component_type = Builder._ComponentType[accessor.componentType];
      var options = {
        normalized: accessor.normalized,
        byte_stride: accessor.bufferView.byteStride,
        byte_offset: accessor.bufferView.byteOffset + accessor.byteOffset
      };
      var id = Builder._VertexAttribId[name] || name;
      init.addAttribute(id, buffer, num_components, component_type, options);
    }
    /**
     * インデックスをイニシャライザに追加
     *
     * @param {mapray.Mesh.Initializer} init      追加先
     * @param {mapray.gltf.Accessor}    accessor  アクセサ
     * @private
     */

  }, {
    key: "_addIndexToInit",
    value: function _addIndexToInit(init, accessor) {
      var buffer = this._findMeshBuffer(accessor.bufferView.buffer, MeshBuffer.Target.INDEX);

      var num_indices = accessor.count;
      var type = Builder._ComponentType[accessor.componentType];
      var options = {
        byte_offset: accessor.bufferView.byteOffset + accessor.byteOffset
      };
      init.addIndex(buffer, num_indices, type, options);
    }
    /**
     * MeshBuffer インスタンスを検索
     *
     * @param  {mapray.gltf.Buffer}       buffer  入力バッファ
     * @param  {mapray.MeshBuffer.Target} target  使用目的
     * @return {mapray.MeshBuffer}
     * @private
     */

  }, {
    key: "_findMeshBuffer",
    value: function _findMeshBuffer(buffer, target) {
      var meshBuffer = this._buffer_map.get(buffer);

      if (meshBuffer === undefined) {
        meshBuffer = new MeshBuffer(this._glenv, buffer.binary, {
          target: target
        });

        this._buffer_map.set(buffer, meshBuffer);
      }

      return meshBuffer;
    }
    /**
     * マテリアルを生成
     *
     * @param  {mapray.gltf.Primitive} iprim  入力プリミティブ
     * @return {mapray.EntityMaterial}        マテリアル
     * @private
     */

  }, {
    key: "_createMaterial",
    value: function _createMaterial(iprim) {
      // キャッシュの場所とオプションを決定
      var cache_suffix = "basic";
      var options = {};

      if (iprim.material && iprim.material.commonData.getExtensions("KHR_materials_unlit")) {
        cache_suffix = "unlit";
        options.is_unlit = true;
      } // マテリアルのインスタンスを取得


      var scene = this._mr_scene;
      var cache_id = "_ModelEntity_model_material_" + cache_suffix;

      if (!scene[cache_id]) {
        // scene にマテリアルをキャッシュ
        scene[cache_id] = new ModelMaterial(scene.glenv, options);
      }

      return scene[cache_id];
    }
    /**
     * メッシュ基点を生成
     *
     * @param  {mapray.gltf.Primitive} iprim  入力プリミティブ
     * @return {?mapray.Vector3}              メッシュ基点
     * @private
     */

  }, {
    key: "_createMeshPivot",
    value: function _createMeshPivot(iprim) {
      var pivot = null;

      var bbox = this._createBoundingBox(iprim);

      if (bbox !== null) {
        pivot = GeoMath.createVector3(); // 境界箱の中点

        for (var i = 0; i < 3; ++i) {
          pivot[i] = (bbox[0][i] + bbox[1][i]) / 2;
        }
      }

      return pivot;
    }
    /**
     * 境界箱を生成
     *
     * @param  {mapray.gltf.Primitive} iprim  入力プリミティブ
     * @return {?mapray.Vector3[]}            境界箱
     * @private
     */

  }, {
    key: "_createBoundingBox",
    value: function _createBoundingBox(iprim) {
      var bbox = null;
      var attrib = iprim.attributes['POSITION'];

      if (attrib !== undefined) {
        var min = attrib.min;
        var max = attrib.max;

        if (min !== null && max !== null) {
          bbox = [GeoMath.createVector3(min), GeoMath.createVector3(max)];
        }
      }

      return bbox;
    }
    /**
     * プロパティを生成
     *
     * @param  {mapray.gltf.Primitive} iprim  入力プリミティブ
     * @return {object}                       プロパティ
     * @private
     */

  }, {
    key: "_createProperties",
    value: function _createProperties(iprim) {
      var material = iprim.material;

      if (material === null) {
        // 既定のマテリアル
        return {
          pbrMetallicRoughness: {
            baseColorFactor: GeoMath.createVector4f([1.0, 1.0, 1.0, 1.0]),
            baseColorTexture: null,
            metallicFactor: 1.0,
            roughnessFactor: 1.0,
            metallicRoughnessTexture: null
          },
          doubleSided: false,
          alphaMode: "OPAQUE",
          alphaCutoff: 0.5,
          emissiveFactor: GeoMath.createVector3f([0.0, 0.0, 0.0]),
          emissiveTexture: null,
          normalTexture: null,
          occlusionTexture: null
        };
      } else {
        var pbrMR = material.pbrMetallicRoughness;
        return {
          pbrMetallicRoughness: {
            baseColorFactor: GeoMath.createVector4f(pbrMR.baseColorFactor),
            baseColorTexture: this._createTextureParam(pbrMR.baseColorTexture),
            metallicFactor: pbrMR.metallicFactor,
            roughnessFactor: pbrMR.roughnessFactor,
            metallicRoughnessTexture: this._createTextureParam(pbrMR.metallicRoughnessTexture)
          },
          doubleSided: material.doubleSided,
          alphaMode: material.alphaMode,
          alphaCutoff: material.alphaCutoff,
          emissiveFactor: GeoMath.createVector3f(material.emissiveFactor),
          emissiveTexture: this._createTextureParam(material.emissiveTexture),
          normalTexture: this._createTextureParam(material.normalTexture),
          occlusionTexture: this._createTextureParam(material.occlusionTexture)
        };
      }
    }
    /**
     * テクスチャパラメータを生成
     *
     * @param  {mapray.gltf.TextureInfo} texinfo  TextureInfo インスタンス
     * @return {object}  テクスチャパラメータ
     * @private
     */

  }, {
    key: "_createTextureParam",
    value: function _createTextureParam(texinfo) {
      if (texinfo === null) {
        return null;
      }

      var param = {
        texture: this._findTexture(texinfo.texture),
        texCoord: texinfo.texCoord
      };

      if (texinfo instanceof NormalTextureInfo) {
        param.scale = texinfo.scale;
      } else if (texinfo instanceof OcclusionTextureInfo) {
        param.strength = texinfo.strength;
      }

      return param;
    }
    /**
     * モデル用のプロパティを複製
     *
     * @param  {mapray.PropSet} props
     * @return {mapray.PropSet}
     *
     * @see _createProperties()
     */

  }, {
    key: "_findTexture",

    /**
     * テクスチャパラメータを生成
     *
     * @param  {mapray.gltf.Texture} itexture  glTF テクスチャ
     * @return {mapray.Texture}                テクスチャ
     * @private
     */
    value: function _findTexture(itexture) {
      var otexture = this._texture_map.get(itexture);

      if (otexture === undefined) {
        var sampler = itexture.sampler;
        var gl = this._glenv.context;
        var tex_opts = {
          mag_filter: sampler.magFilter !== undefined ? sampler.magFilter : gl.LINEAR,
          min_filter: sampler.minFilter !== undefined ? sampler.minFilter : gl.LINEAR_MIPMAP_LINEAR,
          wrap_s: sampler.wrapS,
          wrap_t: sampler.wrapT,
          flip_y: false // glTF のテクスチャ座標は左上が原点なので画像を反転しない

        };
        otexture = new Texture(this._glenv, itexture.source.image, tex_opts);

        this._texture_map.set(itexture, otexture);
      }

      return otexture;
    }
  }, {
    key: "primitives",
    get: function get() {
      return this._primitives;
    }
  }], [{
    key: "_getNodeToScene",
    value: function _getNodeToScene(node, ptos) {
      var ntos = ptos; // node 座標系からシーン座標系の変換

      var ntop = node.matrix; // node 座標系から親ノード座標系の変換

      if (ntop !== null) {
        ntos = GeoMath.createMatrix();
        GeoMath.mul_AA(ptos, ntop, ntos);
      }

      return ntos;
    }
  }, {
    key: "_convertPrimitiveMode",
    value: function _convertPrimitiveMode(iprim) {
      return Builder._DrawMode[iprim.mode];
    }
    /**
     * 頂点数を計算
     *
     * @param  {mapray.gltf.Primitive} iprim  入力プリミティブ
     * @return {number}                       頂点数
     * @private
     */

  }, {
    key: "_calcNumVertices",
    value: function _calcNumVertices(iprim) {
      var attributes = iprim.attributes;
      var counts = [];

      for (var name in attributes) {
        var accessor = attributes[name];
        counts.push(accessor.count);
      }

      return Math.min.apply(null, counts);
    }
  }, {
    key: "fastCloneProperties",
    value: function fastCloneProperties(props) {
      var src_pbr = props.pbrMetallicRoughness;
      return {
        pbrMetallicRoughness: {
          baseColorFactor: GeoMath.createVector3f(src_pbr.baseColorFactor),
          baseColorTexture: Builder._fastCloneTextureParam(src_pbr.baseColorTexture),
          metallicFactor: src_pbr.metallicFactor,
          roughnessFactor: src_pbr.roughnessFactor,
          metallicRoughnessTexture: Builder._fastCloneTextureParam(src_pbr.metallicRoughnessTexture)
        },
        doubleSided: props.doubleSided,
        alphaMode: props.alphaMode,
        alphaCutoff: props.alphaCutoff,
        emissiveFactor: GeoMath.createVector3f(props.emissiveFactor),
        emissiveTexture: Builder._fastCloneTextureParam(props.emissiveTexture),
        normalTexture: Builder._fastCloneTextureParam(props.normalTexture),
        occlusionTexture: Builder._fastCloneTextureParam(props.occlusionTexture)
      };
    }
    /**
     * テクスチャパラメータを複製
     *
     * @param  {object} param
     * @return {!object}
     *
     * @private
     * @see _createTextureParam()
     */

  }, {
    key: "_fastCloneTextureParam",
    value: function _fastCloneTextureParam(iparam) {
      if (iparam === null) return null;
      var oparam = {
        texture: iparam.texture,
        texCoord: iparam.texCoord
      };

      if ('scale' in iparam) {
        oparam.scale = iparam.scale;
      } else if ('strength' in iparam) {
        oparam.strength = iparam.strength;
      }

      return oparam;
    }
  }]);

  return Builder;
}(); // gltf.Primitive.mode -> mapray.Mesh.DrawMode


Builder._DrawMode = {
  0: Mesh.DrawMode.POINTS,
  1: Mesh.DrawMode.LINES,
  2: Mesh.DrawMode.LINE_LOOP,
  3: Mesh.DrawMode.LINE_STRIP,
  4: Mesh.DrawMode.TRIANGLES,
  5: Mesh.DrawMode.TRIANGLE_STRIP,
  6: Mesh.DrawMode.TRIANGLE_FAN
}; // gltf.Accessor.type -> 要素数

Builder._NumComponents = {
  'SCALAR': 1,
  'VEC2': 2,
  'VEC3': 3,
  'VEC4': 4
}; // gltf.Accessor.componentType -> mapray.Mesh.ComponentType

Builder._ComponentType = {
  5120: Mesh.ComponentType.BYTE,
  5121: Mesh.ComponentType.UNSIGNED_BYTE,
  5122: Mesh.ComponentType.SHORT,
  5123: Mesh.ComponentType.UNSIGNED_SHORT,
  5125: Mesh.ComponentType.UNSIGNED_INT,
  5126: Mesh.ComponentType.FLOAT
}; // gltf.Primitive.attributes のキー -> 頂点属性 ID

Builder._VertexAttribId = {
  'POSITION': "a_position",
  'NORMAL': "a_normal",
  'TANGENT': "a_tangent",
  'TEXCOORD_0': "a_texcoord",
  'TEXCOORD_1': "a_texcoord1",
  'COLOR_0': "a_color"
};

var markerline_vs_code = "/**\n * 太さ付き線分の頂点シェーダ\n */\n\nattribute vec4 a_position;    // 頂点位置 (モデル座標系)\nattribute vec3 a_direction;   // 線分方向 (モデル座標系) = 終点位置 - 始点位置\nattribute vec2 a_where;       // 線分の4隅指定: 始点左: {-1, 1}, 始点右: {-1, -1}, 終点左: {1, 1}, 終点右: {1, -1}\n\nuniform mat4 u_obj_to_clip;   // モデル座標系からクリップ座標系への変換\nuniform vec3 u_sparam;        // 画面パラメータ: {2/w, 2/h, h/w}\nuniform vec2 u_thickness;     // 線の太さの半分: {u, v}\n\nvec2\noffset( vec4 cpos )\n{\n    vec4 q0 = cpos;\n    q0.y *= u_sparam.z;  // q0 = A * q0\n    vec4 q1 = cpos + u_obj_to_clip * vec4( a_direction, 0 );\n    q1.y *= u_sparam.z;  // q1 = A * q1\n\n    vec2 ds = normalize( q1.xy / q1.w - q0.xy / q0.w );\n    vec2 wt = a_where * u_thickness;\n    return mat2( ds.x, ds.y, -ds.y, ds.x ) * wt;\n}\n\nvoid\nmain()\n{\n    gl_Position = u_obj_to_clip * a_position;\n    gl_Position.xy += offset( gl_Position ) * u_sparam.xy * gl_Position.w;\n}\n";

var markerline_fs_code = "/**\n * 太さ付き線分のフラグメントシェーダ\n */\n\nprecision mediump float;\n\nuniform vec4 u_color;  // 線の基本色と不透明度\n\nvoid\nmain()\n{\n    gl_FragColor = vec4( u_color.xyz * u_color.w, u_color.w );\n}\n";

/**
 * @summary 太さ付き線分専用マテリアル
 * @memberof mapray
 * @extends mapray.EntityMaterial
 * @private
 */

var MarkerLineMaterial =
/*#__PURE__*/
function (_EntityMaterial) {
  _inherits(MarkerLineMaterial, _EntityMaterial);

  /**
   * @param {mapray.GLEnv} glenv
   */
  function MarkerLineMaterial(glenv) {
    _classCallCheck(this, MarkerLineMaterial);

    return _possibleConstructorReturn(this, _getPrototypeOf(MarkerLineMaterial).call(this, glenv, markerline_vs_code, markerline_fs_code));
  }
  /**
   * @override
   */


  _createClass(MarkerLineMaterial, [{
    key: "isTranslucent",
    value: function isTranslucent(stage, primitive) {
      var props = primitive.properties;
      var opacity = props.opacity !== undefined ? props.opacity : MarkerLineMaterial.DEFAULT_OPACITY;
      return opacity < 1.0;
    }
    /**
     * @override
     */

  }, {
    key: "setParameters",
    value: function setParameters(stage, primitive) {
      var props = primitive.properties; // u_obj_to_clip

      this.setObjToClip(stage, primitive); // 画面パラメータ: {2/w, 2/h, h/w}
      // vec3 u_sparam

      var sparam = MarkerLineMaterial._sparam;
      sparam[0] = 2 / stage._width;
      sparam[1] = 2 / stage._height;
      sparam[2] = stage._height / stage._width;
      this.setVector3("u_sparam", sparam); // 線の太さの半分: {u, v}
      // vec2 u_thickness

      var param_width = props.width || MarkerLineMaterial.DEFAULT_WIDTH;
      var thickness = MarkerLineMaterial._thickness;
      thickness[0] = param_width / 2;
      thickness[1] = param_width / 2;
      this.setVector2("u_thickness", thickness); // 線の基本色
      // vec4 u_color

      var param_color = props.color !== undefined ? props.color : MarkerLineMaterial.DEFAULT_COLOR;
      var param_opacity = props.opacity !== undefined ? props.opacity : MarkerLineMaterial.DEFAULT_OPACITY;
      var color = MarkerLineMaterial._color;
      GeoMath.copyVector3(param_color, color);
      color[3] = param_opacity;
      this.setVector4("u_color", color);
    }
  }]);

  return MarkerLineMaterial;
}(EntityMaterial); // クラス定数の定義


{
  MarkerLineMaterial.DEFAULT_WIDTH = 1.0;
  MarkerLineMaterial.DEFAULT_COLOR = GeoMath.createVector3f([1.0, 1.0, 1.0]);
  MarkerLineMaterial.DEFAULT_OPACITY = 1.0; // 計算用一時領域

  MarkerLineMaterial._sparam = GeoMath.createVector3f();
  MarkerLineMaterial._thickness = GeoMath.createVector2f();
  MarkerLineMaterial._color = GeoMath.createVector4f();
}

// このようにする理由は GeoMath.js の最後を参照

/**
 * @summary エンティティ領域
 *
 * @classdesc
 * <p>標高の変化に伴い、エンティティの更新を行うためのクラスである。</p>
 *
 * @memberof mapray
 * @private
 * @see mapray.UpdatedTileArea
 */

var EntityRegion =
/*#__PURE__*/
function () {
  /**
   */
  function EntityRegion() {
    _classCallCheck(this, EntityRegion);

    this._is_compiled = false;
    this._point_array = new Float64Array(0);
    this._num_points = 0;
    this._node_array = new Uint32Array(0);
    this._next_node = 0;
  }
  /**
   * @summary 位置を追加
   *
   * @desc
   * <p>point.altitude は無視される。</p>
   *
   * @param {mapray.GeoPoint} point  位置
   */


  _createClass(EntityRegion, [{
    key: "addPoint",
    value: function addPoint(point) {
      this._checkNotCompiled();

      this._ensurePointArrayCapacity(2);

      var index = 2 * this._num_points;
      this._point_array[index] = point.longitude;
      this._point_array[index + 1] = point.latitude;
      this._num_points += 1;
    }
    /**
     * @summary 複数の位置を追加
     *
     * @param {number[]} points      頂点配列 (経度, 緯度, ...)
     * @param {number}   offset      先頭インデックス
     * @param {number}   stride      ストライド
     * @param {number}   num_points  頂点数
     */

  }, {
    key: "addPoints",
    value: function addPoints(points, offset, stride, num_points) {
      this._checkNotCompiled();

      this._ensurePointArrayCapacity(2 * num_points);

      var src_index = offset;
      var dst_index = 2 * this._num_points;
      var dst_array = this._point_array;

      for (var i = 0; i < num_points; ++i) {
        dst_array[dst_index] = points[src_index];
        dst_array[dst_index + 1] = points[src_index + 1];
        src_index += stride;
        dst_index += 2;
      }

      this._num_points += num_points;
    }
    /**
     * @summary 比較処理用に翻訳
     *
     * @package
     */

  }, {
    key: "compile",
    value: function compile() {
      if (this._is_compiled) {
        // すでに翻訳済み
        return;
      }

      this._buildCollisionQuadTree(); // this._node_array から使っていない最後の領域を削除


      if (this._node_array.length > this._next_node) {
        this._node_array = new Uint32Array(this._node_array.slice(0, this._next_node));
      }

      this._point_array = null; // 翻訳後は使わないので捨てる

      this._is_compiled = true; // 翻訳済みにする
    }
    /**
     * @summary this と area は交差するか?
     *
     * @param {mapray.UpdatedTileArea} area  判定する領域
     *
     * @return {boolean}  交差するとき true, それ以外のとき false
     *
     * @package
     */

  }, {
    key: "intersectsWith",
    value: function intersectsWith(area) {
      if (this._node_array.length == 0) {
        // this は空領域
        return false;
      }

      var area_list = area.getFlatAreaList();

      for (var i = 0; i < area_list.length; ++i) {
        if (this._intersectsWith(area_list[i])) {
          // ある領域が交差した
          return true;
        }
      } // すべての領域が交差しなかった


      return false;
    }
    /**
     * @summary this と area は交差するか? (単一領域)
     *
     * @param  {Uint8Array} area  判定する領域
     *
     * @return {boolean}  交差するとき true, それ以外のとき false
     *
     * @private
     */

  }, {
    key: "_intersectsWith",
    value: function _intersectsWith(area) {
      // assert this._node_array.length > 0
      var node = 0;
      var node_array = this._node_array;

      for (var i = 0; i < area.length; ++i) {
        node = node_array[node + area[i]];

        if (node == FULL_INDEX) {
          // 交差する (area は全域ノードの内側)
          return true;
        } else if (node == EMPTY_INDEX) {
          // 交差しない (area は空ノードの内側)
          return false;
        }
      } // 交差する
      //   area.length == 0 (全球領域) または area の最後が this 階層の途中


      return true;
    }
    /**
     * @summary すでに翻訳されてるときエラー
     *
     * @private
     */

  }, {
    key: "_checkNotCompiled",
    value: function _checkNotCompiled() {
      if (this._is_compiled) {
        throw new Error("EitityRegion is already compiled.");
      }
    }
    /**
     * @summary this._point_array の容量を十分にする
     *
     * @param {number} added_size  追加サイズ
     *
     * @private
     */

  }, {
    key: "_ensurePointArrayCapacity",
    value: function _ensurePointArrayCapacity(added_size) {
      var old_size = 2 * this._num_points;
      var needed_capacity = old_size + added_size;
      var old_capacity = this._point_array.length;

      if (needed_capacity > old_capacity) {
        // 配列を拡張する
        var new_capacity = Math.max(needed_capacity, Math.floor(1.5 * old_capacity));
        var new_point_array = new Float64Array(new_capacity);
        new_point_array.set(this._point_array.slice(0, old_size));
        this._point_array = new_point_array;
      }
    }
    /**
     * @summary 領域判定四分木を構築
     *
     * @private
     */

  }, {
    key: "_buildCollisionQuadTree",
    value: function _buildCollisionQuadTree() {
      var dPI = 2 * Math.PI;
      var point_array = this._point_array;
      var num_floats = 2 * this._num_points;

      for (var i = 0; i < num_floats;) {
        // 経緯度 (Degrees)
        var lon = point_array[i++];
        var lat = point_array[i++]; // 正規化経緯度 (Degrees)

        var _lon = lon + 180 * Math.floor((90 - lat) / 360 + Math.floor((90 + lat) / 360));

        var nlon = _lon - 360 - 360 * Math.floor((_lon - 180) / 360); // 正規化経度 [-180,180)

        var nlat = 90 - Math.abs(90 - lat + 360 * Math.floor((90 + lat) / 360)); // 正規化緯度 [-90,90]
        // 単位球メルカトル座標

        var xm = nlon * GeoMath.DEGREE;
        var ym = GeoMath.invGudermannian(nlat * GeoMath.DEGREE); // 基底タイル座標 (左上(0, 0)、右下(1, 1))

        var xt = xm / dPI + 0.5;
        var yt = 0.5 - ym / dPI; // ノードを追加

        this._addCollisionQuadTreeNode(xt, yt);
      } // 全域ノードを設定


      if (this._next_node > 0) {
        this._setFullNodeRecur(0);

        this._reduceNodeRecur(0);
      }
    }
    /**
     * @summary 領域判定四分木のノードを追加
     *
     * @param {number} xt  基底タイル座標 X
     * @param {number} yt  基底タイル座標 Y
     *
     * @private
     */

  }, {
    key: "_addCollisionQuadTreeNode",
    value: function _addCollisionQuadTreeNode(xt, yt) {
      if (yt < 0 || yt > 1) {
        // 緯度が範囲外 (極に近い)
        return;
      }

      var size = 1 << MAX_LEVEL;
      var ubits = GeoMath.clamp(Math.floor(xt * size), 0, size - 1);
      var vbits = Math.min(Math.floor(yt * size), size - 1); // >= 0

      var node = this._findRootNode();

      for (var mask = size >> 1; mask != 0; mask >>= 1) {
        var u = (ubits & mask) == 0 ? 0 : 1;
        var v = (vbits & mask) == 0 ? 0 : 2;
        node = this._findChildNode(node, u + v);
      }
    }
    /**
     * @summary 最上位ノードを検索
     *
     * @return {number}  最上位ノード
     *
     * @private
     */

  }, {
    key: "_findRootNode",
    value: function _findRootNode() {
      if (this._next_node == 0) {
        // まだ最上位ノードが存在しない
        // 最上位ノードを生成する
        this._ensureNodeArrayCapacity();

        for (var i = 0; i < 4; ++i) {
          this._node_array[i] = EMPTY_INDEX;
        }

        this._next_node = 4;
      }

      return 0;
    }
    /**
     * @summary 子ノードを検索
     *
     * @param  {number} parent  親ノード
     * @param  {number} ichild  子ノード序列 (0-3)
     * @return {number}         子ノード
     *
     * @private
     */

  }, {
    key: "_findChildNode",
    value: function _findChildNode(parent, ichild) {
      var child = this._node_array[parent + ichild];

      if (child == 0) {
        // まだ子ノードが存在しない
        // 子ノードを生成する
        this._ensureNodeArrayCapacity();

        child = this._next_node;

        for (var i = 0; i < 4; ++i) {
          this._node_array[child + i] = EMPTY_INDEX;
        }

        this._next_node += 4; // 親ノードに生成した子ノードを取り付ける

        this._node_array[parent + ichild] = child;
      }

      return child;
    }
    /**
     * @summary 全域ノードを再帰的に設定
     *
     * @desc
     * <p>末端ノードの子ノードを FULL_INDEX に設定する。</p>
     *
     * @param {number} node  ノードの索引
     *
     * @private
     */

  }, {
    key: "_setFullNodeRecur",
    value: function _setFullNodeRecur(node) {
      var node_array = this._node_array;
      var is_leaf = true;

      for (var i = 0; i < 4; ++i) {
        var child = node_array[node + i];

        if (child != EMPTY_INDEX) {
          this._setFullNodeRecur(child);

          is_leaf = false;
        }
      } // 末端なら子ノードを FULL_INDEX


      if (is_leaf) {
        for (i = 0; i < 4; ++i) {
          node_array[node + i] = FULL_INDEX;
        }
      }
    }
    /**
     * @summary 全域ノードを再帰的に設定
     *
     * @param  {number} node  ノードの索引
     * @return {boolean}      全域ノードなら true, その他なら false
     *
     * @private
     */

  }, {
    key: "_reduceNodeRecur",
    value: function _reduceNodeRecur(node) {
      var node_array = this._node_array;
      var num_fulls = 0;

      for (var i = 0; i < 4; ++i) {
        var child = node_array[node + i];

        if (child == FULL_INDEX) {
          ++num_fulls;
        } else if (child != EMPTY_INDEX) {
          if (this._reduceNodeRecur(child)) {
            node_array[node + i] = FULL_INDEX;
            ++num_fulls;
          }
        }
      }

      return num_fulls == 4;
    }
    /**
     * @summary this._node_array の容量を十分にする
     *
     * @private
     */

  }, {
    key: "_ensureNodeArrayCapacity",
    value: function _ensureNodeArrayCapacity() {
      var old_size = this._next_node;
      var needed_capacity = old_size + 4;
      var old_capacity = this._node_array.length;

      if (needed_capacity > old_capacity) {
        // 配列を拡張する
        var new_capacity = Math.max(needed_capacity, Math.floor(1.5 * old_capacity));
        var new_node_array = new Uint32Array(new_capacity);
        new_node_array.set(this._node_array.slice(0, old_size));
        this._node_array = new_node_array;
      }
    }
  }]);

  return EntityRegion;
}();

var MAX_LEVEL = 20; // 整数: 0~30

var EMPTY_INDEX = 0; // 空ノードの索引

var FULL_INDEX = 4294967295; // 全域ノードの索引 = 2^32 - 1

/**
 * @summary 4分木ベースの領域管理
 *
 * <p>Entity.FlakePrimitiveProducer の getAreaStatus() と createMesh()
 *    メソッドを補助するためのクラスである。</p>
 *
 * @memberof mapray
 * @private
 * @see mapray.Entity.FlakePrimitiveProducer
 */

var QAreaManager =
/*#__PURE__*/
function () {
  /**
   */
  function QAreaManager() {
    _classCallCheck(this, QAreaManager);

    this._tree_root = null; // QAreaNode | AreaStatus.EMPTY | AreaStatus.FULL
  }
  /**
   * @summary 領域状態を取得
   *
   * @desc
   * <p>area が示す領域の状態を取得する。</p>
   *
   * @param {mapray.Area} area  確認する領域
   *
   * @return {mapray.Entity.AreaStatus}  領域の状態
   */


  _createClass(QAreaManager, [{
    key: "getAreaStatus",
    value: function getAreaStatus(area) {
      var node = this._get_area_node(area);

      if (node === Entity.AreaStatus.EMPTY || node === Entity.AreaStatus.FULL) {
        // Entity.AreaStatus のとき
        return node;
      } else {
        // QAreaNode のとき
        return Entity.AreaStatus.PARTIAL;
      }
    }
    /**
     * @summary 内容データを取得
     *
     * @param {mapray.Area} area  対象領域
     *
     * @return {object|mapray.Entity.AreaStatus}  area に対応する内容データ | AreaStatus.EMPTY | AreaStatus.FULL
     */

  }, {
    key: "getAreaContent",
    value: function getAreaContent(area) {
      var node = this._get_area_node(area);

      if (node === Entity.AreaStatus.EMPTY || node === Entity.AreaStatus.FULL) {
        // Entity.AreaStatus のとき
        return node;
      } else {
        // QAreaNode のとき
        return node.content;
      }
    }
    /**
     * @summary 初めの内容データを取得
     *
     * @desc
     * <p>最上位領域の内容データを生成するための内容データを取得する。</p>
     * <p>FlakePrimitiveProducer の実装者がこのメソッドを実装する。</p>
     *
     * @return {object}  内容データ
     *
     * @abstract
     */

  }, {
    key: "getInitialContent",
    value: function getInitialContent() {
      return null;
    }
    /**
     * @summary 領域の内容データを生成
     *
     * @desc
     * <p>領域と parent_content から内容データを生成する。</p>
     * <p>パラメータの座標系は正規化メルカトル座標系である。</p>
     * <p>FlakePrimitiveProducer の実装者がこのメソッドを実装する。</p>
     *
     * @param {number} min_x           領域の最小 x 座標
     * @param {number} min_y           領域の最小 y 座標
     * @param {number} msize           領域の寸法
     * @param {object} parent_content  親領域の内容データ
     *
     * @return {object|mapray.Entity.AreaStatus}  内容データ | AreaStatus.EMPTY | AreaStatus.FULL
     *
     * @abstract
     */

  }, {
    key: "createAreaContent",
    value: function createAreaContent(min_x, min_y, msize, parent_content) {
      return Entity.AreaStatus.EMPTY;
    }
    /**
     * @summary 内容データが更新されたこと通知
     *
     * @desc
     * <p>内容データが更新されときに FlakePrimitiveProducer の実装者がこのメソッドを呼び出す。</p>
     */

  }, {
    key: "notifyForUpdateContent",
    value: function notifyForUpdateContent() {
      this._tree_root = null;
    }
    /**
     * @summary 領域のノードを生成
     *
     * @param {number} min_x           領域の最小 x 座標
     * @param {number} max_y           領域の最大 y 座標
     * @param {number} msize           領域の寸法
     * @param {object} parent_content  親領域の内容データ
     *
     * @return {QAreaNode|mapray.Entity.AreaStatus}  ノード | AreaStatus.EMPTY | AreaStatus.FULL
     *
     * @private
     */

  }, {
    key: "_create_area_node",
    value: function _create_area_node(min_x, max_y, msize, parent_content) {
      var content = this.createAreaContent(min_x, max_y - msize, msize, parent_content);

      if (content === Entity.AreaStatus.EMPTY || content === Entity.AreaStatus.FULL) {
        return content;
      } else {
        return new QAreaNode(content);
      }
    }
    /**
     * @summary 領域のノードを取得
     *
     * @desc
     * <p>area に対応するノードを取得する。</p>
     *
     * @param {mapray.Area} area  領域
     *
     * @return {QAreaNode|mapray.Entity.AreaStatus}  area に対応するノード | AreaStatus.EMPTY | AreaStatus.FULL
     *
     * @private
     */

  }, {
    key: "_get_area_node",
    value: function _get_area_node(area) {
      var msize = 2;
      var min_x = -1;
      var max_y = 1;

      if (this._tree_root === null) {
        var content = this.getInitialContent();
        this._tree_root = this._create_area_node(min_x, max_y, msize, content);
      }

      var node = this._tree_root;
      var tsize = Math.round(Math.pow(2, area.z)); // 現行レベルでの縦横タイル数

      var rx = area.x; // 現行レベルでのタイル x 座標

      var ry = area.y; // 現行レベルでのタイル y 座標

      while (tsize != 1 && node !== Entity.AreaStatus.EMPTY && node !== Entity.AreaStatus.FULL) {
        tsize /= 2;
        var u = rx >= tsize ? 1 : 0;
        var v = ry >= tsize ? 1 : 0;
        msize /= 2;
        min_x += u * msize;
        max_y -= v * msize;
        var index = u + 2 * v;
        var child = node.children[index];

        if (child === null) {
          // 子ノードを生成して node に設定
          child = this._create_area_node(min_x, max_y, msize, node.content);
          node.children[index] = child;
        }

        rx -= u * tsize;
        ry -= v * tsize;
        node = child;
      }

      return node;
    }
  }]);

  return QAreaManager;
}();
/**
 * @summary QAreaManager が管理するノード
 *
 * @memberof mapray.QAreaManager
 * @private
 */


var QAreaNode =
/**
 * @param {object} content  内容データ
 */
function QAreaNode(content) {
  _classCallCheck(this, QAreaNode);

  this.children = [null, null, null, null]; // QAreaNode | AreaStatus.EMPTY | AreaStatus.FULL

  this.content = content;
};

/**
 * @summary 太さ付き連続線エンティティ
 * @memberof mapray
 * @extends mapray.Entity
 */

var MarkerLineEntity =
/*#__PURE__*/
function (_Entity) {
  _inherits(MarkerLineEntity, _Entity);

  /**
   * @param {mapray.Scene} scene        所属可能シーン
   * @param {object}       [opts]       オプション集合
   * @param {object}       [opts.json]  生成情報
   * @param {object}       [opts.refs]  参照辞書
   */
  function MarkerLineEntity(scene, opts) {
    var _this;

    _classCallCheck(this, MarkerLineEntity);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(MarkerLineEntity).call(this, scene, opts));
    _this._point_array = new Float64Array(0);
    _this._num_floats = 0;
    _this._width = 1.0;
    _this._color = GeoMath.createVector3([1.0, 1.0, 1.0]);
    _this._opacity = 1.0;

    if (_this.altitude_mode === AltitudeMode.CLAMP) {
      _this._producer = new FlakePrimitiveProducer$1(_assertThisInitialized(_this));
      _this._is_flake_mode = true;
    } else {
      _this._producer = new PrimitiveProducer$1(_assertThisInitialized(_this));
      _this._is_flake_mode = false;
    } // 生成情報から設定


    if (opts && opts.json) {
      _this._setupByJson(opts.json);
    }

    return _this;
  }
  /**
   * @override
   */


  _createClass(MarkerLineEntity, [{
    key: "getPrimitiveProducer",
    value: function getPrimitiveProducer() {
      return !this._is_flake_mode ? this._producer : null;
    }
    /**
     * @override
     */

  }, {
    key: "getFlakePrimitiveProducer",
    value: function getFlakePrimitiveProducer() {
      return this._is_flake_mode ? this._producer : null;
    }
    /**
     * @override
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode(prev_mode) {
      if (this.altitude_mode === AltitudeMode.CLAMP) {
        this._producer = new FlakePrimitiveProducer$1(this);
        this._is_flake_mode = true;
      } else {
        this._producer = new PrimitiveProducer$1(this);
        this._is_flake_mode = false;
      }
    }
    /**
     * @summary 線の太さを設定
     *
     * @param {number} width  線の太さ (画素単位)
     */

  }, {
    key: "setLineWidth",
    value: function setLineWidth(width) {
      this._width = width;

      this._producer.onChangeProperty();
    }
    /**
     * @summary 基本色を設定
     *
     * @param {mapray.Vector3} color  基本色
     */

  }, {
    key: "setColor",
    value: function setColor(color) {
      GeoMath.copyVector3(color, this._color);

      this._producer.onChangeProperty();
    }
    /**
     * @summary 不透明度を設定
     *
     * @param {number} opacity  不透明度
     */

  }, {
    key: "setOpacity",
    value: function setOpacity(opacity) {
      this._opacity = opacity;

      this._producer.onChangeProperty();
    }
    /**
     * @summary 複数の頂点を追加
     *
     * @desc
     * <p>points は [lon_0, lat_0, alt_0, lon_1, lat_1, alt_1, ...] のような形式の配列を与える。</p>
     *
     * @param {number[]} points  頂点の配列
     */

  }, {
    key: "addPoints",
    value: function addPoints(points) {
      var add_size = points.length;

      if (add_size == 0) {
        // 追加頂点が無いので変化なし
        return;
      } // バッファを拡張


      var target_size = this._num_floats + add_size;
      var buffer_size = this._point_array.length;

      if (target_size > buffer_size) {
        var new_buffer = new Float64Array(Math.max(target_size, 2 * buffer_size));
        var old_buffer = this._point_array;
        var copy_size = this._num_floats;

        for (var i = 0; i < copy_size; ++i) {
          new_buffer[i] = old_buffer[i];
        }

        this._point_array = new_buffer;
      } // 頂点追加処理


      var buffer = this._point_array;
      var base = this._num_floats;

      for (var j = 0; j < add_size; ++j) {
        buffer[base + j] = points[j];
      }

      this._num_floats = target_size; // 形状が変化した可能性がある

      this._producer.onChangePoints();
    }
    /**
     * @summary 専用マテリアルを取得
     * @private
     */

  }, {
    key: "_getMarkerLineMaterial",
    value: function _getMarkerLineMaterial() {
      var scene = this.scene;

      if (!scene._MarkerLineEntity_markerline_material) {
        // scene にマテリアルをキャッシュ
        scene._MarkerLineEntity_markerline_material = new MarkerLineMaterial(scene.glenv);
      }

      return scene._MarkerLineEntity_markerline_material;
    }
    /**
     * @private
     */

  }, {
    key: "_setupByJson",
    value: function _setupByJson(json) {
      // json.points
      this.addPoints(json.points); // json.line_width
      //     .color
      //     .opacity

      if (json.line_width !== undefined) this.setLineWidth(json.line_width);
      if (json.color !== undefined) this.setColor(json.color);
      if (json.opacity !== undefined) this.setOpacity(json.opacity);
    }
  }]);

  return MarkerLineEntity;
}(Entity);
/**
 * @summary MarkerLineEntity の PrimitiveProducer
 *
 * @private
 */


var PrimitiveProducer$1 =
/*#__PURE__*/
function (_Entity$PrimitiveProd) {
  _inherits(PrimitiveProducer, _Entity$PrimitiveProd);

  /**
   * @param {mapray.MarkerLineEntity} entity
   */
  function PrimitiveProducer(entity) {
    var _this2;

    _classCallCheck(this, PrimitiveProducer);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(PrimitiveProducer).call(this, entity)); // プリミティブの要素

    _this2._transform = GeoMath.setIdentity(GeoMath.createMatrix());
    _this2._pivot = GeoMath.createVector3();
    _this2._bbox = [GeoMath.createVector3(), GeoMath.createVector3()];
    _this2._properties = {
      width: 1.0,
      color: GeoMath.createVector3f(),
      opacity: 1.0
    }; // プリミティブ

    var primitive = new Primitive(entity.scene.glenv, null, entity._getMarkerLineMaterial(), _this2._transform);
    primitive.pivot = _this2._pivot;
    primitive.bbox = _this2._bbox;
    primitive.properties = _this2._properties;
    _this2._primitive = primitive; // プリミティブ配列

    _this2._primitives = [primitive];
    _this2._geom_dirty = true;
    return _this2;
  }
  /**
   * @override
   */


  _createClass(PrimitiveProducer, [{
    key: "createRegions",
    value: function createRegions() {
      var region = new EntityRegion();
      region.addPoints(this.entity._point_array, 0, 3, this._numPoints());
      return [region];
    }
    /**
     * @override
     */

  }, {
    key: "onChangeElevation",
    value: function onChangeElevation(regions) {
      this._geom_dirty = true;
    }
    /**
     * @override
     */

  }, {
    key: "getPrimitives",
    value: function getPrimitives(stage) {
      if (this._num_floats < 6) {
        // 2頂点未満は表示しない
        return [];
      } else {
        this._updatePrimitive();

        return this._primitives;
      }
    }
    /**
     * @summary 頂点が変更されたことを通知
     */

  }, {
    key: "onChangePoints",
    value: function onChangePoints() {
      this.needToCreateRegions();
      this._geom_dirty = true;
    }
    /**
     * @summary プロパティが変更されたことを通知
     */

  }, {
    key: "onChangeProperty",
    value: function onChangeProperty() {}
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * <pre>
     * 条件: this._num_floats >= 6
     * 入力:
     *   this._geom_dirty
     *   this.entity._point_array
     *   this.entity._num_floats
     *   this.entity._width
     *   this.entity._color
     *   this.entity._opacity
     * 出力:
     *   this._transform
     *   this._pivot
     *   this._bbox
     *   this._properties
     *   this._primitive.mesh
     *   this._geom_dirty
     * </pre>
     *
     * @private
     */

  }, {
    key: "_updatePrimitive",
    value: function _updatePrimitive() {
      this._updateProperties();

      if (!this._geom_dirty) {
        // メッシュは更新する必要がない
        return;
      }

      var entity = this.entity; // GeoPoint 平坦化配列を GOCS 平坦化配列に変換

      var num_points = this._numPoints();

      var gocs_buffer = GeoPoint.toGocsArray(this._getFlatGeoPoints_with_Absolute(), num_points, new Float64Array(entity._num_floats)); // プリミティブの更新
      //   primitive.transform
      //   primitive.pivot
      //   primitive.bbox

      this._updateTransformPivotBBox(gocs_buffer, num_points); // メッシュ生成


      var mesh_data = {
        vtype: [{
          name: "a_position",
          size: 3
        }, {
          name: "a_direction",
          size: 3
        }, {
          name: "a_where",
          size: 2
        }],
        vertices: this._createVertices(gocs_buffer, num_points),
        indices: this._createIndices()
      };
      var mesh = new Mesh(entity.scene.glenv, mesh_data); // メッシュ設定
      //   primitive.mesh

      var primitive = this._primitive;

      if (primitive.mesh) {
        primitive.mesh.dispose();
      }

      primitive.mesh = mesh; // 更新終了

      this._geom_dirty = false;
    }
    /**
     * @summary プロパティを更新
     *
     * @desc
     * <pre>
     * 入力:
     *   this.entity._width
     *   this.entity._color
     *   this.entity._opacity
     * 出力:
     *   this._properties
     * </pre>
     *
     * @private
     */

  }, {
    key: "_updateProperties",
    value: function _updateProperties() {
      var entity = this.entity;
      var props = this._properties;
      props.width = entity._width;
      GeoMath.copyVector3(entity._color, props.color);
      props.opacity = entity._opacity;
    }
    /**
     * @summary GeoPoint 平坦化配列を取得 (絶対高度)
     *
     * @return {number[]}  GeoPoint 平坦化配列
     * @private
     */

  }, {
    key: "_getFlatGeoPoints_with_Absolute",
    value: function _getFlatGeoPoints_with_Absolute() {
      var entity = this.entity;
      var point_array = entity._point_array;
      var num_floats = entity._num_floats;
      var abs_buffer = null;

      switch (entity.altitude_mode) {
        case AltitudeMode.RELATIVE:
          var num_points = this._numPoints();

          abs_buffer = new Float64Array(num_floats); // abs_buffer[] の高度要素に現在の標高を設定

          entity.scene.viewer.getExistingElevations(num_points, point_array, 0, 3, abs_buffer, 2, 3); // abs_buffer[] に経度要素と緯度要素を設定し、高度要素に絶対高度を設定

          for (var i = 0; i < num_floats; i += 3) {
            abs_buffer[i] = point_array[i]; // 経度

            abs_buffer[i + 1] = point_array[i + 1]; // 緯度

            abs_buffer[i + 2] += point_array[i + 2]; // 絶対高度
          }

          break;

        default:
          // AltitudeMode.ABSOLUTE
          abs_buffer = point_array;
          break;
      }

      return abs_buffer;
    }
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * <pre>
     * 出力:
     *   this._transform
     *   this._pivot
     *   this._bbox
     * </pre>
     *
     * @param {Float64Array} gocs_buffer  入力頂点配列 (GOCS)
     * @param {number}       num_points   入力頂点数
     * @private
     */

  }, {
    key: "_updateTransformPivotBBox",
    value: function _updateTransformPivotBBox(gocs_buffer, num_points) {
      // モデル座標系の原点 (GOCS)
      var ox = gocs_buffer[0];
      var oy = gocs_buffer[1];
      var oz = gocs_buffer[2]; // 変換行列の更新

      var transform = this._transform;
      transform[12] = ox;
      transform[13] = oy;
      transform[14] = oz; // 統計

      var xsum = 0;
      var ysum = 0;
      var zsum = 0;
      var xmin = Number.MAX_VALUE;
      var ymin = Number.MAX_VALUE;
      var zmin = Number.MAX_VALUE;
      var xmax = -Number.MAX_VALUE;
      var ymax = -Number.MAX_VALUE;
      var zmax = -Number.MAX_VALUE;

      for (var i = 0; i < num_points; ++i) {
        var b = 3 * i;
        var x = gocs_buffer[b] - ox;
        var y = gocs_buffer[b + 1] - oy;
        var z = gocs_buffer[b + 2] - oz;
        xsum += x;
        ysum += y;
        zsum += z;

        if (x < xmin) {
          xmin = x;
        }

        if (y < ymin) {
          ymin = y;
        }

        if (z < zmin) {
          zmin = z;
        }

        if (x > xmax) {
          xmax = x;
        }

        if (y > ymax) {
          ymax = y;
        }

        if (z > zmax) {
          zmax = z;
        }
      } // 中心点


      var pivot = this._pivot;
      pivot[0] = xsum / num_points;
      pivot[1] = ysum / num_points;
      pivot[2] = zsum / num_points; // 境界箱

      var bbox = this._bbox;
      var bmin = bbox[0];
      var bmax = bbox[1];
      bmin[0] = xmin;
      bmin[1] = ymin;
      bmin[2] = zmin;
      bmax[0] = xmax;
      bmax[1] = ymax;
      bmax[2] = zmax;
    }
    /**
     * @summary 頂点配列の生成
     *
     * @param  {Float64Array} gocs_buffer  入力頂点配列 (GOCS)
     * @param  {number}       num_points   入力頂点数
     * @return {Float32Array}              Mesh 用の頂点配列
     *
     * @private
     */

  }, {
    key: "_createVertices",
    value: function _createVertices(gocs_buffer, num_points) {
      // モデル座標系の原点 (GOCS)
      var ox = gocs_buffer[0];
      var oy = gocs_buffer[1];
      var oz = gocs_buffer[2];
      var num_segments = num_points - 1;
      var num_vertices = 4 * num_segments;
      var vertices = new Float32Array(8 * num_vertices);

      for (var i = 0; i < num_segments; ++i) {
        var b = 3 * i;
        var sx = gocs_buffer[b] - ox;
        var sy = gocs_buffer[b + 1] - oy;
        var sz = gocs_buffer[b + 2] - oz;
        var ex = gocs_buffer[b + 3] - ox;
        var ey = gocs_buffer[b + 4] - oy;
        var ez = gocs_buffer[b + 5] - oz;
        var dx = gocs_buffer[b + 3] - gocs_buffer[b];
        var dy = gocs_buffer[b + 4] - gocs_buffer[b + 1];
        var dz = gocs_buffer[b + 5] - gocs_buffer[b + 2];
        var v = 32 * i; // 始左

        vertices[v] = sx; // a_position.x

        vertices[v + 1] = sy; // a_position.y

        vertices[v + 2] = sz; // a_position.z

        vertices[v + 3] = dx; // a_direction.x

        vertices[v + 4] = dy; // a_direction.y

        vertices[v + 5] = dz; // a_direction.z

        vertices[v + 6] = -1; // a_where.x

        vertices[v + 7] = 1; // a_where.y
        // 始右

        vertices[v + 8] = sx;
        vertices[v + 9] = sy;
        vertices[v + 10] = sz;
        vertices[v + 11] = dx;
        vertices[v + 12] = dy;
        vertices[v + 13] = dz;
        vertices[v + 14] = -1;
        vertices[v + 15] = -1; // 終左

        vertices[v + 16] = ex;
        vertices[v + 17] = ey;
        vertices[v + 18] = ez;
        vertices[v + 19] = dx;
        vertices[v + 20] = dy;
        vertices[v + 21] = dz;
        vertices[v + 22] = 1;
        vertices[v + 23] = 1; // 終右

        vertices[v + 24] = ex;
        vertices[v + 25] = ey;
        vertices[v + 26] = ez;
        vertices[v + 27] = dx;
        vertices[v + 28] = dy;
        vertices[v + 29] = dz;
        vertices[v + 30] = 1;
        vertices[v + 31] = -1;
      }

      return vertices;
    }
    /**
     * @summary 頂点インデックスの生成
     *
     * @desc
     * <pre>
     * 条件: this.entity._num_floats >= 6
     * 入力: this.entity._num_floats
     * </pre>
     *
     * @return {Uint32Array}  インデックス配列
     *
     * @private
     */

  }, {
    key: "_createIndices",
    value: function _createIndices() {
      var num_points = this._numPoints();

      var num_segments = num_points - 1;
      var num_indices = 6 * num_segments;
      var indices = new Uint32Array(num_indices);

      for (var i = 0; i < num_segments; ++i) {
        var base_d = 6 * i;
        var base_s = 4 * i;
        indices[base_d] = base_s;
        indices[base_d + 1] = base_s + 1;
        indices[base_d + 2] = base_s + 2;
        indices[base_d + 3] = base_s + 2;
        indices[base_d + 4] = base_s + 1;
        indices[base_d + 5] = base_s + 3;
      }

      return indices;
    }
    /**
     * @summary 頂点数を取得
     *
     * @return {number} 頂点数
     *
     * @private
     */

  }, {
    key: "_numPoints",
    value: function _numPoints() {
      return Math.floor(this.entity._num_floats / 3);
    }
  }]);

  return PrimitiveProducer;
}(Entity.PrimitiveProducer);
/**
 * @summary MarkerLineEntity の FlakePrimitiveProducer
 *
 * @private
 */


var FlakePrimitiveProducer$1 =
/*#__PURE__*/
function (_Entity$FlakePrimitiv) {
  _inherits(FlakePrimitiveProducer, _Entity$FlakePrimitiv);

  /**
   * @param {mapray.MarkerLineEntity} entity
   */
  function FlakePrimitiveProducer(entity) {
    var _this3;

    _classCallCheck(this, FlakePrimitiveProducer);

    _this3 = _possibleConstructorReturn(this, _getPrototypeOf(FlakePrimitiveProducer).call(this, entity));
    _this3._material = entity._getMarkerLineMaterial();
    _this3._properties = null;
    _this3._area_manager = new LineAreaManager(entity);
    return _this3;
  }
  /**
   * @override
   */


  _createClass(FlakePrimitiveProducer, [{
    key: "getAreaStatus",
    value: function getAreaStatus(area) {
      return this._area_manager.getAreaStatus(area);
    }
    /**
     * @override
     */

  }, {
    key: "createMesh",
    value: function createMesh(area, dpows, dem) {
      var segments = this._divideXY(area, dpows);

      if (segments.length == 0) {
        return null;
      } // メッシュ生成


      var mesh_data = {
        vtype: [{
          name: "a_position",
          size: 3
        }, {
          name: "a_direction",
          size: 3
        }, {
          name: "a_where",
          size: 2
        }],
        vertices: this._createVertices(area, dem, segments),
        indices: this._createIndices(segments.length)
      };
      return new Mesh(this.entity.scene.glenv, mesh_data);
    }
    /**
     * @override
     */

  }, {
    key: "getMaterialAndProperties",
    value: function getMaterialAndProperties(stage) {
      if (this._properties === null) {
        var entity = this.entity;
        this._properties = {
          width: entity._width,
          color: GeoMath.createVector3f(entity._color),
          opacity: entity._opacity
        };
      }

      return {
        material: this._material,
        properties: this._properties
      };
    }
    /**
     * @summary 頂点が変更されたことを通知
     */

  }, {
    key: "onChangePoints",
    value: function onChangePoints() {
      this._area_manager.notifyForUpdateContent();

      this.notifyForUpdate();
    }
    /**
     * @summary プロパティが変更されたことを通知
     */

  }, {
    key: "onChangeProperty",
    value: function onChangeProperty() {
      this._properties = null;
    }
    /**
     * @summary すべての線分を垂直グリッドで分割
     *
     * @param {mapray.Area} area   地表断片の領域
     * @param {number}      msize  area 寸法 ÷ π (厳密値)
     * @param {number}      dpow   area の x 分割指数
     *
     * @private
     */

  }, {
    key: "_divideXOnly",
    value: function _divideXOnly(area, msize, dpow) {
      var x_min = Math.PI * (area.x * msize - 1);
      var x_max = Math.PI * ((area.x + 1) * msize - 1);
      var div_x = 1 << dpow; // 横分割数: 2^dpow

      var step_x = (x_max - x_min) / div_x; // 横分割間隔

      var segments = []; // 垂直グリッド線で分割

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this._area_manager.getAreaContent(area)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var _step$value = _slicedToArray(_step.value, 4),
              px = _step$value[0],
              py = _step$value[1],
              qx = _step$value[2],
              qy = _step$value[3];

          var _ref = px <= qx ? [px, py, qx, qy] : [qx, qy, px, py],
              _ref2 = _slicedToArray(_ref, 4),
              x0 = _ref2[0],
              y0 = _ref2[1],
              x1 = _ref2[2],
              y1 = _ref2[3]; // assert: x0 <= x1


          if (x1 < x_min || x0 >= x_max) {
            // 線分の x 座標が area の範囲外
            continue;
          }

          if (x0 == x1) {
            // 垂直線分なので、垂直グリッド線で分割しない
            segments.push([x0, y0, x1, y1]);
            continue;
          }

          var delta = (y1 - y0) / (x1 - x0); // 左端でトリミング

          var tx0 = x0;
          var ty0 = y0;

          if (x0 < x_min) {
            tx0 = x_min;
            ty0 = y0 + delta * (x_min - x0); // 左端線と線分の交点の y 座標
          } // 右端でトリミング


          var tx1 = x1;
          var ty1 = y1;

          if (x1 > x_max) {
            tx1 = x_max;
            ty1 = y0 + delta * (x_max - x0); // 右端線と線分の交点の y 座標
          } // グリッド線の範囲


          var i_min = Math.max(Math.ceil((x0 - x_min) / step_x), 1);
          var i_max = Math.min(Math.floor((x1 - x_min) / step_x), div_x - 1);
          var prev_x = tx0;
          var prev_y = ty0;

          for (var i = i_min; i <= i_max; ++i) {
            var next_x = x_min + step_x * i; // 垂直グリッド線の x 座標

            var next_y = y0 + delta * (next_x - x0); // 垂直グリッド線と線分の交点の y 座標

            if (prev_x != next_x || prev_y != next_y) {
              segments.push([prev_x, prev_y, next_x, next_y]);
            }

            prev_x = next_x;
            prev_y = next_y;
          }

          if (prev_x != tx1 || prev_y != ty1) {
            segments.push([prev_x, prev_y, tx1, ty1]);
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return segments;
    }
    /**
     * @summary すべての線分をグリッドで分割
     *
     * @param {mapray.Area} area   地表断片の領域
     * @param {number[]}    dpows  area の xy 分割指数
     *
     * @private
     */

  }, {
    key: "_divideXY",
    value: function _divideXY(area, dpows) {
      // area 寸法 ÷ π (厳密値)
      // 線分の場合、領域の端によるクリッピングがシビアなので厳密値 (2^整数) を使う
      var msize = 2 / Math.round(Math.pow(2, area.z)); // area の y 座標の範囲

      var y_min = Math.PI * (1 - (area.y + 1) * msize);
      var y_max = Math.PI * (1 - area.y * msize);
      var div_y = 1 << dpows[1]; // 縦分割数: 2^dpow

      var step_y = (y_max - y_min) / div_y; // 縦分割間隔

      var segments = []; // 水平グリッド線で分割

      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this._divideXOnly(area, msize, dpows[0])[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var _step2$value = _slicedToArray(_step2.value, 4),
              px = _step2$value[0],
              py = _step2$value[1],
              qx = _step2$value[2],
              qy = _step2$value[3];

          var _ref3 = py <= qy ? [px, py, qx, qy] : [qx, qy, px, py],
              _ref4 = _slicedToArray(_ref3, 4),
              x0 = _ref4[0],
              y0 = _ref4[1],
              x1 = _ref4[2],
              y1 = _ref4[3]; // assert: y0 <= y1


          if (y1 < y_min || y0 >= y_max) {
            // 線分の y 座標が area の範囲外
            continue;
          }

          if (y0 == y1) {
            // 水平線分なので、水平グリッド線で分割しない
            segments.push([x0, y0, x1, y1]);
            continue;
          }

          var delta = (x1 - x0) / (y1 - y0); // 下端でトリミング

          var tx0 = x0;
          var ty0 = y0;

          if (y0 < y_min) {
            tx0 = x0 + delta * (y_min - y0); // 下端線と線分の交点の x 座標

            ty0 = y_min;
          } // 上端でトリミング


          var tx1 = x1;
          var ty1 = y1;

          if (y1 > y_max) {
            tx1 = x0 + delta * (y_max - y0); // 上端線と線分の交点の x 座標

            ty1 = y_max;
          } // グリッド線の範囲


          var i_min = Math.max(Math.ceil((y0 - y_min) / step_y), 1);
          var i_max = Math.min(Math.floor((y1 - y_min) / step_y), div_y - 1);
          var prev_x = tx0;
          var prev_y = ty0;

          for (var i = i_min; i <= i_max; ++i) {
            var next_y = y_min + step_y * i; // 水平グリッド線の y 座標

            var next_x = x0 + delta * (next_y - y0); // 水平グリッド線と線分の交点の x 座標

            if (prev_x != next_x || prev_y != next_y) {
              segments.push([prev_x, prev_y, next_x, next_y]);
            }

            prev_x = next_x;
            prev_y = next_y;
          }

          if (prev_x != tx1 || prev_y != ty1) {
            segments.push([prev_x, prev_y, tx1, ty1]);
          }
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      return segments;
    }
    /**
     * @summary 頂点配列の生成
     *
     * @param {mapray.Area}      area  地表断片の領域
     * @param {mapray.DemBinary} dem   DEM バイナリ
     *
     * @return {Float32Array}  Mesh 用の頂点配列
     *
     * @private
     */

  }, {
    key: "_createVertices",
    value: function _createVertices(area, dem, segments) {
      var sampler = dem.newLinearSampler();

      var _AreaUtil$getCenter = AreaUtil.getCenter(area, GeoMath.createVector3()),
          _AreaUtil$getCenter2 = _slicedToArray(_AreaUtil$getCenter, 3),
          ox = _AreaUtil$getCenter2[0],
          oy = _AreaUtil$getCenter2[1],
          oz = _AreaUtil$getCenter2[2];

      var num_segments = segments.length;
      var num_vertices = 4 * num_segments;
      var vertices = new Float32Array(8 * num_vertices);

      for (var i = 0; i < num_segments; ++i) {
        var _segments$i = _slicedToArray(segments[i], 4),
            smx = _segments$i[0],
            smy = _segments$i[1],
            emx = _segments$i[2],
            emy = _segments$i[3];

        var _toGocs = toGocs(smx, smy, sampler),
            _toGocs2 = _slicedToArray(_toGocs, 3),
            sgx = _toGocs2[0],
            sgy = _toGocs2[1],
            sgz = _toGocs2[2];

        var _toGocs3 = toGocs(emx, emy, sampler),
            _toGocs4 = _slicedToArray(_toGocs3, 3),
            egx = _toGocs4[0],
            egy = _toGocs4[1],
            egz = _toGocs4[2];

        var sx = sgx - ox;
        var sy = sgy - oy;
        var sz = sgz - oz;
        var ex = egx - ox;
        var ey = egy - oy;
        var ez = egz - oz;
        var dx = egx - sgx;
        var dy = egy - sgy;
        var dz = egz - sgz;
        var v = 32 * i; // 始左

        vertices[v] = sx; // a_position.x

        vertices[v + 1] = sy; // a_position.y

        vertices[v + 2] = sz; // a_position.z

        vertices[v + 3] = dx; // a_direction.x

        vertices[v + 4] = dy; // a_direction.y

        vertices[v + 5] = dz; // a_direction.z

        vertices[v + 6] = -1; // a_where.x

        vertices[v + 7] = 1; // a_where.y
        // 始右

        vertices[v + 8] = sx;
        vertices[v + 9] = sy;
        vertices[v + 10] = sz;
        vertices[v + 11] = dx;
        vertices[v + 12] = dy;
        vertices[v + 13] = dz;
        vertices[v + 14] = -1;
        vertices[v + 15] = -1; // 終左

        vertices[v + 16] = ex;
        vertices[v + 17] = ey;
        vertices[v + 18] = ez;
        vertices[v + 19] = dx;
        vertices[v + 20] = dy;
        vertices[v + 21] = dz;
        vertices[v + 22] = 1;
        vertices[v + 23] = 1; // 終右

        vertices[v + 24] = ex;
        vertices[v + 25] = ey;
        vertices[v + 26] = ez;
        vertices[v + 27] = dx;
        vertices[v + 28] = dy;
        vertices[v + 29] = dz;
        vertices[v + 30] = 1;
        vertices[v + 31] = -1;
      }

      return vertices;
    }
    /**
     * @summary @summary 頂点インデックスの生成
     *
     * @param {number} num_segments  線分の数
     *
     * @return {Uint32Array}  Mesh 用の頂点インデックス
     *
     * @private
     */

  }, {
    key: "_createIndices",
    value: function _createIndices(num_segments) {
      var num_indices = 6 * num_segments;
      var indices = new Uint32Array(num_indices);

      for (var i = 0; i < num_segments; ++i) {
        var base_d = 6 * i;
        var base_s = 4 * i;
        indices[base_d] = base_s;
        indices[base_d + 1] = base_s + 1;
        indices[base_d + 2] = base_s + 2;
        indices[base_d + 3] = base_s + 2;
        indices[base_d + 4] = base_s + 1;
        indices[base_d + 5] = base_s + 3;
      }

      return indices;
    }
  }]);

  return FlakePrimitiveProducer;
}(Entity.FlakePrimitiveProducer);
/**
 * @private
 */


function toGocs(x, y, sampler) {
  var λ = x;
  var φ = GeoMath.gudermannian(y);
  var r = GeoMath.EARTH_RADIUS + sampler.sample(x, y);
  var cosφ = Math.cos(φ);
  return [r * cosφ * Math.cos(λ), r * cosφ * Math.sin(λ), r * Math.sin(φ)];
}
/**
 * @summary 線分の領域管理
 *
 * @private
 */


var LineAreaManager =
/*#__PURE__*/
function (_QAreaManager) {
  _inherits(LineAreaManager, _QAreaManager);

  /**
   * @param {mapray.MarkerLineEntity} entity  管理対象のエンティティ
   */
  function LineAreaManager(entity) {
    var _this4;

    _classCallCheck(this, LineAreaManager);

    _this4 = _possibleConstructorReturn(this, _getPrototypeOf(LineAreaManager).call(this));
    _this4._entity = entity;
    return _this4;
  }
  /**
   * @override
   */


  _createClass(LineAreaManager, [{
    key: "getInitialContent",
    value: function getInitialContent() {
      var Degree = GeoMath.DEGREE;
      var RAngle = Math.PI / 2; // 直角

      var TwoPI = 2 * Math.PI; // 2π

      var segments = []; // 頂点データ

      var points = this._entity._point_array;
      var end_point = this._entity._num_floats;

      if (end_point < 6) {
        // 線分なし
        return segments;
      } // 線分の始点 (ラジアン)


      var lon0 = points[0] * Degree;
      var lat0 = points[1] * Degree;
      var lon1;
      var lat1;

      for (var i = 3; i < end_point; i += 3, lon0 = lon1, lat0 = lat1) {
        // 線分の終点 (ラジアン)
        lon1 = points[i] * Degree;
        lat1 = points[i + 1] * Degree;

        if (lat0 <= -RAngle || lat0 >= RAngle || lat1 <= -RAngle || lat1 >= RAngle) {
          // 端点の緯度の絶対値が RAngle 以上の線分は除外
          // ※ まだ検討していないので、とりあえずの処置
          continue;
        } // 単位球メルカトル座標系に変換


        var x0 = lon0;
        var y0 = GeoMath.invGudermannian(lat0);
        var x1 = lon1;
        var y1 = GeoMath.invGudermannian(lat1); // 左端点と右端点

        var _ref5 = x0 < x1 ? [x0, y0, x1, y1] : [x1, y1, x0, y0],
            _ref6 = _slicedToArray(_ref5, 4),
            xL = _ref6[0],
            yL = _ref6[1],
            xR = _ref6[2],
            yR = _ref6[3]; // -π <= xL < π になるように xL を正規化


        if (xL < -Math.PI || xL >= Math.PI) {
          var dx = xR - xL;
          xL -= TwoPI * (Math.floor((xL - Math.PI) / TwoPI) + 1);

          if (xL < -Math.PI || xL >= Math.PI) {
            // 誤差対策
            xL = -Math.PI;
          }

          xR = xL + dx;
        }

        if (xL == xR && yL == yR) {
          // 長さ 0 の線分は除外
          continue;
        } // 線分を追加


        segments.push([xL, yL, xR, yR]);

        if (xR > Math.PI) {
          // 線分が 180 度子午線をまたぐとき
          // こちらは多少厳密さを無視する
          segments.push([xL - TwoPI, yL, xR - TwoPI, yR]);
        }
      }

      return segments;
    }
    /**
     * @override
     */

  }, {
    key: "createAreaContent",
    value: function createAreaContent(min_x, min_y, msize, parent_content) {
      // 単位球メルカトルでの領域に変換
      var x_area_min = Math.PI * min_x;
      var x_area_max = Math.PI * (min_x + msize);
      var y_area_min = Math.PI * min_y;
      var y_area_max = Math.PI * (min_y + msize);
      var segments = [];
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = parent_content[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var segment = _step3.value;

          var _segment = _slicedToArray(segment, 4),
              xP = _segment[0],
              yP = _segment[1],
              xQ = _segment[2],
              yQ = _segment[3];

          if (this._intersect(x_area_min, x_area_max, y_area_min, y_area_max, xP, yP, xQ, yQ)) {
            segments.push(segment);
          }
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }

      return segments.length > 0 ? segments : Entity.AreaStatus.EMPTY;
    }
    /**
     * @summary 矩形と線分の交差判定
     *
     * @desc
     * <p>矩形領域と線分が交差するかどうかを返す。</p>
     * <p>矩形領域には x 座標が x_area_max の点と、y 座標が y_area_max の点は含まれないものとする。</p>
     *
     * <pre>
     * 事前条件:
     *   x_area_min < x_area_max
     *   y_area_min < y_area_max
     * </pre>
     *
     * @param {number} x_area_min  矩形領域の最小 x 座標
     * @param {number} x_area_max  矩形領域の最大 x 座標
     * @param {number} y_area_min  矩形領域の最小 y 座標
     * @param {number} y_area_max  矩形領域の最大 y 座標
     * @param {number} xP          線分端点 P の x 座標
     * @param {number} yP          線分端点 P の y 座標
     * @param {number} xQ          線分端点 Q の x 座標
     * @param {number} yQ          線分端点 Q の y 座標
     *
     * @return {boolean}  交差するとき true, それ以外のとき false
     *
     * @private
     */

  }, {
    key: "_intersect",
    value: function _intersect(x_area_min, x_area_max, y_area_min, y_area_max, xP, yP, xQ, yQ) {
      if (Math.abs(xP - xQ) < Math.abs(yP - yQ)) {
        // 線分が垂直に近いとき
        return this._nhorz_intersect(x_area_min, x_area_max, y_area_min, y_area_max, xP, yP, xQ, yQ);
      } else {
        // 線分が水平に近いとき
        return this._nhorz_intersect(y_area_min, y_area_max, x_area_min, x_area_max, yP, xP, yQ, xQ);
      }
    }
    /**
     * @summary 矩形と非水平線分の交差判定
     *
     * @desc
     * <p>矩形領域と線分が交差するかどうかを返す。</p>
     * <p>矩形領域には x 座標が x_area_max の点と、y 座標が y_area_max の点は含まれないものとする。</p>
     *
     * <pre>
     * 事前条件:
     *   x_area_min < x_area_max
     *   y_area_min < y_area_max
     *   yP != yQ
     * </pre>
     *
     * <p>注意: |yP - yQ| が小さいと精度が悪くなる。</p>
     *
     * @param {number} x_area_min  矩形領域の最小 x 座標
     * @param {number} x_area_max  矩形領域の最大 x 座標
     * @param {number} y_area_min  矩形領域の最小 y 座標
     * @param {number} y_area_max  矩形領域の最大 y 座標
     * @param {number} xP          線分端点 P の x 座標
     * @param {number} yP          線分端点 P の y 座標
     * @param {number} xQ          線分端点 Q の x 座標
     * @param {number} yQ          線分端点 Q の y 座標
     *
     * @return {boolean}  交差するとき true, それ以外のとき false
     *
     * @private
     */

  }, {
    key: "_nhorz_intersect",
    value: function _nhorz_intersect(x_area_min, x_area_max, y_area_min, y_area_max, xP, yP, xQ, yQ) {
      // 線分の y 座標の範囲
      var _ref7 = yP < yQ ? [yP, yQ] : [yQ, yP],
          _ref8 = _slicedToArray(_ref7, 2),
          y_line_min = _ref8[0],
          y_line_max = _ref8[1];

      if (y_line_min >= y_area_max || y_line_max < y_area_min) {
        // 線分の y 範囲が矩形領域の y 範囲の外側なので交差しない
        return false;
      } // 矩形領域と線分の y 座標が重なる範囲 (順不同)


      var y_range_0 = y_area_min >= y_line_max ? y_area_min : y_line_max;
      var y_range_1 = y_area_max <= y_line_min ? y_area_max : y_line_min; // y が {y_range_0, y_range_1} 範囲での線分の x 範囲 (順不同)

      var x_range_0 = xP + (xQ - xP) * (y_range_0 - yP) / (yQ - yP);
      var x_range_1 = xP + (xQ - xP) * (y_range_1 - yP) / (yQ - yP); // y が {y_range_0, y_range_1} 範囲での線分の x 範囲

      var _ref9 = x_range_0 < x_range_1 ? [x_range_0, x_range_1] : [x_range_1, x_range_0],
          _ref10 = _slicedToArray(_ref9, 2),
          x_range_min = _ref10[0],
          x_range_max = _ref10[1]; // [x_range_min, x_range_max] 範囲は矩形領域の x の範囲と重なるか?


      return x_range_min < x_area_max && x_range_max >= x_area_min;
    }
  }]);

  return LineAreaManager;
}(QAreaManager);

var text_vs_code = "/**\n * テキスト (頂点シェーダ)\n */\n\nattribute vec4 a_position;    // 頂点位置 (モデル座標系)\nattribute vec2 a_offset;      // 頂点変位 (スクリーン座標系)\nattribute vec2 a_texcoord;    // テクスチャ座標\n\nuniform mat4 u_obj_to_clip;   // モデル座標系からクリップ座標系への変換\nuniform vec2 u_sparam;        // 画面パラメータ: {2/w, 2/h}\n\nvarying vec2 v_texcoord;      // テキストのテクスチャ座標\n\nvoid\nmain()\n{\n    gl_Position = u_obj_to_clip * a_position;\n    gl_Position.xy += a_offset * u_sparam * gl_Position.w;\n    v_texcoord = a_texcoord;\n}";

var text_fs_code = "/**\n * テキスト (フラグメントシェーダ)\n */\n\nprecision mediump float;\n\nvarying vec2 v_texcoord;        // テクスチャ座標\nuniform sampler2D u_image;      // 画像\n\nvoid\nmain()\n{\n    gl_FragColor = texture2D( u_image, v_texcoord );\n}";

/**
 * @summary テキストマテリアル
 * @memberof mapray
 * @extends mapray.EntityMaterial
 * @private
 * @see mapray.TextEntity
 */

var TextMaterial =
/*#__PURE__*/
function (_EntityMaterial) {
  _inherits(TextMaterial, _EntityMaterial);

  /**
   * @param {mapray.GLEnv} glenv
   */
  function TextMaterial(glenv) {
    var _this;

    _classCallCheck(this, TextMaterial);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(TextMaterial).call(this, glenv, text_vs_code, text_fs_code)); // 不変パラメータを事前設定

    _this.bindProgram();

    _this.setInteger("u_image", TextMaterial.TEXUNIT_IMAGE);

    return _this;
  }
  /**
   * @override
   */


  _createClass(TextMaterial, [{
    key: "isTranslucent",
    value: function isTranslucent(stage, primitive) {
      var props = primitive.properties; // If drawing background color, alpha is disable.

      return !props.enable_bg;
    }
    /**
     * @override
     */

  }, {
    key: "setParameters",
    value: function setParameters(stage, primitive) {
      var props = primitive.properties; // mat4 u_obj_to_clip

      this.setObjToClip(stage, primitive); // 画面パラメータ: {2/w, 2/h}
      // vec2 u_sparam

      var sparam = TextMaterial._sparam;
      sparam[0] = 2 / stage._width;
      sparam[1] = 2 / stage._height;
      this.setVector2("u_sparam", sparam); // テクスチャのバインド
      // sampler2D u_image

      var image_tex = props["image"];
      this.bindTexture2D(TextMaterial.TEXUNIT_IMAGE, image_tex.handle);
    }
  }]);

  return TextMaterial;
}(EntityMaterial); // クラス定数の定義


{
  TextMaterial.TEXUNIT_IMAGE = 0; // 画像のテクスチャユニット
  // 計算用一時領域

  TextMaterial._sparam = GeoMath.createVector2f();
}

var text_vs_code$1 = "/**\n * テキスト (頂点シェーダ)\n */\n\nattribute vec4 a_position;    // 頂点位置 (モデル座標系)\nattribute vec2 a_offset;      // 頂点変位 (スクリーン座標系)\nattribute vec2 a_texcoord;    // テクスチャ座標\nattribute vec4 a_color;       // テキストの色と不透明度\n\nuniform mat4 u_obj_to_clip;   // モデル座標系からクリップ座標系への変換\nuniform vec2 u_sparam;        // 画面パラメータ: {2/w, 2/h}\n\nvarying vec2 v_texcoord;      // テキストのテクスチャ座標\nvarying vec4 v_color;         // テキストの色と不透明度\n\nvoid\nmain()\n{\n    gl_Position = u_obj_to_clip * a_position;\n    gl_Position.xy += a_offset * u_sparam * gl_Position.w;\n    v_texcoord = a_texcoord;\n    v_color    = a_color;\n}\n";

var text_fs_code$1 = "/**\n * テキスト (フラグメントシェーダ)\n */\n\nprecision mediump float;\n\nvarying vec2 v_texcoord;     // テキストのテクスチャ座標\nvarying vec4 v_color;        // テキストの色と不透明度\n\nuniform sampler2D u_image;   // テキスト画像\n\nvoid\nmain()\n{\n    float level = texture2D( u_image, v_texcoord ).w;  // 輝度\n    float alpha = v_color.w * level;\n    gl_FragColor = vec4( v_color.xyz * alpha, alpha );\n}\n";

/**
 * @summary テキストマテリアル
 * @memberof mapray
 * @extends mapray.EntityMaterial
 * @private
 * @see mapray.TextEntity
 */

var SimpleTextMaterial =
/*#__PURE__*/
function (_EntityMaterial) {
  _inherits(SimpleTextMaterial, _EntityMaterial);

  /**
   * @param {mapray.GLEnv} glenv
   */
  function SimpleTextMaterial(glenv) {
    var _this;

    _classCallCheck(this, SimpleTextMaterial);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(SimpleTextMaterial).call(this, glenv, text_vs_code$1, text_fs_code$1)); // 不変パラメータを事前設定

    _this.bindProgram();

    _this.setInteger("u_image", SimpleTextMaterial.TEXUNIT_IMAGE);

    return _this;
  }
  /**
   * @override
   */


  _createClass(SimpleTextMaterial, [{
    key: "isTranslucent",
    value: function isTranslucent(stage, primitive) {
      // アンチエイリアス用のブレンドのため常に半透明
      return true;
    }
    /**
     * @override
     */

  }, {
    key: "setParameters",
    value: function setParameters(stage, primitive) {
      var props = primitive.properties; // mat4 u_obj_to_clip

      this.setObjToClip(stage, primitive); // 画面パラメータ: {2/w, 2/h}
      // vec2 u_sparam

      var sparam = SimpleTextMaterial._sparam;
      sparam[0] = 2 / stage._width;
      sparam[1] = 2 / stage._height;
      this.setVector2("u_sparam", sparam); // テクスチャのバインド
      // sampler2D u_image

      var image_tex = props["image"];
      this.bindTexture2D(SimpleTextMaterial.TEXUNIT_IMAGE, image_tex.handle);
    }
  }]);

  return SimpleTextMaterial;
}(EntityMaterial); // クラス定数の定義


{
  SimpleTextMaterial.TEXUNIT_IMAGE = 0; // 画像のテクスチャユニット
  // 計算用一時領域

  SimpleTextMaterial._sparam = GeoMath.createVector2f();
}

/**
 * @summary Utility Class for Color
 * @memberof mapray
 */
var Color =
/*#__PURE__*/
function () {
  /**
   * @param r {number}    The red (0.0 ~ 1.0)
   * @param g {number}    The green (0.0 ~ 1.0)
   * @param b {number}    The blue (0.0 ~ 1.0)
   * @param a {number}    The alpha (0.0 ~ 1.0)
   */
  function Color(r, g, b, a) {
    _classCallCheck(this, Color);

    this._r = r;
    this._g = g;
    this._b = b;
    this._a = a;
  }
  /**
   * @summary 不透明色を生成
   * @param  {mapray.Vector3}
   * @return {mapray.Color}
   */


  _createClass(Color, [{
    key: "toArray",

    /**
     * @summary 色配列に変換する
     * @desc
     * <p>0から255に正規化。 [R, G, B, A]の順番</p>
     *
     * @return {mapray.Vector4}      dst
     */
    value: function toArray() {
      return this._a === 0 ? [0, 0, 0, 0] : [this.floatToByte(this._r) / this._a, this.floatToByte(this._g) / this._a, this.floatToByte(this._b) / this._a, this._a];
    }
    /**
     * @summary 色配列に変換する
     * @desc
     * <p>0から1に正規化。 [R, G, B, A]の順番</p>
     *
     * @return {mapray.Vector4}      dst
     */

  }, {
    key: "toVector4",
    value: function toVector4() {
      return this._a === 0 ? [0, 0, 0, 0] : [this._r / this._a, this._g / this._a, this._b / this._a, this._a];
    }
    /**
     * @summary RGBA文字列に変換する
     * @desc
     * <p>RGBA文字列に変換して文字列を返却</p>
     *
     * @return {mapray.string}
     */

  }, {
    key: "toRGBString",
    value: function toRGBString() {
      var rgba = this.toArray();
      return "rgba(".concat(Math.round(rgba[0]), ",").concat(Math.round(rgba[1]), ",").concat(Math.round(rgba[2]), ",").concat(rgba[3], ")");
    }
    /**
     * @summary 0~1.0の色値を255までで正規化
     * @desc
     * <p>0から1で正規化された色値を255までに拡張する</p>
     *
     * @return {mapray.string}
     */

  }, {
    key: "floatToByte",
    value: function floatToByte(value) {
      return value === 1.0 ? 255.0 : value * 256.0 | 0;
    }
    /**
     * @summary Red
     * @type {number}
     * @readonly
     */

  }, {
    key: "r",
    get: function get() {
      return this._r;
    }
    /**
     * @summary Green
     * @type {number}
     * @readonly
     */

  }, {
    key: "g",
    get: function get() {
      return this._g;
    }
    /**
    * @summary Blue
    * @type {number}
    * @readonly
    */

  }, {
    key: "b",
    get: function get() {
      return this._b;
    }
    /**
     * @summary Alpha
     * @type {number}
     * @readonly
     */

  }, {
    key: "a",
    get: function get() {
      return this._a;
    }
  }], [{
    key: "generateOpacityColor",
    value: function generateOpacityColor(rgb) {
      return new Color(rgb[0], rgb[1], rgb[2], 1);
    }
    /**
     * @summary 色を代入
     * @desc
     * <p>src を dst に代入する。</p>
     * @param  {mapray.Color} src  代入元
     * @param  {mapray.Color} dst  代入先
     * @return {mapray.Color}      dst
     */

  }, {
    key: "copyColor",
    value: function copyColor(src, dst) {
      dst._r = src._r;
      dst._g = src._g;
      dst._b = src._b;
      dst._a = src._a;
      return dst;
    }
    /**
     * @summary 不透明色を代入
     * @desc
     * <p>src を dst に代入する。</p>
     * @param  {mapray.Vector3} rgb  代入元
     * @param  {mapray.Color} dst  代入先
     * @return {mapray.Color}      dst
     */

  }, {
    key: "setOpacityColor",
    value: function setOpacityColor(rgb, dst) {
      dst._r = rgb[0];
      dst._g = rgb[1];
      dst._b = rgb[2];
      dst._a = 1;
    }
  }]);

  return Color;
}();

/**
 * @summary テキストエンティティ
 *
 * @memberof mapray
 * @extends mapray.Entity
 */

var TextEntity =
/*#__PURE__*/
function (_Entity) {
  _inherits(TextEntity, _Entity);

  /**
   * @param {mapray.Scene} scene        所属可能シーン
   * @param {object}       [opts]       オプション集合
   * @param {object}       [opts.json]  生成情報
   * @param {object}       [opts.refs]  参照辞書
   */
  function TextEntity(scene, opts) {
    var _this;

    _classCallCheck(this, TextEntity);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(TextEntity).call(this, scene, opts)); // テキスト管理

    _this._entries = []; // テキストの親プロパティ

    _this._text_parent_props = {
      font_style: "normal",
      font_weight: "normal",
      font_size: TextEntity.DEFAULT_FONT_SIZE,
      font_family: TextEntity.DEFAULT_FONT_FAMILY,
      color: Color.generateOpacityColor(TextEntity.DEFAULT_COLOR),
      stroke_color: Color.generateOpacityColor(TextEntity.DEFAULT_STROKE_COLOR),
      stroke_width: TextEntity.DEFAULT_STROKE_WIDTH,
      bg_color: Color.generateOpacityColor(TextEntity.DEFAULT_BG_COLOR),
      enable_stroke: false,
      enable_bg: false
    }; // 生成情報から設定

    if (opts && opts.json) {
      _this._setupByJson(opts.json);
    }

    return _this;
  }
  /**
   * @override
   */


  _createClass(TextEntity, [{
    key: "getPrimitiveProducer",
    value: function getPrimitiveProducer() {
      return this._primitive_producer;
    }
    /**
     * @override
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode(prev_mode) {
      this._primitive_producer.onChangeAltitudeMode();
    }
    /**
     * @summary フォントスタイルを設定
     * @param {string} style  フォントスタイル ("normal" | "italic" | "oblique")
     */

  }, {
    key: "setFontStyle",
    value: function setFontStyle(style) {
      this._setValueProperty("font_style", style);
    }
    /**
     * @summary フォントの太さを設定
     * @param {string} weight  フォントの太さ ("normal" | "bold")
     */

  }, {
    key: "setFontWeight",
    value: function setFontWeight(weight) {
      this._setValueProperty("font_weight", weight);
    }
    /**
     * @summary フォントの大きさを設定
     * @param {number} size  フォントの大きさ (Pixels)
     */

  }, {
    key: "setFontSize",
    value: function setFontSize(size) {
      this._setValueProperty("font_size", size);
    }
    /**
     * @summary フォントファミリーを設定
     * @param {string} family  フォントファミリー
     * @see https://developer.mozilla.org/ja/docs/Web/CSS/font-family
     */

  }, {
    key: "setFontFamily",
    value: function setFontFamily(family) {
      this._setValueProperty("font_family", family);
    }
    /**
     * @summary テキストの色を設定
     * @param {mapray.Vector3} color  テキストの色
     */

  }, {
    key: "setColor",
    value: function setColor(color) {
      this._setColorProperty("color", color);
    }
    /**
     * @summary テキスト縁の色を設定
     * @param {mapray.Vector3} color  縁の色
     */

  }, {
    key: "setStrokeColor",
    value: function setStrokeColor(color) {
      this._setColorProperty("stroke_color", color);
    }
    /**
     * @summary テキスト縁の太さを設定
     * @param {mapray.number} width  縁の線幅
     */

  }, {
    key: "setStrokeLineWidth",
    value: function setStrokeLineWidth(width) {
      this._setValueProperty("stroke_width", width);
    }
    /**
     * @summary テキスト縁を有効にするかどうか
     * @param {boolean} enable  trueなら有効
     */

  }, {
    key: "setEnableStroke",
    value: function setEnableStroke(enable) {
      this._setValueProperty("enable_stroke", enable);

      this._primitive_producer = new PrimitiveProducer$2(this);
    }
    /**
     * @summary テキスト背景の色を設定
     * @param {mapray.Vector3} color  テキストの色
     */

  }, {
    key: "setBackgroundColor",
    value: function setBackgroundColor(color) {
      this._setColorProperty("bg_color", color);
    }
    /**
    * @summary テキスト縁を有効にするかどうか
    * @param {boolean} enable  trueなら有効
    */

  }, {
    key: "setEnableBackground",
    value: function setEnableBackground(enable) {
      this._setValueProperty("enable_bg", enable);

      this._primitive_producer = new PrimitiveProducer$2(this);
    }
    /**
     * @summary テキストを追加
     * @param {string}          text      テキスト
     * @param {mapray.GeoPoint} position  位置
     * @param {object}          [props]   プロパティ
     * @param {string}         [props.font_style]   フォントスタイル ("normal" | "italic" | "oblique")
     * @param {string}         [props.font_weight]  フォントの太さ   ("normal" | "bold")
     * @param {number}         [props.font_size]    フォントの大きさ (Pixels)
     * @param {string}         [props.font_family]  フォントファミリー
     * @param {mapray.Color}   [props.color]        テキストの色
     * @param {mapray.Color}   [props.stroke_color] テキスト縁の色
     * @param {number}         [props.stroke_width] テキスト縁の幅
     * @param {mapray.Color}   [props.bg_color]     テキスト背景色
     * @param {boolean}        [props.enable_stroke] テキストの縁取りを有効にするか
     */

  }, {
    key: "addText",
    value: function addText(text, position, props) {
      this._entries.push(new Entry$2(this, text, position, props));

      this._primitive_producer = new PrimitiveProducer$2(this);

      this._primitive_producer.onAddTextEntry();
    }
    /**
     * @summary 専用マテリアルを取得
     * @private
     */

  }, {
    key: "_getTextMaterial",
    value: function _getTextMaterial() {
      var scene = this.scene;

      if (!scene._TextEntity_text_material) {
        // scene にマテリアルをキャッシュ
        scene._TextEntity_text_material = new TextMaterial(scene.glenv);
      }

      return scene._TextEntity_text_material;
    }
    /**
     * @summary テキストだけを描画する専用マテリアルを取得
     * @private
     */

  }, {
    key: "_getSimpleTextMaterial",
    value: function _getSimpleTextMaterial() {
      var scene = this.scene;

      if (!scene._SimpleTextEntity_text_material) {
        // scene にマテリアルをキャッシュ
        scene._SimpleTextEntity_text_material = new SimpleTextMaterial(scene.glenv);
      }

      return scene._SimpleTextEntity_text_material;
    }
    /**
     * @private
     */

  }, {
    key: "_setValueProperty",
    value: function _setValueProperty(name, value) {
      var props = this._text_parent_props;

      if (props[name] != value) {
        props[name] = value;

        this._primitive_producer.onChangeParentProperty();
      }
    }
    /**
     * @private
     */

  }, {
    key: "_setColorProperty",
    value: function _setColorProperty(name, value) {
      var dst = this._text_parent_props[name];

      if (dst.r != value[0] || dst.g != value[1] || dst.b != value[2]) {
        Color.setOpacityColor(value, dst);

        this._primitive_producer.onChangeParentProperty();
      }
    }
    /**
     * @private
     */

  }, {
    key: "_setupByJson",
    value: function _setupByJson(json) {
      var position = new GeoPoint();
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = json.entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var entry = _step.value;
          position.setFromArray(entry.position);
          this.addText(entry.text, position, entry);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      if (json.font_style !== undefined) this.setFontStyle(json.font_style);
      if (json.font_weight !== undefined) this.setFontWeight(json.font_weight);
      if (json.font_size !== undefined) this.setFontSize(json.font_size);
      if (json.font_family !== undefined) this.setFontFamily(json.font_family);
      if (json.color !== undefined) this.setColor(json.color);
      if (json.stroke_color !== undefined) this.setStrokeColor(json.stroke_color);
      if (json.stroke_width !== undefined) this.setStrokeLineWidth(json.stroke_width);
      if (json.enable_stroke !== undefined) this.setEnableStroke(json.enable_stroke);
      if (json.bg_color !== undefined) this.setBackgroundColor(json.bg_color);
      if (json.enable_bg !== undefined) this.setEnableBackground(json.enable_bg);
    }
    /**
     * @private
     */

  }, {
    key: "_enableStroke",
    value: function _enableStroke() {
      return this._text_parent_props["enable_stroke"];
    }
  }]);

  return TextEntity;
}(Entity); // クラス定数の定義


{
  TextEntity.DEFAULT_FONT_SIZE = 16;
  TextEntity.DEFAULT_FONT_FAMILY = "sans-serif";
  TextEntity.DEFAULT_COLOR = [1, 1, 1];
  TextEntity.DEFAULT_STROKE_COLOR = [0.0, 0.0, 0.0];
  TextEntity.DEFAULT_STROKE_WIDTH = 0.48;
  TextEntity.DEFAULT_BG_COLOR = [0.3, 0.3, 0.3];
  TextEntity.DEFAULT_TEXT_UPPER = 1.1;
  TextEntity.DEFAULT_TEXT_LOWER = 0.38;
  TextEntity.SAFETY_PIXEL_MARGIN = 1;
  TextEntity.MAX_IMAGE_WIDTH = 4096;
}
/**
 * @summary TextEntity の PrimitiveProducer
 *
 * TODO: relative で標高の変化のたびにテクスチャを生成する必要はないので
 *       Layout でのテクスチャの生成とメッシュの生成を分離する
 *
 * @private
 */

var PrimitiveProducer$2 =
/*#__PURE__*/
function (_Entity$PrimitiveProd) {
  _inherits(PrimitiveProducer, _Entity$PrimitiveProd);

  /**
   * @param {mapray.TextEntity} entity
   */
  function PrimitiveProducer(entity) {
    var _this2;

    _classCallCheck(this, PrimitiveProducer);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(PrimitiveProducer).call(this, entity));
    _this2._glenv = entity.scene.glenv;
    _this2._dirty = true; // プリミティブの要素

    _this2._transform = GeoMath.setIdentity(GeoMath.createMatrix());
    _this2._properties = {
      enable_bg: false,
      image: null // テキスト画像

    }; // プリミティブ

    var material = null;

    if (_this2._isSimpleText()) {
      material = entity._getSimpleTextMaterial();
    } else {
      material = entity._getTextMaterial();
    }

    var primitive = new Primitive(_this2._glenv, null, material, _this2._transform);
    primitive.properties = _this2._properties;
    _this2._primitive = primitive; // プリミティブ配列

    _this2._primitives = [];
    return _this2;
  }
  /**
   * @override
   */


  _createClass(PrimitiveProducer, [{
    key: "createRegions",
    value: function createRegions() {
      var region = new EntityRegion();
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this.entity._entries[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var position = _step2.value.position;
          region.addPoint(position);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      return [region];
    }
    /**
     * @override
     */

  }, {
    key: "onChangeElevation",
    value: function onChangeElevation(regions) {
      this._dirty = true;
    }
    /**
     * @override
     */

  }, {
    key: "getPrimitives",
    value: function getPrimitives(stage) {
      return this._updatePrimitive();
    }
    /**
     * @summary 親プロパティが変更されたことを通知
     */

  }, {
    key: "onChangeParentProperty",
    value: function onChangeParentProperty() {
      this._dirty = true;
    }
    /**
     * @summary 高度モードが変更されたことを通知
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode() {
      this._dirty = true;
    }
    /**
     * @summary テキストが追加されたことを通知
     */

  }, {
    key: "onAddTextEntry",
    value: function onAddTextEntry() {
      // 変化した可能性がある
      this.needToCreateRegions();
      this._dirty = true;
    }
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * 入力:
     *   this.entity._entries
     *   this._dirty
     * 出力:
     *   this._transform
     *   this._properties.image
     *   this._primitive.mesh
     *   this._primitives
     *   this._dirty
     *
     * @return {array.<mapray.Prmitive>}  this._primitives
     *
     * @private
     */

  }, {
    key: "_updatePrimitive",
    value: function _updatePrimitive() {
      if (!this._dirty) {
        // 更新する必要はない
        return this._primitives;
      }

      this._updateProperties();

      if (this.entity._entries.length == 0) {
        this._primitives = [];
        this._dirty = false;
        return this._primitives;
      } // 各エントリーの GOCS 位置を生成 (平坦化配列)


      var gocs_array = this._createFlatGocsArray(); // プリミティブの更新
      //   primitive.transform


      this._updateTransform(gocs_array);

      var layout = new Layout(this, gocs_array);

      if (!layout.isValid()) {
        // 更新に失敗
        this._primitives = [];
        this._dirty = false;
        return this._primitives;
      } // テクスチャ設定


      var properties = this._properties;

      if (properties.image) {
        properties.image.dispose();
      }

      properties.image = layout.texture; // メッシュ生成

      var vtype = [];

      if (this._isSimpleText()) {
        vtype = [{
          name: "a_position",
          size: 3
        }, {
          name: "a_offset",
          size: 2
        }, {
          name: "a_texcoord",
          size: 2
        }, {
          name: "a_color",
          size: 4
        }];
      } else {
        vtype = [{
          name: "a_position",
          size: 3
        }, {
          name: "a_offset",
          size: 2
        }, {
          name: "a_texcoord",
          size: 2
        }];
      }

      var mesh_data = {
        vtype: vtype,
        vertices: layout.vertices,
        indices: layout.indices
      };
      var mesh = new Mesh(this._glenv, mesh_data); // メッシュ設定
      //   primitive.mesh

      var primitive = this._primitive;

      if (primitive.mesh) {
        primitive.mesh.dispose();
      }

      primitive.mesh = mesh; // 更新に成功

      this._primitives = [primitive];
      this._dirty = false;
      return this._primitives;
    }
    /**
     * @summary プロパティを更新
     *
     * @desc
     * <pre>
     * 入力:
     *   this.entity
     * 出力:
     *   this._properties
     * </pre>
     *
     * @private
     */

  }, {
    key: "_updateProperties",
    value: function _updateProperties() {
      var entity = this.entity;
      var props = this._properties;
      props.enable_bg = entity._text_parent_props.enable_bg;
    }
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * 条件:
     *   this.entity._entries.length > 0
     * 入力:
     *   this.entity._entries.length
     * 出力:
     *   this._transform
     *
     * @param {number[]} gocs_array  GOCS 平坦化配列
     *
     * @private
     */

  }, {
    key: "_updateTransform",
    value: function _updateTransform(gocs_array) {
      var num_entries = this.entity._entries.length;
      var xsum = 0;
      var ysum = 0;
      var zsum = 0;

      for (var i = 0; i < num_entries; ++i) {
        var ibase = 3 * i;
        xsum += gocs_array[ibase];
        ysum += gocs_array[ibase + 1];
        zsum += gocs_array[ibase + 2];
      } // 変換行列の更新


      var transform = this._transform;
      transform[12] = xsum / num_entries;
      transform[13] = ysum / num_entries;
      transform[14] = zsum / num_entries;
    }
    /**
     * @summary GOCS 平坦化配列を取得
     *
     * 入力: this.entity._entries
     *
     * @return {number[]}  GOCS 平坦化配列
     * @private
     */

  }, {
    key: "_createFlatGocsArray",
    value: function _createFlatGocsArray() {
      var num_points = this.entity._entries.length;
      return GeoPoint.toGocsArray(this._getFlatGeoPoints_with_Absolute(), num_points, new Float64Array(3 * num_points));
    }
    /**
     * @summary GeoPoint 平坦化配列を取得 (絶対高度)
     *
     * 入力: this.entity._entries
     *
     * @return {number[]}  GeoPoint 平坦化配列
     * @private
     */

  }, {
    key: "_getFlatGeoPoints_with_Absolute",
    value: function _getFlatGeoPoints_with_Absolute() {
      var owner = this.entity;
      var entries = owner._entries;
      var num_points = entries.length;
      var flat_array = new Float64Array(3 * num_points); // flat_array[] に経度要素と緯度要素を設定

      for (var i = 0; i < num_points; ++i) {
        var pos = entries[i].position;
        flat_array[3 * i] = pos.longitude;
        flat_array[3 * i + 1] = pos.latitude;
      }

      switch (owner.altitude_mode) {
        case AltitudeMode.RELATIVE:
        case AltitudeMode.CLAMP:
          // flat_array[] の高度要素に現在の標高を設定
          owner.scene.viewer.getExistingElevations(num_points, flat_array, 0, 3, flat_array, 2, 3);

          if (owner.altitude_mode === AltitudeMode.RELATIVE) {
            // flat_array[] の高度要素に相対高度を加える
            for (var _i = 0; _i < num_points; ++_i) {
              flat_array[3 * _i + 2] += entries[_i].position.altitude;
            }
          }

          break;

        default:
          // AltitudeMode.ABSOLUTE
          // flat_array[] の高度要素に絶対高度を設定
          for (var _i2 = 0; _i2 < num_points; ++_i2) {
            flat_array[3 * _i2 + 2] = entries[_i2].position.altitude;
          }

          break;
      }

      return flat_array;
    }
    /**
    * @summary シンプルテキストモードかどうかを確認
    *
    *
    * @return {boolean}  シンプルテキストモードならtrue.
    * @private
    */

  }, {
    key: "_isSimpleText",
    value: function _isSimpleText() {
      var entity = this.entity;
      var enable = true; // check enable bg color or stroke;

      if (entity._text_parent_props.enable_bg || entity._text_parent_props.enable_stroke) {
        enable = false;
      } // check enable stroke


      var i = 0;

      while (enable && entity._entries.length > i) {
        var entry = entity._entries[i];
        enable = !entry.enable_stroke;
        i++;
      }

      return enable;
    }
  }]);

  return PrimitiveProducer;
}(Entity.PrimitiveProducer);
/**
 * @summary テキスト要素
 * @memberof mapray.TextEntity
 * @private
 */


var Entry$2 =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.TextEntity} owner                所有者
   * @param {string}            text                 テキスト
   * @param {mapray.GeoPoint}   position             位置
   * @param {object}            [props]              プロパティ
   * @param {string}            [props.font_style]   フォントスタイル ("normal" | "italic" | "oblique")
   * @param {string}            [props.font_weight]  フォントの太さ   ("normal" | "bold")
   * @param {number}            [props.font_size]    フォントの大きさ (Pixels)
   * @param {string}            [props.font_family]  フォントファミリー
   * @param {mapray.Color}      [props.color]        テキストの色
   * @param {mapray.Color}      [props.stroke_color] テキスト縁の色
   * @param {number}            [props.stroke_width] テキスト縁の幅
   * @param {number}            [props.enable_stroke] テキストの縁取りを有効にするか
   */
  function Entry(owner, text, position, props) {
    _classCallCheck(this, Entry);

    this._owner = owner;
    this._text = text;
    this._position = position.clone();
    this._props = Object.assign({}, props); // props の複製

    this._copyColorProperty("color"); // deep copy


    this._copyColorProperty("stroke_color"); // deep copy


    this._copyColorProperty("bg_color"); // deep copy

  }
  /**
   * @summary テキスト
   * @type {string}
   * @readonly
   */


  _createClass(Entry, [{
    key: "_copyColorProperty",

    /**
     * @private
     */
    value: function _copyColorProperty(name) {
      var props = this._props;

      if (props.hasOwnProperty(name)) {
        props[name] = Color.generateOpacityColor(props[name]);
      }
    }
  }, {
    key: "text",
    get: function get() {
      return this._text;
    }
    /**
     * @summary 位置
     * @type {mapray.GeoPoint}
     * @readonly
     */

  }, {
    key: "position",
    get: function get() {
      return this._position;
    }
    /**
     * @summary フォントサイズ (Pixels)
     * @type {number}
     * @readonly
     */

  }, {
    key: "size",
    get: function get() {
      var props = this._props;
      var parent = this._owner._text_parent_props;
      return props.font_size || parent.font_size;
    }
    /**
     * @summary テキストの色
     * @type {mapray.Vector3}
     * @readonly
     */

  }, {
    key: "color",
    get: function get() {
      var props = this._props;
      var parent = this._owner._text_parent_props;
      return props.color || parent.color;
    }
    /**
     * @summary フォント
     * @type {string}
     * @readonly
     * @see https://developer.mozilla.org/ja/docs/Web/CSS/font
     */

  }, {
    key: "font",
    get: function get() {
      var props = this._props;
      var parent = this._owner._text_parent_props;
      var style = props.font_style || parent.font_style;
      var variant = "normal";
      var weight = props.font_weight || parent.font_weight;
      var family = props.font_family || parent.font_family;
      return style + " " + variant + " " + weight + " " + this.size + "px " + family;
    }
    /**
     * @summary テキスト縁の色
     * @type {mapray.Color}
     * @readonly
     */

  }, {
    key: "stroke_color",
    get: function get() {
      var props = this._props;
      var parent = this._owner._text_parent_props;
      return props.stroke_color || parent.stroke_color;
    }
    /**
     * @summary 縁の幅 (Pixels)
     * @type {number}
     * @readonly
     */

  }, {
    key: "stroke_width",
    get: function get() {
      var props = this._props;
      var parent = this._owner._text_parent_props;
      return props.stroke_width || parent.stroke_width;
    }
    /**
     * @summary 縁を描画するか
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "enable_stroke",
    get: function get() {
      var props = this._props;
      var parent = this._owner._text_parent_props;
      return props.enable_stroke || parent.enable_stroke;
    }
    /**
     * @summary 背景色
     * @type {mapray.Color}
     * @readonly
     */

  }, {
    key: "bg_color",
    get: function get() {
      var props = this._props;
      var parent = this._owner._text_parent_props;
      return props.bg_color || parent.bg_color;
    }
    /**
     * @summary 背景描画するか
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "enable_background",
    get: function get() {
      // Enable or Disable background can be set by parent.
      var parent = this._owner._text_parent_props;
      return parent.enable_bg;
    }
  }]);

  return Entry;
}();
/**
 * @summary テキスト画像を Canvas 上にレイアウト
 *
 * @memberof mapray.TextEntity
 * @private
 */


var Layout =
/*#__PURE__*/
function () {
  /**
   * @desc
   * 入力:
   *   owner._glenv
   *   owner.entity._entries
   *   owner._transform
   *
   * @param {PrimitiveProducer} owner       所有者
   * @param {number[]}          gocs_array  GOCS 平坦化配列
   */
  function Layout(owner, gocs_array) {
    _classCallCheck(this, Layout);

    this._owner = owner;
    this._items = this._createItemList();
    this._is_valid = true;

    var row_layouts = this._createRowLayouts();

    if (row_layouts.length == 0) {
      // 有効なテキストが1つも無い
      this._is_valid = false;
      return;
    } // アイテムの配置の設定とキャンバスサイズの決定


    var size = this._setupLocation(row_layouts);

    if (this._isSimpleTextWithAllItems(this._items)) {
      this._texture = this._createTextureForSimple(size.width, size.height);
      this._vertices = this._createVerticesForSimple(size.width, size.height, gocs_array);
    } else {
      this._texture = this._createTexture(size.width, size.height);
      this._vertices = this._createVertices(size.width, size.height, gocs_array);
    }

    this._indices = this._createIndices();
  }
  /**
   * @summary 有効なオブジェクトか?
   * @desc
   * <p>無効のとき、他のメソッドは呼び出せない。</p>
   * @return {boolean}  有効のとき true, 無効のとき false
   */


  _createClass(Layout, [{
    key: "isValid",
    value: function isValid() {
      return this._is_valid;
    }
    /**
     * @summary テクスチャ
     * @type {mapray.Texture}
     * @readonly
     */

  }, {
    key: "_createItemList",

    /**
     * @summary レイアウトアイテムのリストを生成
     * @return {array.<mapray.TextEntity.LItem>}
     * @private
     */
    value: function _createItemList() {
      var context = Dom.createCanvasContext(1, 1);
      var items = [];
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = this._owner.entity._entries[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var entry = _step3.value;
          items.push(new LItem(this, entry, context));
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }

      return items;
    }
    /**
     * @summary RowLayout のリストを生成
     * @return {array.<mapray.TextEntity.RowLayout>}
     * @private
     */

  }, {
    key: "_createRowLayouts",
    value: function _createRowLayouts() {
      // アイテムリストの複製
      var items = [].concat(this._items); // RowLayout 内であまり高さに差が出ないように、アイテムリストを高さで整列

      items.sort(function (a, b) {
        return a.height_pixel - b.height_pixel;
      }); // リストを生成

      var row_layouts = [];

      while (items.length > 0) {
        var row_layout = new RowLayout(items);

        if (row_layout.isValid()) {
          row_layouts.push(row_layout);
        }
      }

      return row_layouts;
    }
    /**
     * @summary テクスチャを生成
     * @param  {number} width    横幅
     * @param  {number} height   高さ
     * @return {mapray.Texture}  テキストテクスチャ
     * @private
     */

  }, {
    key: "_createTexture",
    value: function _createTexture(width, height) {
      var context = Dom.createCanvasContext(width, height);
      context.textAlign = "left";
      context.textBaseline = "alphabetic";
      context.fillStyle = "rgba( 255, 255, 255, 1.0 )";
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;

        if (item._entry.enable_background) {
          item.drawRect(context);
        }

        item.drawText(context);

        if (item._entry.enable_stroke) {
          item.drawStrokeText(context);
        }
      }

      var glenv = this._owner._glenv;
      var opts = {
        usage: Texture.Usage.TEXT
      };
      return new Texture(glenv, context.canvas, opts);
    }
    /**
     * @summary 頂点配列を生成
     *
     * @param  {number}   width       横幅
     * @param  {number}   height      高さ
     * @param  {number[]} gocs_array  GOCS 平坦化配列
     * @return {array.<number>}  頂点配列 [左下0, 右下0, 左上0, 右上0, ...]
     *
     * @private
     */

  }, {
    key: "_createVertices",
    value: function _createVertices(width, height, gocs_array) {
      var vertices = []; // テキスト集合の原点 (GOCS)

      var transform = this._owner._transform;
      var xo = transform[12];
      var yo = transform[13];
      var zo = transform[14];
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue; // テキストの位置 (モデル座標系)

        var ibase = 3 * i;
        var xm = gocs_array[ibase] - xo;
        var ym = gocs_array[ibase + 1] - yo;
        var zm = gocs_array[ibase + 2] - zo; // ベースライン左端 (キャンバス座標系)

        var xc = item.pos_x;
        var yc = item.pos_y;
        var upper = item.upper;
        var lower = item.lower;
        var xsize = item.width;
        var xn = 1 / width;
        var yn = 1 / height; // 左下

        vertices.push(xm, ym, zm); // a_position

        vertices.push(-xsize / 2, -lower); // a_offset

        vertices.push(xc * xn, 1 - (yc + lower) * yn); // a_texcoord
        // 右下

        vertices.push(xm, ym, zm); // a_position

        vertices.push(xsize / 2, -lower); // a_offset

        vertices.push((xc + xsize) * xn, 1 - (yc + lower) * yn); // a_texcoord
        // 左上

        vertices.push(xm, ym, zm); // a_position

        vertices.push(-xsize / 2, upper); // a_offset

        vertices.push(xc * xn, 1 - (yc - upper) * yn); // a_texcoord
        // 右上

        vertices.push(xm, ym, zm); // a_position

        vertices.push(xsize / 2, upper); // a_offset

        vertices.push((xc + xsize) * xn, 1 - (yc - upper) * yn); // a_texcoord
      }

      return vertices;
    }
    /**
     * @summary 単純テキスト用テクスチャを生成
     * @param  {number} width    横幅
     * @param  {number} height   高さ
     * @return {mapray.Texture}  テキストテクスチャ
     * @private
     */

  }, {
    key: "_createTextureForSimple",
    value: function _createTextureForSimple(width, height) {
      var context = Dom.createCanvasContext(width, height);
      context.textAlign = "left";
      context.textBaseline = "alphabetic";
      context.fillStyle = "rgba( 255, 255, 255, 1.0 )";
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;
        item.drawText(context);
      }

      var glenv = this._owner._glenv;
      var opts = {
        usage: Texture.Usage.SIMPLETEXT
      };
      return new Texture(glenv, context.canvas, opts);
    }
    /**
     * @summary 単純テキスト用頂点配列を生成
     *
     * @param  {number}   width       横幅
     * @param  {number}   height      高さ
     * @param  {number[]} gocs_array  GOCS 平坦化配列
     * @return {array.<number>}  頂点配列 [左下0, 右下0, 左上0, 右上0, ...]
     *
     * @private
     */

  }, {
    key: "_createVerticesForSimple",
    value: function _createVerticesForSimple(width, height, gocs_array) {
      var vertices = []; // テキスト集合の原点 (GOCS)

      var transform = this._owner._transform;
      var xo = transform[12];
      var yo = transform[13];
      var zo = transform[14];
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;
        var entry = item.entry; // テキストの色

        var color = entry.color.toVector4(); // テキストの位置 (モデル座標系)

        var ibase = 3 * i;
        var xm = gocs_array[ibase] - xo;
        var ym = gocs_array[ibase + 1] - yo;
        var zm = gocs_array[ibase + 2] - zo; // ベースライン左端 (キャンバス座標系)

        var xc = item.pos_x;
        var yc = item.pos_y;
        var upper = item.upper;
        var lower = item.lower;
        var xsize = item.width;
        var xn = 1 / width;
        var yn = 1 / height; // 左下

        vertices.push(xm, ym, zm); // a_position

        vertices.push(-xsize / 2, -lower); // a_offset

        vertices.push(xc * xn, 1 - (yc + lower) * yn); // a_texcoord

        vertices.push(color[0], color[1], color[2], 1); // a_color
        // 右下

        vertices.push(xm, ym, zm); // a_position

        vertices.push(xsize / 2, -lower); // a_offset

        vertices.push((xc + xsize) * xn, 1 - (yc + lower) * yn); // a_texcoord

        vertices.push(color[0], color[1], color[2], 1); // a_color
        // 左上

        vertices.push(xm, ym, zm); // a_position

        vertices.push(-xsize / 2, upper); // a_offset

        vertices.push(xc * xn, 1 - (yc - upper) * yn); // a_texcoord

        vertices.push(color[0], color[1], color[2], 1); // a_color
        // 右上

        vertices.push(xm, ym, zm); // a_position

        vertices.push(xsize / 2, upper); // a_offset

        vertices.push((xc + xsize) * xn, 1 - (yc - upper) * yn); // a_texcoord

        vertices.push(color[0], color[1], color[2], 1); // a_color
      }

      return vertices;
    }
    /**
     * @summary インデックス配列を生成
     * @return {array.<number>}  インデックス配列 []
     * @private
     */

  }, {
    key: "_createIndices",
    value: function _createIndices() {
      var indices = [];
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;
        var b = 4 * i;
        indices.push(b, b + 1, b + 2, b + 2, b + 1, b + 3);
      }

      return indices;
    }
    /**
     * @summary アイテムの配置を設定
     * @param  {array.<mapray.TextEntity.RowLayout>} row_layouts
     * @return {object}                              キャンバスサイズ
     * @private
     */

  }, {
    key: "_setupLocation",
    value: function _setupLocation(row_layouts) {
      var width = 0;
      var height = 0;
      height += TextEntity.SAFETY_PIXEL_MARGIN;

      for (var i = 0; i < row_layouts.length; ++i) {
        var row_layout = row_layouts[i];
        row_layout.locate(height);
        width = Math.max(row_layout.width_assumed, width);
        height += row_layout.height_pixel + TextEntity.SAFETY_PIXEL_MARGIN;
      }

      return {
        width: width,
        height: height
      };
    }
    /**
     * @summary シンプルテキストモードかどうか
     * @param  {mapray.TextEntity.LItem} item
     * @return {boolean}                 シンプルテキストモードならtrue
     * @private
     */

  }, {
    key: "_isSimpleText",
    value: function _isSimpleText(item) {
      if (item._entry.enable_background || item._entry.enable_stroke) {
        return false;
      }

      return true;
    }
    /**
     * @summary シンプルテキストモードかどうか
     * @param  {array.<mapray.TextEntity.LItem>} items
     * @return {boolean}                 シンプルテキストモードならtrue
     * @private
     */

  }, {
    key: "_isSimpleTextWithAllItems",
    value: function _isSimpleTextWithAllItems(items) {
      var enable = true;
      var i = 0;

      while (enable && items.length > i) {
        var item = items[i];
        enable = this._isSimpleText(item);
        i++;
      }

      return enable;
    }
  }, {
    key: "texture",
    get: function get() {
      return this._texture;
    }
    /**
     * @summary 頂点配列
     * @desc
     * 条件:
     *   this._entries.length > 0
     * 入力:
     *   this._entries
     *   this._transform
     * @type {Float32Array}
     * @readonly
     */

  }, {
    key: "vertices",
    get: function get() {
      return this._vertices;
    }
    /**
     * @summary インデックス配列
     * @type {Uint32Array}
     * @readonly
     */

  }, {
    key: "indices",
    get: function get() {
      return this._indices;
    }
  }]);

  return Layout;
}();
/**
 * @summary レイアウト対象
 * @memberof mapray.TextEntity
 * @private
 */


var LItem =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.TextEntity.Layout} layout   所有者
   * @param {mapray.TextEntity.Entry}  entry    TextEntity エントリ
   * @param {CanvasRenderingContext2D} context  測定用コンテキスト
   */
  function LItem(layout, entry, context) {
    _classCallCheck(this, LItem);

    this._entry = entry; // テキストの基点

    this._pos_x = 0; // 左端

    this._pos_y = 0; // ベースライン位置
    // テキストの横幅

    context.font = entry.font;
    this._width = context.measureText(entry.text).width; // テキストの上下範囲

    this._upper = entry.size * TextEntity.DEFAULT_TEXT_UPPER;
    this._lower = entry.size * TextEntity.DEFAULT_TEXT_LOWER;
    this._is_canceled = false;
  }
  /**
   * @type {mapray.TextEntity.Entry}
   * @readonly
   */


  _createClass(LItem, [{
    key: "cancel",

    /**
     * @summary 取り消し状態に移行
     */
    value: function cancel() {
      this._is_canceled = true;
    }
    /**
     * @summary 配置を決定
     * @param {number} x  テキスト矩形左辺の X 座標 (キャンバス座標系)
     * @param {number} y  テキスト矩形上辺の Y 座標 (キャンバス座標系)
     */

  }, {
    key: "locate",
    value: function locate(x, y) {
      this._pos_x = x;
      this._pos_y = y + Math.ceil(this._upper);
    }
    /**
     * @summary テキストだけを描画 (stokeやfillRectとは組み合わせ不可)
     * @desc
     * <p>context は以下のように設定していること。</p>
     * <pre>
     *   context.textAlign    = "left";
     *   context.textBaseline = "alphabetic";
     *   context.fillStyle    = "rgba( 255, 255, 255, 1.0 )";
     * </pre>
     * @param {CanvasRenderingContext2D} context  描画先コンテキスト
     */

  }, {
    key: "drawTextOnly",
    value: function drawTextOnly(context) {
      var entry = this._entry;
      context.font = entry.font;
      context.fillText(entry.text, this._pos_x, this._pos_y);
    }
    /**
     * @summary テキストを描画
     * @desc
     * <p>context は以下のように設定していること。</p>
     * <pre>
     *   context.textAlign    = "left";
     *   context.textBaseline = "alphabetic";
     *   context.fillStyle    = "rgba( 255, 255, 255, 1.0 )";
     * </pre>
     * @param {CanvasRenderingContext2D} context  描画先コンテキスト
     */

  }, {
    key: "drawText",
    value: function drawText(context) {
      var entry = this._entry;
      context.font = entry.font;
      context.fillStyle = entry.color.toRGBString();
      context.fillText(entry.text, this._pos_x, this._pos_y);
    }
    /**
     * @summary テキストの淵を描画
     * @desc
     * <p>drawTextOnlyとは組み合わせ不可</p>
      * @param {CanvasRenderingContext2D} context  描画先コンテキスト
     */

  }, {
    key: "drawStrokeText",
    value: function drawStrokeText(context) {
      var entry = this._entry;
      context.strokeStyle = entry.stroke_color.toRGBString();
      context.lineWidth = entry.stroke_width;
      context.lineJoin = "round";
      context.strokeText(entry.text, this._pos_x, this._pos_y);
    }
    /**
     * @summary テキストの背景を描画
     * @desc
     * <p>drawTextOnlyとは組み合わせ不可</p>
      * @param {CanvasRenderingContext2D} context  描画先コンテキスト
     */

  }, {
    key: "drawRect",
    value: function drawRect(context) {
      var entry = this._entry;
      context.fillStyle = entry.bg_color.toRGBString();
      context.fillRect(this._pos_x - TextEntity.SAFETY_PIXEL_MARGIN, this._pos_y - this._upper - TextEntity.SAFETY_PIXEL_MARGIN, this.width_pixel + TextEntity.SAFETY_PIXEL_MARGIN, this.height_pixel + TextEntity.SAFETY_PIXEL_MARGIN);
    }
  }, {
    key: "entry",
    get: function get() {
      return this._entry;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "pos_x",
    get: function get() {
      return this._pos_x;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "pos_y",
    get: function get() {
      return this._pos_y;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "width",
    get: function get() {
      return this._width;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "upper",
    get: function get() {
      return this._upper;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "lower",
    get: function get() {
      return this._lower;
    }
    /**
     * キャンバス上でのテキストの横画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "width_pixel",
    get: function get() {
      return Math.ceil(this._width);
    }
    /**
     * キャンバス上でのテキストの縦画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_pixel",
    get: function get() {
      return Math.ceil(this._upper) + Math.ceil(this._lower);
    }
    /**
     * 取り消し状態か?
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "is_canceled",
    get: function get() {
      return this._is_canceled;
    }
  }]);

  return LItem;
}();
/**
 * @summary 水平レイアウト
 * @memberof mapray.TextEntity
 * @private
 */


var RowLayout =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>レイアウトされた、またはレイアウトに失敗したアイテムは src_items から削除される。</p>
   * <p>レイアウトに失敗したアイテムは取り消し (is_canceled) になる。</p>
   * @param {array.<mapray.TextEntity.LItem>} src_items  アイテムリスト
   */
  function RowLayout(src_items) {
    _classCallCheck(this, RowLayout);

    var width_assumed_total = 0;
    var height_pixel_max = 0;
    var row_items = [];
    width_assumed_total += TextEntity.SAFETY_PIXEL_MARGIN; // 左マージン

    while (src_items.length > 0) {
      var item = src_items.shift();
      var width_assumed = item.width_pixel + TextEntity.SAFETY_PIXEL_MARGIN; // テキスト幅 + 右マージン

      if (width_assumed_total + width_assumed <= TextEntity.MAX_IMAGE_WIDTH) {
        // 行にアイテムを追加
        row_items.push(item);
        width_assumed_total += width_assumed;
        height_pixel_max = Math.max(item.height_pixel, height_pixel_max);
      } else {
        if (row_items.length == 0) {
          // テキストが長すぎて表示できない
          item.cancel();
        } else {
          // 次の行になるため差し戻して終了
          src_items.unshift(item);
          break;
        }
      }
    }

    this._items = row_items;
    this._width_assumed = width_assumed_total;
    this._height_pixel = height_pixel_max;
  }
  /**
   * @summary 有効なオブジェクトか?
   * @desc
   * <p>無効のとき、他のメソッドは呼び出せない。</p>
   * @return {boolean}  有効のとき true, 無効のとき false
   */


  _createClass(RowLayout, [{
    key: "isValid",
    value: function isValid() {
      return this._items.length > 0;
    }
    /**
     *
     * @type {array.<mapray.TextEntity.LItem>}
     * @readonly
     */

  }, {
    key: "locate",

    /**
     * @summary レイアウトの配置を決定
     * @param {number} y  テキスト矩形上辺の Y 座標 (キャンバス座標系)
     */
    value: function locate(y) {
      var items = this._items;
      var x = 0;
      x += TextEntity.SAFETY_PIXEL_MARGIN; // 左マージン

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        item.locate(x, y);
        x += item.width_pixel + TextEntity.SAFETY_PIXEL_MARGIN; // テキスト幅 + 右マージン
      }
    }
  }, {
    key: "items",
    get: function get() {
      return this._items;
    }
    /**
     * キャンバス上での行の横占有画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "width_assumed",
    get: function get() {
      return this._width_assumed;
    }
    /**
     * キャンバス上での行の縦画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_pixel",
    get: function get() {
      return this._height_pixel;
    }
  }]);

  return RowLayout;
}();

/**
 * @summary モデルエンティティ
 * @memberof mapray
 * @extends mapray.Entity
 */

var ModelEntity =
/*#__PURE__*/
function (_Entity) {
  _inherits(ModelEntity, _Entity);

  /**
   * @param {mapray.Scene} scene        所属可能シーン
   * @param {object}       [opts]       オプション集合
   * @param {object}       [opts.json]  生成情報
   * @param {object}       [opts.refs]  参照辞書
   *
   * @throws Error  ModelContainer からモデルが見つからなかった
   */
  function ModelEntity(scene, opts) {
    var _this;

    _classCallCheck(this, ModelEntity);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(ModelEntity).call(this, scene, opts));
    _this._position = new GeoPoint(0, 0, 0);
    _this._rotation = GeoMath.setIdentity(GeoMath.createMatrix());
    _this._scale = GeoMath.createVector3([1, 1, 1]);
    _this._primitive_producer = new PrimitiveProducer$3(_assertThisInitialized(_this));

    _this._setupAnimationBindingBlock();

    if (opts && opts.json) {
      var json = opts.json;
      var refs = opts.refs || {};

      _this._setupTransform(json);

      _this._setupModelObject(json, refs);
    }

    return _this;
  }
  /**
   * @override
   */


  _createClass(ModelEntity, [{
    key: "getPrimitiveProducer",
    value: function getPrimitiveProducer() {
      return this._primitive_producer;
    }
    /**
     * @override
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode(prev_mode) {
      this._primitive_producer.onChangeAltitudeMode();
    }
    /**
     * アニメーションの BindingBlock を初期化
     *
     * @private
     */

  }, {
    key: "_setupAnimationBindingBlock",
    value: function _setupAnimationBindingBlock() {
      var _this2 = this;

      var block = this.animation; // 実体は EasyBindingBlock

      var number = Type.find("number");
      var vector3 = Type.find("vector3");
      var matrix = Type.find("matrix"); // パラメータ名: position
      // パラメータ型: vector3
      //   ベクトルの要素が longitude, latitude, altitude 順であると解釈

      var position_temp = new GeoPoint();
      block.addEntry("position", [vector3], null, function (value) {
        position_temp.setFromArray(value); // Vector3 -> GeoPoint

        _this2.setPosition(position_temp);
      }); // パラメータ名: orientation
      // パラメータ型: matrix | vector3
      //   型が matrix のとき MLOCS での回転行列
      //   型が vector3 のとき、要素が heading, tilt, roll 順であると解釈

      var orientation_temp = new Orientation();
      var orientation_type;

      var orientation_tsolver = function orientation_tsolver(curve) {
        orientation_type = AnimUtil.findFirstTypeSupported(curve, [matrix, vector3]);
        return orientation_type;
      };

      block.addEntry("orientation", [matrix, vector3], orientation_tsolver, function (value) {
        if (orientation_type === matrix) {
          _this2._setRotation(value);
        } else {
          // orientation_type === vector3
          orientation_temp.heading = value[0];
          orientation_temp.tilt = value[1];
          orientation_temp.roll = value[2];

          _this2.setOrientation(orientation_temp);
        }
      }); // パラメータ名: scale
      // パラメータ型: vector3 | number
      //   型が vector3 のときは XYZ 別の倍率
      //   型が number のときは均等倍率

      var scale_temp = GeoMath.createVector3();
      var scale_type;

      var scale_tsolver = function scale_tsolver(curve) {
        scale_type = AnimUtil.findFirstTypeSupported(curve, [vector3, number]);
        return scale_type;
      };

      block.addEntry("scale", [vector3, number], scale_tsolver, function (value) {
        if (scale_type === vector3) {
          _this2.setScale(value);
        } else {
          // scale_type === number
          scale_temp[0] = value;
          scale_temp[1] = value;
          scale_temp[2] = value;

          _this2.setScale(scale_temp);
        }
      });
    }
    /**
     * @summary position, orientation, scale を設定
     *
     * @param {object} json  生成情報
     *
     * @private
     */

  }, {
    key: "_setupTransform",
    value: function _setupTransform(json) {
      var tr = json.transform; // <TRANSFORM>
      // position

      this.setPosition(new GeoPoint().setFromArray(tr.position)); // heading, tilt, roll

      this.setOrientation(new Orientation(tr.heading, tr.tilt, tr.roll)); // scale

      var scale = tr.scale !== undefined ? tr.scale : [1, 1, 1]; // <PARAM-SCALE3>

      if (typeof scale == 'number') {
        // スケールをベクトルに正規化
        scale = [scale, scale, scale];
      }

      this.setScale(scale);
    }
    /**
     * @summary モデルを設定
     *
     * @param {object} json  生成情報
     * @param {object} refs  参照辞書
     *
     * @throws Error
     *
     * @private
     */

  }, {
    key: "_setupModelObject",
    value: function _setupModelObject(json, refs) {
      var container = refs[json.ref_model];

      this._primitive_producer.setModelObject(container, json.index);
    }
    /**
     * @summary モデル原点位置を設定
     *
     * @param {mapray.GeoPoint} value  モデル原点の位置
     */

  }, {
    key: "setPosition",
    value: function setPosition(value) {
      var op = this._position; // 変更前の位置

      if (value.longitude != op.longitude || value.latitude != op.latitude || value.altitude != op.altitude) {
        // 位置が変更された
        this._position.assign(value);

        this._primitive_producer.onChangePosition();
      }
    }
    /**
     * @summary モデルの向きを設定
     *
     * @param {mapray.Orientation} value  モデルの向き
     */

  }, {
    key: "setOrientation",
    value: function setOrientation(value) {
      value.getTransformMatrix(sameScaleVector3, this._rotation);
    }
    /**
     * @summary モデルのスケールを設定
     *
     * @param {mapray.Vector3} value  モデルのスケール
     */

  }, {
    key: "setScale",
    value: function setScale(value) {
      GeoMath.copyVector3(value, this._scale);
    }
    /**
     * @summary モデルの回転を設定
     *
     * @desc
     * <p>今のところアニメーション専用</p>
     *
     * @param {mapray.Matrix} value  回転行列
     *
     * @private
     */

  }, {
    key: "_setRotation",
    value: function _setRotation(value) {
      GeoMath.copyMatrix(value, this._rotation);
    }
    /**
     * @summary モデル位置の標高を取得
     *
     * @return {number} 標高値
     *
     * @private
     */

  }, {
    key: "_getElevation",
    value: function _getElevation() {
      return this.scene.viewer.getExistingElevation(this._position);
    }
  }]);

  return ModelEntity;
}(Entity);
/**
 * @summary ModelEntity の PrimitiveProducer
 *
 * @private
 */


var PrimitiveProducer$3 =
/*#__PURE__*/
function (_Entity$PrimitiveProd) {
  _inherits(PrimitiveProducer, _Entity$PrimitiveProd);

  /**
   * @param {mapray.ModelEntity} entity
   */
  function PrimitiveProducer(entity) {
    var _this3;

    _classCallCheck(this, PrimitiveProducer);

    _this3 = _possibleConstructorReturn(this, _getPrototypeOf(PrimitiveProducer).call(this, entity));
    _this3._primitives = []; // プリミティブ配列

    _this3._ptoe_array = []; // 各プリミティブ座標系からエンティティ座標系への変換行列

    _this3._abs_position = null; // 絶対高度に変換した位置のキャッシュ (null なら無効)

    return _this3;
  }
  /**
   * @summary モデルを設定
   *
   * @param {mapray.ModelContainer} container  モデルコンテナ
   * @param {number|string}         [id]       モデル ID
   *
   * @throws Error
   */


  _createClass(PrimitiveProducer, [{
    key: "setModelObject",
    value: function setModelObject(container, index) {
      var primitives = container.createPrimitives(index);

      if (primitives) {
        this._primitives = primitives;
        this._ptoe_array = primitives.map(function (prim) {
          return GeoMath.createMatrix(prim.transform);
        });
      } else {
        // ModelContainer からモデルが見つからなかった
        throw new Error("model is not found in ModelContainer");
      }
    }
    /**
     * @override
     */

  }, {
    key: "createRegions",
    value: function createRegions() {
      var region = new EntityRegion();
      region.addPoint(this.entity._position);
      return [region];
    }
    /**
     * @override
     */

  }, {
    key: "onChangeElevation",
    value: function onChangeElevation(regions) {
      this._abs_position = null; // キャッシュを無効化
    }
    /**
     * @override
     */

  }, {
    key: "getPrimitives",
    value: function getPrimitives(stage) {
      var entity = this.entity; // this._abs_position を更新

      this._updateAbsPosition();

      var mlocs_to_gocs = this._abs_position.getMlocsToGocsMatrix(GeoMath.createMatrix());

      var entity_to_mlocs = mul_RS(entity._rotation, entity._scale, GeoMath.createMatrix());
      var entity_to_gocs = GeoMath.mul_AA(mlocs_to_gocs, entity_to_mlocs, GeoMath.createMatrix()); // Primitive#transform を設定

      var primitives = this._primitives;
      var ptoe_array = this._ptoe_array;

      for (var i = 0; i < primitives.length; ++i) {
        var prim = primitives[i];
        var ptoe = ptoe_array[i]; // prim.transform = entity_to_gocs * ptoe

        GeoMath.mul_AA(entity_to_gocs, ptoe, prim.transform);
      }

      return this._primitives;
    }
    /**
     * @summary 高度モードが変更されたときに呼び出される
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode() {
      this._abs_position = null; // キャッシュを無効化
    }
    /**
     * @summary 位置が変更されたときに呼び出される
     */

  }, {
    key: "onChangePosition",
    value: function onChangePosition() {
      this.needToCreateRegions();
      this._abs_position = null;
    }
    /**
     * @summary 絶対高度位置を更新
     *
     * 出力: this._abs_position
     *
     * @private
     */

  }, {
    key: "_updateAbsPosition",
    value: function _updateAbsPosition() {
      if (this._abs_position !== null) {
        // キャッシュされている
        return;
      }

      var entity = this.entity;
      this._abs_position = entity._position.clone();

      switch (entity.altitude_mode) {
        case AltitudeMode.RELATIVE:
          this._abs_position.altitude += entity._getElevation();
          break;

        case AltitudeMode.CLAMP:
          this._abs_position.altitude = entity._getElevation();
          break;
      }
    }
  }]);

  return PrimitiveProducer;
}(Entity.PrimitiveProducer); // 等倍を表すベクトル


var sameScaleVector3 = GeoMath.createVector3([1, 1, 1]);
/**
 * @summary 回転行列 * 倍率
 *
 * @param {mapray.Matrix}  rmat  回転行列
 * @param {mapray.Vector3} svec  倍率ベクトル
 * @param {mapray.Matrix}  dst   結果
 *
 * @return {mapray.Matrix}  dst
 *
 * @private
 */

function mul_RS(rmat, svec, dst) {
  var sx = svec[0];
  var sy = svec[1];
  var sz = svec[2];
  dst[0] = rmat[0] * sx;
  dst[1] = rmat[1] * sx;
  dst[2] = rmat[2] * sx;
  dst[3] = 0;
  dst[4] = rmat[4] * sy;
  dst[5] = rmat[5] * sy;
  dst[6] = rmat[6] * sy;
  dst[7] = 0;
  dst[8] = rmat[8] * sz;
  dst[9] = rmat[9] * sz;
  dst[10] = rmat[10] * sz;
  dst[11] = 0;
  dst[12] = 0;
  dst[13] = 0;
  dst[14] = 0;
  dst[15] = 1;
  return dst;
}

var exportTypedArrayStaticMethod$1 = arrayBufferViewCore.exportTypedArrayStaticMethod; // `%TypedArray%.from` method
// https://tc39.github.io/ecma262/#sec-%typedarray%.from

exportTypedArrayStaticMethod$1('from', typedArrayFrom, typedArrayConstructorsRequireWrappers);

var polygon_vs_code = "/**\n * 多角形の頂点シェーダ\n */\n\nattribute vec4 a_position;   // 位置 (モデル座標系)\nattribute vec3 a_normal;     // 法線 (モデル座標系)\n\nuniform mat4 u_obj_to_clip;  // モデル座標系からクリップ座標系への変換\nuniform mat4 u_obj_to_view;  // モデル座標系から視点座標系への変換\nuniform bool u_lighting;     // 照光の有無\nuniform vec3 u_light_dir;    // ライト逆方向 (視点座標系) と強さ\n\nvarying vec3 v_lit_diffuse;  // 拡散光ライト\n\n\nvoid\nmain()\n{\n    gl_Position = u_obj_to_clip * a_position;\n\n    if ( u_lighting ) {\n        // 法線 (視点座標系)\n        vec3 normal = normalize( vec3( u_obj_to_view * vec4( a_normal, 0.0 ) ) );\n\n        // 拡散光の強さ\n        v_lit_diffuse = vec3( dot( normal, u_light_dir ) );\n    }\n    else {\n        // 照光なしのときは 1 に固定\n        v_lit_diffuse = vec3( 1 );\n    }\n}\n";

var polygon_fs_code = "/**\n * 多角形のフラグメントシェーダ\n */\n\nprecision mediump float;\n\nvarying vec3 v_lit_diffuse;  // 拡散光ライト\n\nuniform vec4 u_color;        // 基本色と不透明度\n\n\nvoid\nmain()\n{\n    vec3  color   = u_color.xyz * v_lit_diffuse;\n    float opacity = u_color.w;\n\n    gl_FragColor = vec4( color * opacity, opacity );\n}\n";

/**
 * @summary 多角形分専用マテリアル
 * @memberof mapray
 * @extends mapray.EntityMaterial
 * @private
 */

var PolygonMaterial =
/*#__PURE__*/
function (_EntityMaterial) {
  _inherits(PolygonMaterial, _EntityMaterial);

  /**
   * @param {mapray.GLEnv} glenv
   */
  function PolygonMaterial(glenv) {
    _classCallCheck(this, PolygonMaterial);

    return _possibleConstructorReturn(this, _getPrototypeOf(PolygonMaterial).call(this, glenv, polygon_vs_code, polygon_fs_code));
  }
  /**
   * @override
   */


  _createClass(PolygonMaterial, [{
    key: "isTranslucent",
    value: function isTranslucent(stage, primitive) {
      var props = primitive.properties;
      var opacity = props.opacity !== undefined ? props.opacity : PolygonMaterial.DEFAULT_OPACITY;
      return opacity < 1.0;
    }
    /**
     * @override
     */

  }, {
    key: "setParameters",
    value: function setParameters(stage, primitive) {
      var props = primitive.properties; // 変換行列
      // u_obj_to_clip, u_obj_to_view

      this.setObjToClip(stage, primitive);
      this.setObjToView(stage, primitive); // 基本色
      // vec4 u_color

      var param_color = props.color !== undefined ? props.color : PolygonMaterial.DEFAULT_COLOR;
      var param_opacity = props.opacity !== undefined ? props.opacity : PolygonMaterial.DEFAULT_OPACITY;
      var color = PolygonMaterial._color;
      GeoMath.copyVector3(param_color, color);
      color[3] = param_opacity;
      this.setVector4("u_color", color); // 照光の有無
      // bool u_lighting

      this.setBoolean("u_lighting", props.lighting); // ライト逆方向 (視点座標系) と強さ
      // vec3 u_light_dir

      this.setVector3("u_light_dir", [0, 0, 1]);
    }
  }]);

  return PolygonMaterial;
}(EntityMaterial); // クラス定数の定義


{
  PolygonMaterial.DEFAULT_COLOR = GeoMath.createVector3f([1.0, 1.0, 1.0]);
  PolygonMaterial.DEFAULT_OPACITY = 1.0; // 計算用一時領域

  PolygonMaterial._color = GeoMath.createVector4f();
}

/**
 * @summary 多角形を三角形に分割
 *
 * @classdesc
 * <p>入力した多角形を三角形に分割して結果を返す。</p>
 * <p>構築子と addBoundary() でで多角形を入力して、run() メソッドでそれを三角形に分割して返す。</p>
 *
 * <p>実装のアルゴリズムと用語は基本的にコンピュータ・ジオメトリ (近代科学社) の第3章「多角形の三角形分割」を参考にしている。</p>
 *
 * @memberof mapray
 * @private
 */
var Triangulator =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>points は多角形の頂点の xy 座標の配列である。</p>
   * <p>座標系は x 軸が右方向、y 軸が上方向を想定している。</p>
   *
   * @param {number[]} points  頂点配列
   * @param {number}   offset  最初の頂点のインデックス (>= 0)
   * @param {number}   stride  頂点の間隔 (>= 2)
   * @param {number}   count   頂点数
   */
  function Triangulator(points, offset, stride, count) {
    _classCallCheck(this, Triangulator);

    this._points = new Float64Array(2 * count);
    this._polygons = new Set(); // 頂点座標を複製

    var src = offset;
    var dst = 0;

    for (var i = 0; i < count; ++i) {
      this._points[dst] = points[src];
      this._points[dst + 1] = points[src + 1];
      src += stride;
      dst += 2;
    }
  }
  /**
   * @summary 多角形の境界を追加
   *
   * @desc
   * <p>インデックスの順序は外側境界のときは反時計回り、内側境界のときは時計回りでなければならない。</p>
   * <p>内側境界を追加するときは、その外側の境界も追加しなければならない。追加の順序はどちらが先でも良い。</p>
   * <p>境界内または複数の境界間でエッジが交差してはならない。同じように頂点が他の頂点またはエッジの上に乗ってはならない。</p>
   *
   * @param {number[]} indices  多角形の境界を表す 3 個以上の頂点インデックス
   */


  _createClass(Triangulator, [{
    key: "addBoundary",
    value: function addBoundary(indices) {
      this._polygons.add(Polygon.create(this._points, indices));
    }
    /**
     * @summary 多角形を三角形に分割して結果を取得
     *
     * @desc
     * <p>各々の三角形は 3 つの整数インデックスが反時計回りに並べて表現される。
     * すべての三角形に対して、その表現を連結した配列を出力する。</p>
     * <p>インデックスは入力頂点の最初の頂点を 0 とする。</p>
     *
     * @throws Error  想定外の多角形
     *
     * @return {Uint32Array}  三角形の頂点インデックスの配列
     */

  }, {
    key: "run",
    value: function run() {
      // 多角形を y 単調多角形に分割
      this._makeYMonotonePolygons();

      var triangles = new Uint32Array(3 * this._numTriangles());
      var offset = 0; // 各 y 単調多角形を三角形に分割

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this._polygons[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var polygon = _step.value;

          var temp = this._makeTriangleArray(polygon);

          triangles.set(temp, offset);
          offset += temp.length;
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
      return triangles;
    }
    /**
     * @summary 三角形の数を取得
     *
     * @return {number} 三角形の数
     *
     * @private
     */

  }, {
    key: "_numTriangles",
    value: function _numTriangles() {
      var count = 0;
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this._polygons[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var polygon = _step2.value;
          count += polygon.numVertices() - 2;
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
      return count;
    }
    /**
     * @summary 多角形を y 単調多角形に分割
     *
     * @desc
     * <p>this._polygons を y 軸単調な部分多角形に分割する。</p>
     *
     * @private
     */

  }, {
    key: "_makeYMonotonePolygons",
    value: function _makeYMonotonePolygons() {
      var vertices = this._getYOrderedVertices();

      var edge_mgr = new EdgeManager();
      var diag_mgr = new DiagonalManager(this._polygons);

      for (var i = 0; i < vertices.length; ++i) {
        var vertex = vertices[i];

        switch (vertex.getVertexType()) {
          case "start":
            {
              var ledge = vertex.getFrontEdge();
              edge_mgr.addEdge(ledge, vertex);
            }
            break;

          case "end":
            {
              var _ledge = vertex.getBackEdge();

              var lhelp = edge_mgr.getHelper(_ledge);

              if (lhelp.getVertexType() == "merge") {
                diag_mgr.addDiagonal(vertex, lhelp);
              }

              edge_mgr.removeEdge(_ledge);
            }
            break;

          case "split":
            {
              var nedge = edge_mgr.findNearestLeftEdge(vertex);
              diag_mgr.addDiagonal(vertex, edge_mgr.getHelper(nedge));
              edge_mgr.setHelper(nedge, vertex);
              var redge = vertex.getFrontEdge();
              edge_mgr.addEdge(redge, vertex);
            }
            break;

          case "merge":
            {
              var _redge = vertex.getBackEdge();

              var rhelp = edge_mgr.getHelper(_redge);

              if (rhelp.getVertexType() == "merge") {
                diag_mgr.addDiagonal(vertex, rhelp);
              }

              edge_mgr.removeEdge(_redge);

              var _nedge = edge_mgr.findNearestLeftEdge(vertex);

              var nhelp = edge_mgr.getHelper(_nedge);

              if (nhelp.getVertexType() == "merge") {
                diag_mgr.addDiagonal(vertex, nhelp);
              }

              edge_mgr.setHelper(_nedge, vertex);
            }
            break;

          default:
            {
              // "regular"
              if (vertex.isRightInner()) {
                // vertex の局所右は多角形の内側
                var uedge = vertex.getBackEdge();
                var uhelp = edge_mgr.getHelper(uedge);

                if (uhelp.getVertexType() == "merge") {
                  diag_mgr.addDiagonal(vertex, uhelp);
                }

                edge_mgr.removeEdge(uedge);
                var dedge = vertex.getFrontEdge();
                edge_mgr.addEdge(dedge, vertex);
              } else {
                // vertex の局所右は多角形の外側
                var _nedge2 = edge_mgr.findNearestLeftEdge(vertex);

                var _nhelp = edge_mgr.getHelper(_nedge2);

                if (_nhelp.getVertexType() == "merge") {
                  diag_mgr.addDiagonal(vertex, _nhelp);
                }

                edge_mgr.setHelper(_nedge2, vertex);
              }
            }
            break;
        }
      } // this._polygons を対角線により分割


      diag_mgr.splitPolygons();
    }
    /**
     * @summary 上から順の頂点配列を取得
     *
     * @return {Vertex[]}  Y 位置降順の頂点配列
     *
     * @private
     */

  }, {
    key: "_getYOrderedVertices",
    value: function _getYOrderedVertices() {
      var vertices = [];
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = this._polygons[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var polygon = _step3.value;
          Array.prototype.push.apply(vertices, polygon.getVertices());
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }
      return vertices.sort(function (a, b) {
        return Vertex.comparePositionY(b, a);
      });
    }
    /**
     * @summary 多角形を三角形に分割
     *
     * @desc
     * <p>y 単調多角形 polygon を 1 つ以上の三角形に分割して返す。</p>
     * <p>1 つの三角形は 3 つの整数インデックスで表現され、三角形数の3倍の長さの整数配列を返す。
     * このインデックスは入力頂点配列に対するもので、3 頂点は反時計回りで格納される。</p>
     *
     * @param {Polygon} polygon  y 単調多角形
     *
     * @return {Uint32Array}  三角形の配列
     *
     * @private
     */

  }, {
    key: "_makeTriangleArray",
    value: function _makeTriangleArray(polygon) {
      var ti = 0;
      var triangles = new Uint32Array(3 * (polygon.numVertices() - 2));
      var stack = new Stack();
      var vi = 0;
      var vertices = polygon.getVertices().sort(function (a, b) {
        return Vertex.comparePositionY(b, a);
      });
      var is_right = vertices[0].prev === vertices[1]; // スタックのチェインが右側か?

      stack.push(vertices[vi++]);
      stack.push(vertices[vi++]);

      while (vi < vertices.length - 1) {
        var _vertex = vertices[vi];
        var is_same_chain = is_right ? _vertex === stack.top.prev : _vertex === stack.top.next;

        if (is_same_chain) {
          var _v = stack.pop();

          while (stack.size > 0) {
            var v3 = stack.top;

            var _ref = is_right ? [_v, v3] : [v3, _v],
                _ref2 = _slicedToArray(_ref, 2),
                a = _ref2[0],
                b = _ref2[1];

            if (Vertex.isCCW(_vertex, a, b)) {
              // 対角線が多角形の内部 -> 三角形を取り出す
              triangles[ti++] = _vertex.id;
              triangles[ti++] = a.id;
              triangles[ti++] = b.id;
              _v = stack.pop();
            } else {
              break;
            }
          }

          stack.push(_v); // 最後にポップした頂点をスタックに戻す

          stack.push(_vertex);
        } else {
          // すべての頂点をスタックからポップ
          var _v2 = stack.pop();

          while (stack.size > 0) {
            // 三角形を取り出す
            var _v3 = stack.pop();

            var _ref3 = is_right ? [_v2, _v3] : [_v3, _v2],
                _ref4 = _slicedToArray(_ref3, 2),
                _a = _ref4[0],
                _b = _ref4[1];

            triangles[ti++] = _vertex.id;
            triangles[ti++] = _a.id;
            triangles[ti++] = _b.id;
            _v2 = _v3;
          }

          stack.push(vertices[vi - 1]);
          stack.push(_vertex); // スタックのチェインが左右反転

          is_right = !is_right;
        }

        ++vi;
      } // スタックの最初と最後の頂点を除いて、最下点から
      // スタック上のすべての頂点への対角線を加える


      var vertex = vertices[vi];
      var v2 = stack.pop();

      while (stack.size > 0) {
        // 三角形を取り出す
        var _v4 = stack.pop();

        var _ref5 = is_right ? [v2, _v4] : [_v4, v2],
            _ref6 = _slicedToArray(_ref5, 2),
            _a2 = _ref6[0],
            _b2 = _ref6[1];

        triangles[ti++] = vertex.id;
        triangles[ti++] = _a2.id;
        triangles[ti++] = _b2.id;
        v2 = _v4;
      }

      return triangles;
    }
  }]);

  return Triangulator;
}();
/**
 * @summary 多角形の頂点
 *
 * @private
 */


var Vertex =
/*#__PURE__*/
function () {
  /**
   * @param {number} id  頂点 ID
   * @param {number} x   x 座標
   * @param {number} y   y 座標
   */
  function Vertex(id, x, y) {
    _classCallCheck(this, Vertex);

    this.id = id;
    this.x = x;
    this.y = y;
    this.polygon = null;
    this.next = null;
    this.prev = null;
  }
  /**
   * @summary 複製
   *
   * @desc
   * <p>ただし this.polygon, this.next, this.prev には null が設定される。</p>
   *
   * @return {Vertex}  this の複製
   */


  _createClass(Vertex, [{
    key: "clone",
    value: function clone() {
      return new Vertex(this.id, this.x, this.y);
    }
    /**
     * @summary 頂点タイプを取得
     *
     * @desc
     * 以下のタイプの何れかを返す。
     * <pre>
     *   "start"    出発点 (□)
     *   "end"      最終点 (■)
     *   "split"    分離点 (▲)
     *   "merge"    統合点 (▼)
     *   "regular"  普通点 (●)
     * </pre>
     *
     * @return {string}  頂点タイプ
     */

  }, {
    key: "getVertexType",
    value: function getVertexType() {
      var prev = this.prev;
      var next = this.next;
      var cprev = Vertex.comparePositionY(prev, this);
      var cnext = Vertex.comparePositionY(next, this);

      if (cprev > 0 && cnext > 0 || cprev < 0 && cnext < 0) {
        // 両側の点が上、または両側の点が下にある
        // r: (prev -> this) ベクトルに対して左 (反時計回り) に直角なベクトル
        var rx = prev.y - this.y;
        var ry = this.x - prev.x; // v: (this -> next) ベクトル

        var vx = next.x - this.x;
        var vy = next.y - this.y; // dot( r, v ): 負数なら内角が 180 度より大きい

        var dot = rx * vx + ry * vy;

        if (cprev > 0 && cnext > 0) {
          // 両側の点が上にある
          return dot < 0 ? "merge" : "end";
        } else {
          // 両側の点が下にある
          return dot < 0 ? "split" : "start";
        }
      } else {
        // 片方の点が上で片方の点が下
        return "regular";
      }
    }
    /**
     * @summary 前方エッジ
     *
     * @return {Vertex}  前方エッジの始点
     */

  }, {
    key: "getFrontEdge",
    value: function getFrontEdge() {
      return this;
    }
    /**
     * @summary 後方エッジ
     *
     * @return {Vertex}  後方エッジの始点
     */

  }, {
    key: "getBackEdge",
    value: function getBackEdge() {
      return this.prev;
    }
    /**
     * @summary 頂点の局所右は多角形の内側か?
     *
     * @desc
     * <p>頂点の局所的な右側は多角形の内側かどうかを返す。</p>
     * <p>this は regular タイプの頂点でなければならない。</p>
     *
     * @return {boolean}  内側のとき true, そうでなければ false
     */

  }, {
    key: "isRightInner",
    value: function isRightInner() {
      // 次の点のほうが下のとき、vertex の右が内側
      return Vertex.comparePositionY(this.next, this) < 0;
    }
    /**
     * @summary 点の高さを比較
     *
     * @desc
     * <p>v1 の点が v2 の点より低いとき -1, v1 の点が v2 の点より高いとき +1, 高さが同じとき 0 を返す。</p>
     *
     * @param {Vertex} v1  頂点 1
     * @param {Vertex} v2  頂点 2
     *
     * @return {number} 比較結果
     */

  }], [{
    key: "comparePositionY",
    value: function comparePositionY(v1, v2) {
      if (v1.y < v2.y || v1.y == v2.y && v1.x > v2.x) {
        // v1 (<) v2
        return -1;
      } else if (v1.y > v2.y || v1.y == v2.y && v1.x < v2.x) {
        // v1 (>) v2
        return 1;
      } else {
        // v1 (=) v2
        return 0;
      }
    }
    /**
     * @summary 3 点は反時計回りか?
     *
     * @param {Vertex} v1  頂点 1
     * @param {Vertex} v2  頂点 2
     * @param {Vertex} v3  頂点 3
     *
     * @return {boolean}  反時計回りのとき true, そうでなければ false
     */

  }, {
    key: "isCCW",
    value: function isCCW(v1, v2, v3) {
      // a = v2 - v1
      var ax = v2.x - v1.x;
      var ay = v2.y - v1.y; // b = v3 - v1

      var bx = v3.x - v1.x;
      var by = v3.y - v1.y; // det( |a b| ) > 0

      return ax * by - ay * bx > 0;
    }
  }]);

  return Vertex;
}();
/**
 * @summary 多角形
 *
 * @private
 */


var Polygon =
/*#__PURE__*/
function () {
  function Polygon() {
    _classCallCheck(this, Polygon);

    this._first = null;
  }
  /**
   * @summary 多角形を生成
   *
   * @desc
   * <p>coords は多角形の頂点の xy 座標の配列である。</p>
   * <p>座標系は x 軸が右方向、y 軸が上方向を想定している。</p>
   * <p>indices での頂点の順序は反時計回りである。<p>
   *
   * @param {number[]} coords   座標配列
   * @param {number[]} indices  多角形の頂点インデックス配列 (indices.length >= 3)
   *
   * @return {Polygon}  Polygon インスタンス
   */


  _createClass(Polygon, [{
    key: "numVertices",

    /**
     * @summary 頂点数を取得
     *
     * @return {number}  頂点数
     */
    value: function numVertices() {
      var count = 0;
      var vertex = this._first;
      ++count;
      var end = this._first;

      for (vertex = vertex.next; vertex !== end; vertex = vertex.next) {
        ++count;
      }

      return count;
    }
    /**
     * @summary すべての頂点の配列を取得
     *
     * @return {Vertex[]}  すべての頂点の配列
     */

  }, {
    key: "getVertices",
    value: function getVertices() {
      var array = [];
      var vertex = this._first;
      array.push(vertex);
      var end = this._first;

      for (vertex = vertex.next; vertex !== end; vertex = vertex.next) {
        array.push(vertex);
      }

      return array;
    }
    /**
     * @summary 頂点を更新
     *
     * @private
     */

  }, {
    key: "_updateVertices",
    value: function _updateVertices() {
      var vertex = this._first;
      vertex.polygon = this;
      var end = this._first;

      for (vertex = vertex.next; vertex !== end; vertex = vertex.next) {
        vertex.polygon = this;
      }
    }
  }], [{
    key: "create",
    value: function create(coords, indices) {
      var poly = new Polygon();
      var id = indices[0];
      var base = 2 * id;
      var vertex = new Vertex(id, coords[base], coords[base + 1]);
      poly._first = vertex;

      for (var i = 1; i < indices.length; ++i) {
        var before = vertex;
        id = indices[i];
        base = 2 * id;
        vertex = new Vertex(id, coords[base], coords[base + 1]);
        before.next = vertex;
        vertex.prev = before;
      } // ここで vertex は最後の頂点


      poly._first.prev = vertex;
      vertex.next = poly._first;

      poly._updateVertices();

      return poly;
    }
    /**
     * @summary 多角形を生成
     *
     * @param {Vertex} first  最初の頂点
     *
     * @return {Polygon}  Polygon インスタンス
     */

  }, {
    key: "createByVertex",
    value: function createByVertex(first) {
      var poly = new Polygon();
      poly._first = first;

      poly._updateVertices();

      return poly;
    }
  }]);

  return Polygon;
}();
/**
 * @summary 単調多角形に分割するためのエッジ管理
 *
 * @classdesc
 * <p>追加されるエッジの局所右は常に多角形の内側になる。</p>
 *
 * @private
 */


var EdgeManager =
/*#__PURE__*/
function () {
  /**
   */
  function EdgeManager() {
    _classCallCheck(this, EdgeManager);

    this._edges = new Map();
  }
  /**
   * @summary エッジを追加
   *
   * @param {Vertex} edge    追加するエッジ
   * @param {Vertex} helper  初期ヘルパー頂点
   */


  _createClass(EdgeManager, [{
    key: "addEdge",
    value: function addEdge(edge, helper) {
      this._edges.set(edge, {
        helper: helper
      });
    }
    /**
     * @summary エッジを削除
     *
     * @param {Vertex} edge  削除するエッジ
     */

  }, {
    key: "removeEdge",
    value: function removeEdge(edge) {
      this._edges["delete"](edge);
    }
    /**
     * @summary エッジにヘルパーを設定
     *
     * @param {Vertex} edge    対象エッジ
     * @param {Vertex} helper  ヘルパー頂点
     */

  }, {
    key: "setHelper",
    value: function setHelper(edge, helper) {
      this._edges.get(edge).helper = helper;
    }
    /**
     * @summary エッジのヘルパーを取得
     *
     * @param {Vertex} edge  対象エッジ
     *
     * @return {Vertex}  ヘルパー頂点
     */

  }, {
    key: "getHelper",
    value: function getHelper(edge) {
      return this._edges.get(edge).helper;
    }
    /**
     * @summary 頂点の左側で最も近いエッジを検索
     *
     * @desc
     * <p>vertex を左に (多角形の内側を) 移動しながら最初に突き当たるエッジを取得する。
     *    そのようなエッジが常に存在することが前提になっている。</p>
     *
     * <p>vertex の局所左は常に多角形の内側になる。</p>
     *
     * @param {Vertex} vertex  対象頂点
     *
     * @return {Vertex}  エッジ
     */

  }, {
    key: "findNearestLeftEdge",
    value: function findNearestLeftEdge(vertex) {
      // このメソッドが呼び出された時点での前提状態:
      //   - どちらかの端点が vertex のエッジは存在しない
      //   - 両端の y 座標が同じエッジは存在しない
      //   - すべてのエッジは vertex を通る水平線と交差する
      // TODO:
      //   このメソッドは多角形の頂点数 n に対して計算量は最悪 O(n), 平均は不明
      //   最悪の場合、ポリゴン分割全体の計算量が O(n^2) になってしまう
      //   そのため、このめメソッド単体で最悪 O(log n) または平均 O(log n) 以下にしたい
      var nearest_edge;
      var min_distance = Number.MAX_VALUE;
      var vx = vertex.x;
      var vy = vertex.y;
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = this._edges[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var _step4$value = _slicedToArray(_step4.value, 1),
              edge = _step4$value[0];

          // エッジ始点 p
          var px = edge.x;
          var py = edge.y; // エッジ終点 q

          var qx = edge.next.x;
          var qy = edge.next.y; // エッジの x 座標勾配

          var gx = (qx - px) / (qy - py); // 水平線とエッジの交点の x 座標

          var rx = px + (vy - py) * gx; // vertex と交点 r との符号付き距離 (正のとき r は vertex の左側)

          var distance = vx - rx;

          if (distance > 0) {
            if (distance < min_distance) {
              // 近いエッジを更新
              min_distance = distance;
              nearest_edge = edge;
            }
          }
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) {
            _iterator4["return"]();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }

      if (nearest_edge === undefined) {
        // 想定に反して左のエッジが見つからなかった
        throw new Error("Probably a degenerate polygon");
      }

      return nearest_edge;
    }
  }]);

  return EdgeManager;
}();
/**
 * @summary 対角線
 *
 * @private
 */


var Diagonal =
/**
 * @param {Vertex} v1  対角線の端点1
 * @param {Vertex} v2  対角線の端点2
 */
function Diagonal(v1, v2) {
  _classCallCheck(this, Diagonal);

  this.v1 = v1;
  this.v2 = v2;
};
/**
 * @summary 対角線管理
 *
 * @private
 */


var DiagonalManager =
/*#__PURE__*/
function () {
  /**
   * @param {Set.<Polygon>} polygons  多角形集合
   */
  function DiagonalManager(polygons) {
    _classCallCheck(this, DiagonalManager);

    this._polygons = polygons;
    this._diagonals = [];
    this._dmap = new DiagonalMap();
  }
  /**
   * @brief 対角線を追加
   *
   * @param {Vertex} v1  対角線の端点1
   * @param {Vertex} v2  対角線の端点2
   */


  _createClass(DiagonalManager, [{
    key: "addDiagonal",
    value: function addDiagonal(v1, v2) {
      var diagonal = new Diagonal(v1, v2);

      this._diagonals.push(diagonal);

      this._dmap.addDiagonal(diagonal);
    }
    /**
     * @brief すべての多角形を対角線で分割
     */

  }, {
    key: "splitPolygons",
    value: function splitPolygons() {
      // 対角線の順序をランダムにして、分割方向が偏らないようにする
      // これにより頂点数 n に対して計算量 O(n log n) が期待できる
      this._shuffleArray(this._diagonals); // 個々の対角線で多角形を分割


      while (this._diagonals.length > 0) {
        var diagonal = this._diagonals.pop();

        this._dmap.removeDiagonal(diagonal);

        var v1 = diagonal.v1;
        var v2 = diagonal.v2;

        var _this$_splitPolygonHa = this._splitPolygonHalf(v1, v2),
            _this$_splitPolygonHa2 = _slicedToArray(_this$_splitPolygonHa, 2),
            v1a = _this$_splitPolygonHa2[0],
            v2a = _this$_splitPolygonHa2[1];

        var _this$_splitPolygonHa3 = this._splitPolygonHalf(v2, v1),
            _this$_splitPolygonHa4 = _slicedToArray(_this$_splitPolygonHa3, 2),
            v2b = _this$_splitPolygonHa4[0],
            v1b = _this$_splitPolygonHa4[1];

        var p1 = v1.polygon;
        var p2 = v2.polygon;

        if (p1 === p2) {
          // diagonal は多角形 p1 内の対角線
          this._polygons["delete"](p1);

          this._polygons.add(Polygon.createByVertex(v1a));

          this._polygons.add(Polygon.createByVertex(v1b));
        } else {
          // diagonal は多角形 p1, p2 間の対角線
          this._polygons["delete"](p1);

          this._polygons["delete"](p2);

          this._polygons.add(Polygon.createByVertex(v1a));
        } // 対角線の端点を新しく生成された端点に置き換える


        this._replaceVertexInDiagonals(v1, v1a, v1b);

        this._replaceVertexInDiagonals(v2, v2a, v2b);
      }
    }
    /**
     * @summary 多角形分割の半分の処理
     *
     * @param {Vertex} sv  開始点
     * @param {Vertex} ev  終了点
     *
     * @return {Vertex[]}  [新 sv, 新 ev]
     *
     * @private
     */

  }, {
    key: "_splitPolygonHalf",
    value: function _splitPolygonHalf(sv, ev) {
      var sc = sv.clone();
      var ec = ev.clone();
      sc.prev = sv.prev;
      sc.next = ec;
      sv.prev.next = sc;
      ec.prev = sc;
      ec.next = ev.next;
      ev.next.prev = ec;
      return [sc, ec];
    }
    /**
     * @summary 対角線の端点の置き換え
     *
     * @desc
     * <p>端点の1つが vo の対角線のその端点を va または vb に置き換える。</p>
     * <p>候補端点 va, vb のうち、置き換えると対角線が多角形の内側になる方を選ぶ。</p>
     * <p>一方が内側で、一方が外側になるはず。</p>
     *
     * @param {Vertex} vo  元の端点
     * @param {Vertex} va  候補端点 a
     * @param {Vertex} vb  候補端点 b
     *
     * @private
     */

  }, {
    key: "_replaceVertexInDiagonals",
    value: function _replaceVertexInDiagonals(vo, va, vb) {
      // 一旦 this._dmap から対角線を抜き取って、端点を書き換えてから戻す
      var _iteratorNormalCompletion5 = true;
      var _didIteratorError5 = false;
      var _iteratorError5 = undefined;

      try {
        for (var _iterator5 = this._dmap.removeDiagonals(vo)[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
          var diagonal = _step5.value;
          // vo の反対側の端点
          var vo_oppo = diagonal.v1 === vo ? diagonal.v2 : diagonal.v1; // 対角線の端点の書き換え

          diagonal.v1 = this._testDiagonal(va, vo_oppo) ? va : vb;
          diagonal.v2 = vo_oppo; // 対角線を戻す

          this._dmap.addDiagonal(diagonal);
        }
      } catch (err) {
        _didIteratorError5 = true;
        _iteratorError5 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion5 && _iterator5["return"] != null) {
            _iterator5["return"]();
          }
        } finally {
          if (_didIteratorError5) {
            throw _iteratorError5;
          }
        }
      }
    }
    /**
     * @summary 対角線テスト
     *
     * <p>端点が v1, v2 の線分は多角形の (v1 の) 内側に入るか?</p>
     *
     * @param {Vertex} v1  端点1
     * @param {Vertex} v2  端点2
     *
     * @return {boolean}  内側に入るとき true, それ以外のとき false
     *
     * @private
     */

  }, {
    key: "_testDiagonal",
    value: function _testDiagonal(v1, v2) {
      // a: v1 から順方向のベクトル
      var ax = v1.next.x - v1.x;
      var ay = v1.next.y - v1.y; // b: v1 から逆方向のベクトル

      var bx = v1.prev.x - v1.x;
      var by = v1.prev.y - v1.y; // c: v1 から v2 のベクトル

      var cx = v2.x - v1.x;
      var cy = v2.y - v1.y; // cross(a) . c > 0

      var aflag = ax * cy - cx * ay > 0; // cross(b) . c < 0

      var bflag = bx * cy - cx * by < 0; // |ax bx|
      // |ay by|

      var det = ax * by - bx * ay;
      return det >= 0 ? aflag && bflag : aflag || bflag;
    }
    /**
     * @summary 配列の並びをランダム化
     *
     * @param {array} array  処理対象の配列
     *
     * @private
     */

  }, {
    key: "_shuffleArray",
    value: function _shuffleArray(array) {
      // Fisher-Yates のシャッフル
      // TODO: 用途上、再現性のある乱数を使ってもよいし、そのほうが何かあった時に原因をつかみやすい
      for (var i = array.length - 1; i > 0; --i) {
        var j = Math.floor(Math.random() * (i + 1)); // 0 <= j <= i
        // array[i] と array[j] を交換

        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
      }
    }
  }]);

  return DiagonalManager;
}();
/**
 * @summary 辞書: 対角線頂点 → 対角線リスト
 *
 * @classdesc
 * <p>対角線の頂点から、その頂点を端点とする対角線の配列を取得する。</p>
 * <p>1 つの頂点に対して対角線は最大 3 本なので、追加、削除、検索の計算量は多角形の頂点数 n に対して O(1) である。</p>
 *
 * @memberof DiagonalManager
 * @private
 */


var DiagonalMap =
/*#__PURE__*/
function () {
  function DiagonalMap() {
    _classCallCheck(this, DiagonalMap);

    // 辞書を生成
    // key:   Vertex
    // value: Diagonal[]
    this._map = new Map();
  }
  /**
   * @summary 対角線を登録
   *
   * @param {Diagonal} diagonal  追加する対角線
   */


  _createClass(DiagonalMap, [{
    key: "addDiagonal",
    value: function addDiagonal(diagonal) {
      this._addDiagonalByVertex(diagonal.v1, diagonal);

      this._addDiagonalByVertex(diagonal.v2, diagonal);
    }
    /**
     * @summary 対角線の登録を解除
     *
     * @param {Diagonal} diagonal  削除する対角線
     */

  }, {
    key: "removeDiagonal",
    value: function removeDiagonal(diagonal) {
      this._removeDiagonalByVertex(diagonal.v1, diagonal);

      this._removeDiagonalByVertex(diagonal.v2, diagonal);
    }
    /**
     * @summary vertex を端点とする、すべの対角線の登録を解除
     *
     * @param {Vertex} vertex  対角線の端点
     *
     * @return {Diagonal[]}  登録を解除された対角線の配列
     */

  }, {
    key: "removeDiagonals",
    value: function removeDiagonals(vertex) {
      var diagonals = this._map.get(vertex);

      if (diagonals !== undefined) {
        // 辞書から対角線を削除
        var cloned = diagonals.slice();
        var _iteratorNormalCompletion6 = true;
        var _didIteratorError6 = false;
        var _iteratorError6 = undefined;

        try {
          for (var _iterator6 = cloned[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
            var diag = _step6.value;
            this.removeDiagonal(diag);
          }
        } catch (err) {
          _didIteratorError6 = true;
          _iteratorError6 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion6 && _iterator6["return"] != null) {
              _iterator6["return"]();
            }
          } finally {
            if (_didIteratorError6) {
              throw _iteratorError6;
            }
          }
        }

        return cloned;
      } else {
        // 存在しなかった
        return [];
      }
    }
    /**
     * @summary 対角線を登録
     *
     * @param {Vertex}   vertex    どちらかの端点
     * @param {Diagonal} diagonal  追加する対角線
     *
     * @private
     */

  }, {
    key: "_addDiagonalByVertex",
    value: function _addDiagonalByVertex(vertex, diagonal) {
      var array = this._map.get(vertex);

      if (array === undefined) {
        // vertex に対する最初の対角線
        this._map.set(vertex, [diagonal]);
      } else {
        // vertex に対する2つ目以降の対角線
        if (array.indexOf(diagonal) != -1) {
          // 対角線は二重登録されないはずが...
          throw new Error("Unexpected");
        }

        if (array.length < 1 || array.length > 2) {
          // 同一頂点の対角線は最大3本のはずが...
          throw new Error("Unexpected");
        }

        array.push(diagonal);
      }
    }
    /**
     * @summary 対角線を削除
     *
     * @param {Vertex}   vertex    どちらかの端点
     * @param {Diagonal} diagonal  削除する対角線
     *
     * @private
     */

  }, {
    key: "_removeDiagonalByVertex",
    value: function _removeDiagonalByVertex(vertex, diagonal) {
      var array = this._map.get(vertex);

      if (array === undefined) {
        // 存在するはずが...
        throw new Error("Unexpected");
      }

      var index = array.indexOf(diagonal);

      if (index == -1) {
        // 存在するはずが...
        throw new Error("Unexpected");
      } // 配列から diagonal を削除


      array.splice(index, 1); // 配列が空になったら配列を削除

      if (array.length == 0) {
        this._map["delete"](vertex);
      }
    }
  }]);

  return DiagonalMap;
}();
/**
 * @summary スタック
 *
 * @private
 */


var Stack =
/*#__PURE__*/
function () {
  function Stack() {
    _classCallCheck(this, Stack);

    this._array = new Array();
  }

  _createClass(Stack, [{
    key: "push",
    value: function push(item) {
      this._array.push(item);
    }
  }, {
    key: "pop",
    value: function pop() {
      return this._array.pop();
    }
  }, {
    key: "size",
    get: function get() {
      return this._array.length;
    }
  }, {
    key: "top",
    get: function get() {
      var a = this._array;
      return a.length > 0 ? a[a.length - 1] : null;
    }
  }]);

  return Stack;
}();

var globalIsFinite = global_1.isFinite; // `Number.isFinite` method
// https://tc39.github.io/ecma262/#sec-number.isfinite

var numberIsFinite = Number.isFinite || function isFinite(it) {
  return typeof it == 'number' && globalIsFinite(it);
};

// https://tc39.github.io/ecma262/#sec-number.isfinite

_export({
  target: 'Number',
  stat: true
}, {
  isFinite: numberIsFinite
});

/**
 * @summary 凸多角形
 *
 * @memberof mapray
 *
 * @private
 */
var ConvexPolygon =
/*#__PURE__*/
function () {
  /**
   * <p>3 点またはそれ以上の頂点座標を反時計回りで指定する。</p>
   *
   * @param {iterable.<number>} coords  頂点座標の並び x0, y0, x1, y1, ...
   */
  function ConvexPolygon(coords) {
    _classCallCheck(this, ConvexPolygon);

    this._vertices = Float64Array.from(coords);
    this._num_vertices = this._vertices.length / 2;
  }
  /**
   * @summary 凸多角形の頂点数
   *
   * @type {number}
   *
   * @readonly
   */


  _createClass(ConvexPolygon, [{
    key: "isValid",

    /**
     * @summary 妥当性を検査
     *
     * @desc
     * <p>this が妥当な凸多角形かどうかを確かめる。</p>
     *
     * @return {boolean}  this が妥当なとき true, それ以外のとき false
     */
    value: function isValid() {
      if (this._num_vertices < 3) {
        // 3 頂点未満の多角形は非対応
        return false;
      } // 座標が有効な数値であることをチェック


      for (var i = 0; i < this._num_vertices; ++i) {
        var x = this._vertices[2 * i];
        var y = this._vertices[2 * i + 1];

        if (!Number.isFinite(x) || !Number.isFinite(y)) {
          // 有効な数値ではない座標が含まれる
          return false;
        }
      } // 長さ 0 の稜線が無いことをチェック


      for (var ei = 0; ei < this._num_vertices; ++ei) {
        var si = ei != 0 ? ei - 1 : this._num_vertices - 1;
        var sx = this._vertices[2 * si];
        var sy = this._vertices[2 * si + 1];
        var ex = this._vertices[2 * ei];
        var ey = this._vertices[2 * ei + 1];

        if (sx == ex && sy == ey) {
          // 同一位置の隣接頂点が含まれる
          return false;
        }
      } // 内角が 0 でない、または 180 度より大きくないことをチェック


      for (var oi = 0; oi < this._num_vertices; ++oi) {
        var ox = this._vertices[2 * oi];
        var oy = this._vertices[2 * oi + 1]; // 前方への方向ベクトル

        var fi = oi == this._num_vertices - 1 ? 0 : oi + 1;
        var fx = this._vertices[2 * fi] - ox;
        var fy = this._vertices[2 * fi + 1] - oy; // 後方への方向ベクトル

        var bi = oi == 0 ? this._num_vertices - 1 : oi - 1;
        var bx = this._vertices[2 * bi] - ox;
        var by = this._vertices[2 * bi + 1] - oy; // 面積と内積

        var det = fx * by - bx * fy;
        var dot = fx * bx + fy * by;

        if (det < 0 || det == 0 && dot > 0) {
          // 内角 θ は 0 < θ <= 180 ではない
          return false;
        }
      }

      return true;
    }
    /**
     * @summary 交差凸多角形を取得
     *
     * @desc
     * <p>凸多角形 this と凸多角形 polygon が交差すれば、交差部分の凸多角形を返す。</p>
     * <p>this と polygon が交差しないときは null を返す。</p>
     * <p>this が polygon を包含するときは polygon を返す可能性がある。</p>
     *
     * @param {ConvexPolygon} polygon  凸多角形
     *
     * @return {?ConvexPolygon}  交差凸多角形、ただし交差しないときは null
     *
     * @throws Error  凸多角形の切り取りに失敗
     */

  }, {
    key: "getIntersection",
    value: function getIntersection(polygon) {
      try {
        return this._clip_by_polygon(polygon);
      } catch (e) {
        throw new Error("ConvexPolygon#getIntersection failed");
      }
    }
    /**
     * @summary 凸多角形同士に交差があるかどうか?
     *
     * @desc
     * <p>凸多角形 this と凸多角形 polygon が交差するかどうかを返す。</p>
     *
     * @param {ConvexPolygon} polygon  凸多角形
     *
     * @return {boolean}  交差するとき true, 交差しないとき false
     *
     * @throws Error  交差の確認に失敗
     */

  }, {
    key: "hasIntersection",
    value: function hasIntersection(polygon) {
      try {
        return this._clip_by_polygon(polygon) !== null;
      } catch (e) {
        throw new Error("ConvexPolygon#hasIntersection failed");
      }
    }
    /**
     * @summary 凸多角形を包含するか?
     *
     * @desc
     * <p>凸多角形 this は凸多角形 polygon を包含するかどうかを返す。</p>
     *
     * @param {ConvexPolygon} polygon  凸多角形
     *
     * @return {boolean}  this が polygon を包含するとき true, それ以外は false
     */

  }, {
    key: "includes",
    value: function includes(polygon) {
      for (var ei = 0; ei < this._num_vertices; ++ei) {
        var si = ei != 0 ? ei - 1 : this._num_vertices - 1; // 直線上の 1 点

        var px = this._vertices[2 * si];
        var py = this._vertices[2 * si + 1]; // 直線の内側方向

        var nx = py - this._vertices[2 * ei + 1];
        var ny = this._vertices[2 * ei] - px; // 判定数値

        var dval = px * nx + py * ny; // this の si-ei 稜線の

        for (var i = 0; i < polygon._num_vertices; ++i) {
          // polygon の 1 点
          var qx = polygon._vertices[2 * i];
          var qy = polygon._vertices[2 * i + 1];

          if (qx * nx + qy * ny < dval) {
            // polygon の 1 点が this の外側
            // polygon は this の完全に内側ではない
            return false;
          }
        }
      } // polygon は this の完全に内側である


      return true;
    }
    /**
     * @summary 凸多角形により凸多角形を切り取る
     *
     * @desc
     * <p>凸多角形 this により凸多角形 polygon を切り取った凸多角形を返す。</p>
     * <p>this が polygon を包含するときは polygon を返す。</p>
     * <p>this と polygon が交差しないときは null を返す。</p>
     *
     * @param {ConvexPolygon} polygon  凸多角形
     *
     * @return {?ConvexPolygon}  凸多角形または null
     *
     * @throws Error  凸多角形の切り取りに失敗
     *
     * @private
     */

  }, {
    key: "_clip_by_polygon",
    value: function _clip_by_polygon(polygon) {
      var current = polygon;

      for (var ei = 0; ei < this._num_vertices; ++ei) {
        var si = ei != 0 ? ei - 1 : this._num_vertices - 1; // 直線上の 1 点

        var px = this._vertices[2 * si];
        var py = this._vertices[2 * si + 1]; // 直線の内側方向

        var nx = py - this._vertices[2 * ei + 1];
        var ny = this._vertices[2 * ei] - px; // 判定数値

        var dval = px * nx + py * ny; // 半空間による切り取り

        current = current._clip_by_halfspace(nx, ny, dval);

        if (current === null) {
          // this と polygon は交差しない
          break;
        }
      }

      return current;
    }
    /**
     * @summary 半空間により凸多角形を切り取る
     *
     * @desc
     * <p>半空間により凸多角形 this を切り取ったり、その凸多角形を返す。</p>
     * <p>半空間が this を内包するときは this を返す。</p>
     * <p>半空間と this が交差しないときは null を返す。</p>
     *
     * @param {number} nx    半空間の内側方向の x 座標
     * @param {number} ny    半空間の内側方向の y 座標
     * @param {number} dval  判定用数値
     *
     * @return {?ConvexPolygon}  凸多角形または null
     *
     * @throws Error  半空間による切り取りに失敗
     *
     * @private
     */

  }, {
    key: "_clip_by_halfspace",
    value: function _clip_by_halfspace(nx, ny, dval) {
      // 半空間の境界線からの距離範囲
      var dist_min = Number.MAX_VALUE;
      var dist_max = -Number.MAX_VALUE;

      for (var i = 0; i < this._num_vertices; ++i) {
        // 頂点座標
        var px = this._vertices[2 * i];
        var py = this._vertices[2 * i + 1]; // dist == 0 半空間の境界線上
        // dist > 0  半空間の内側
        // dist < 0  半空間の外側

        var dist = px * nx + py * ny - dval; // 最大最小を更新

        dist_min = Math.min(dist_min, dist);
        dist_max = Math.max(dist_max, dist);
      }

      if (dist_min >= 0) {
        // 半空間は this を内包する
        return this;
      }

      if (dist_max <= 0) {
        // 半空間 と this は交差しない
        return null;
      } // ここで dist_min < 0 < dist_max なので、半空間の境界線は凸多角形
      // this の内部を通過している (接していない)


      return this._clip_by_crossed_halfspace(nx, ny, dval);
    }
    /**
     * @summary 半空間により凸多角形を切り取る (一部交差前提)
     *
     * @desc
     * <p>半空間により凸多角形 this を切り取ったり、その凸多角形を返す。</p>
     * <p>このメソッドは凸多角形 this の境界線と半空間の境界線が異なる
     *    2 点で交差していることが前提になっている。</p>
     *
     * @param {number} nx    半空間の内側方向の x 座標
     * @param {number} ny    半空間の内側方向の y 座標
     * @param {number} dval  判定用数値
     *
     * @return {ConvexPolygon}  凸多角形
     *
     * @throws Error  半空間による切り取りに失敗
     *
     * @private
     */

  }, {
    key: "_clip_by_crossed_halfspace",
    value: function _clip_by_crossed_halfspace(nx, ny, dval) {
      var _this$_get_cross_edge = this._get_cross_edges_by_crossed_halfspace_boundary(nx, ny, dval),
          _this$_get_cross_edge2 = _slicedToArray(_this$_get_cross_edge, 2),
          ce0 = _this$_get_cross_edge2[0],
          ce1 = _this$_get_cross_edge2[1];

      var polygon = []; // 最初の頂点

      polygon.push(ce0.qx);
      polygon.push(ce0.qy); // 中間頂点のインデックス

      var first_i = ce0.ei; // 最初の中間頂点

      var last_i = ce1.ei; // 最後の中間頂点の次
      // 中間の頂点

      for (var i = first_i; i != last_i; i = (i + 1) % this._num_vertices) {
        polygon.push(this._vertices[2 * i]);
        polygon.push(this._vertices[2 * i + 1]);
      } // 最後の頂点


      polygon.push(ce1.qx);
      polygon.push(ce1.qy);
      return new ConvexPolygon(polygon);
    }
    /**
     * @summary 半空間境界線と交差する2稜線のデータを取得 (2点交差前提)
     *
     * @desc
     * <p>2要素の配列を返す。</p>
     * <p>最初の要素は切り取りにより前方が残される稜線のデータである。</p>
     * <p>次の要素は切り取りにより後方が残される稜線のデータである。</p>
     *
     * <p>配列の各要素のオブジェクトプロパティは次のようになる。</p>
     * <pre>
     *   ei: 境界線と交差した稜線の終点インデックス
     *   qx: 境界線と稜線が交差した位置の x 座標
     *   qy: 境界線と稜線が交差した位置の y 座標
     * </pre>
     *
     * @param {number} nx    半空間の内側方向の x 座標
     * @param {number} ny    半空間の内側方向の y 座標
     * @param {number} dval  判定用数値
     *
     * @return {object[]}  2稜線の交差データ
     *
     * @throws Error  2点の交差が見つからなかった
     *
     * @private
     */

  }, {
    key: "_get_cross_edges_by_crossed_halfspace_boundary",
    value: function _get_cross_edges_by_crossed_halfspace_boundary(nx, ny, dval) {
      var cross_edges = new Array(2);

      for (var si = 0, ce_count = 0; ce_count < 2; ++si) {
        if (si == this._num_vertices) {
          // 妥当でない凸多角形、数値計算誤差、非数値の混入などで
          // 2点の交差が見つからず、無限ループになる可能性がある
          // それを避けるため、すべての稜線を調べ終わったら例外で
          // 強制的に終了する
          throw new Error("cross edges could not be found");
        }

        var ei = (si + 1) % this._num_vertices; // 稜線の始点位置

        var sx = this._vertices[2 * si];
        var sy = this._vertices[2 * si + 1]; // 稜線の終点位置

        var ex = this._vertices[2 * ei];
        var ey = this._vertices[2 * ei + 1]; // 境界線からの距離

        var sd = sx * nx + sy * ny - dval;
        var ed = ex * nx + ey * ny - dval; // 半空間境界線と si-ei 稜線の交差があればデータを追加

        if (sd <= 0 && 0 < ed || ed <= 0 && 0 < sd) {
          var t = sd / (sd - ed);
          var qx = sx + (ex - sx) * t;
          var qy = sy + (ey - sy) * t;
          cross_edges[sd < ed ? 0 : 1] = {
            ei: ei,
            qx: qx,
            qy: qy
          };
          ++ce_count;
        }
      }

      return cross_edges;
    }
  }, {
    key: "num_vertices",
    get: function get() {
      return this._num_vertices;
    }
    /**
     * @summary 凸多角形の頂点座標配列
     *
     * @desc
     * <p>反時計回りで格納された頂点座標の配列 [x0, y0, x1, y1, ...] を返す。<p>
     * <p>返された配列の内容は this に対して変更操作が行われるまで有効である。<p>
     *
     * @type {number[]}
     *
     * @readonly
     */

  }, {
    key: "vertices",
    get: function get() {
      return this._vertices;
    }
    /**
     * @summary 矩形から凸多角形を生成
     *
     * @param {number} x_min  x 座標の最小値
     * @param {number} y_min  y 座標の最小値
     * @param {number} x_max  x 座標の最大値
     * @param {number} y_max  y 座標の最大値
     *
     * @return {mapray.ConvexPolygon}  凸多角形
     */

  }], [{
    key: "createByRectangle",
    value: function createByRectangle(x_min, y_min, x_max, y_max) {
      // 入力座標配列
      var coords = [x_min, y_min, x_max, y_min, x_max, y_max, x_min, y_max]; // 凸多角形を生成

      return new ConvexPolygon(coords);
    }
  }]);

  return ConvexPolygon;
}();

/**
 * @summary 多角形エンティティ
 * @memberof mapray
 * @extends mapray.Entity
 */

var PolygonEntity =
/*#__PURE__*/
function (_Entity) {
  _inherits(PolygonEntity, _Entity);

  /**
   * @param {mapray.Scene} scene        所属可能シーン
   * @param {object}       [opts]       オプション集合
   * @param {object}       [opts.json]  生成情報
   * @param {object}       [opts.refs]  参照辞書
   */
  function PolygonEntity(scene, opts) {
    var _this;

    _classCallCheck(this, PolygonEntity);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(PolygonEntity).call(this, scene, opts));
    _this._extruded_height = 0.0;
    _this._color = GeoMath.createVector3([1, 1, 1]);
    _this._opacity = 1.0; // 頂点管理

    _this._boundaries = []; // Boundary のリスト

    _this._position = null; // 中央付近の GeoPoint
    // this._producer
    // this._is_flake_mode

    if (_this.altitude_mode === AltitudeMode.CLAMP) {
      _this._producer = new FlakePrimitiveProducer$2(_assertThisInitialized(_this));
      _this._is_flake_mode = true;
    } else {
      _this._producer = new PrimitiveProducer$4(_assertThisInitialized(_this));
      _this._is_flake_mode = false;
    } // 生成情報から設定


    if (opts && opts.json) {
      _this._setupByJson(opts.json);
    }

    return _this;
  }
  /**
   * @summary 押し出し量(0より大きい値)
   * @type {number}
   */


  _createClass(PolygonEntity, [{
    key: "getPrimitiveProducer",

    /**
     * @override
     */
    value: function getPrimitiveProducer() {
      return !this._is_flake_mode ? this._producer : null;
    }
    /**
     * @override
     */

  }, {
    key: "getFlakePrimitiveProducer",
    value: function getFlakePrimitiveProducer() {
      return this._is_flake_mode ? this._producer : null;
    }
    /**
     * @override
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode(prev_mode) {
      if (this.altitude_mode === AltitudeMode.CLAMP) {
        this._producer = new FlakePrimitiveProducer$2(this);
        this._is_flake_mode = true;
      } else {
        this._producer = new PrimitiveProducer$4(this);
        this._is_flake_mode = false;
      }
    }
    /**
     * @summary 基本色を設定
     * @param {mapray.Vector3} color  基本色
     */

  }, {
    key: "setColor",
    value: function setColor(color) {
      GeoMath.copyVector3(color, this._color);

      this._producer.onChangeProperty();
    }
    /**
     * @summary 不透明度を設定
     * @param {number} opacity  不透明度
     */

  }, {
    key: "setOpacity",
    value: function setOpacity(opacity) {
      this._opacity = opacity;

      this._producer.onChangeProperty();
    }
    /**
     * @summary 外側境界を追加
     *
     * @desc
     * <p>points は [lon_0, lat_0, alt_0, lon_1, lat_1, alt_1, ...] のような形式で配列を与える。</p>
     *
     * @param {number[]} points  頂点の配列
     */

  }, {
    key: "addOuterBoundary",
    value: function addOuterBoundary(points) {
      this._addBoundary(points, false);
    }
    /**
     * @summary 内側境界を追加
     *
     * @desc
     * <p>points は [lon_0, lat_0, alt_0, lon_1, lat_1, alt_1, ...] のような形式で配列を与える。</p>
     *
     * @param {number[]} points  頂点の配列
     */

  }, {
    key: "addInnerBoundary",
    value: function addInnerBoundary(points) {
      this._addBoundary(points, true);
    }
    /**
     * @summary 境界を追加
     *
     * @desc
     * <p>addOuterBoundary(), addInnerBoundary() の実装である。</p>
     *
     * @param {number[]} points  頂点の配列
     *
     * @private
     */

  }, {
    key: "_addBoundary",
    value: function _addBoundary(points, is_inner) {
      this._boundaries.push(new Boundary(points, is_inner));

      this._position = null; // 境界の変更を通知

      this._producer.onChangeBoundary();
    }
    /**
     * @summary 専用マテリアルを取得
     * @private
     */

  }, {
    key: "_getPolygonMaterial",
    value: function _getPolygonMaterial() {
      var scene = this.scene;

      if (!scene._PolygonEntity_material) {
        // scene にマテリアルをキャッシュ
        scene._PolygonEntity_material = new PolygonMaterial(scene.glenv);
      }

      return scene._PolygonEntity_material;
    }
    /**
     * @private
     */

  }, {
    key: "_setupByJson",
    value: function _setupByJson(json) {
      // json.boundaries
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = json.boundaries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var boundary = _step.value;

          if (boundary.type == "inner") {
            this.addInnerBoundary(boundary.points);
          } else {
            this.addOuterBoundary(boundary.points);
          }
        } // json.extruded_height

      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      if (json.extruded_height !== undefined) {
        this.extruded_height = json.extruded_height;
      } // json.color
      //     .opacity


      if (json.color !== undefined) GeoMath.copyVector3(json.color, this._color);
      if (json.opacity !== undefined) this._opacity = json.opacity;
    }
    /**
     * @summary 中央位置を取得
     *
     * @desc
     * <p>中央位置を計算して返す。多角形が存在しないときは null を返す。</p>
     *
     * <p>中央位置が変化する可能性があるときは this._position にを null を設定すること。</p>
     *
     * <pre>
     * 入力: this._boundaries
     * </pre>
     *
     * @return {mapray.GeoPoint}  中央位置 (高度は 0) または null
     *
     * @private
     */

  }, {
    key: "_getPosition",
    value: function _getPosition() {
      if (this._position !== null) {
        // キャッシュさている値を返す
        return this._position;
      }

      if (this._boundaries.length == 0) {
        // 多角形が存在しない
        return null;
      }

      var min_lon = Number.MAX_VALUE;
      var max_lon = -Number.MAX_VALUE;
      var min_lat = Number.MAX_VALUE;
      var max_lat = -Number.MAX_VALUE;
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this._boundaries[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var bo = _step2.value;
          var count = bo.num_points;
          var points = bo.points;

          for (var i = 0; i < count; ++i) {
            var lon = points[3 * i];
            var lat = points[3 * i + 1];
            if (lon < min_lon) min_lon = lon;
            if (lon > max_lon) max_lon = lon;
            if (lat < min_lat) min_lat = lat;
            if (lat > max_lat) max_lat = lat;
          }
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      this._position = new GeoPoint((min_lon + max_lon) / 2, (min_lat + max_lat) / 2);
      return this._position;
    }
    /**
     * @summary すべての境界の頂点数の合計を取得
     *
     * @private
     */

  }, {
    key: "_countNumPointsOnBoundaries",
    value: function _countNumPointsOnBoundaries() {
      var num_points = 0;
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = this._boundaries[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var bo = _step3.value;
          num_points += bo.num_points;
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }

      return num_points;
    }
    /**
     * @summary 結合された境界点列を取得
     *
     * @return {Float64Array}  結合された境界点列
     */

  }, {
    key: "_getCombinedBoundaryPoints",
    value: function _getCombinedBoundaryPoints() {
      var points = new Float64Array(3 * this._countNumPointsOnBoundaries());
      var offset = 0;
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = this._boundaries[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var bo = _step4.value;
          points.set(bo.points, offset);
          offset += 3 * bo.num_points;
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) {
            _iterator4["return"]();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }

      return points;
    }
    /**
     * @summary 結合された 2D 境界点列を取得 (高度なし)
     *
     * @return {Float64Array}  結合された 2D 境界点列
     */

  }, {
    key: "_getCombinedBoundary2DPoints",
    value: function _getCombinedBoundary2DPoints() {
      var dst_points = new Float64Array(2 * this._countNumPointsOnBoundaries());
      var di = 0;
      var _iteratorNormalCompletion5 = true;
      var _didIteratorError5 = false;
      var _iteratorError5 = undefined;

      try {
        for (var _iterator5 = this._boundaries[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
          var bo = _step5.value;
          var src_size = 3 * bo.num_points;
          var src_points = bo.points;

          for (var si = 0; si < src_size; si += 3) {
            dst_points[di++] = src_points[si];
            dst_points[di++] = src_points[si + 1];
          }
        }
      } catch (err) {
        _didIteratorError5 = true;
        _iteratorError5 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion5 && _iterator5["return"] != null) {
            _iterator5["return"]();
          }
        } finally {
          if (_didIteratorError5) {
            throw _iteratorError5;
          }
        }
      }

      return dst_points;
    }
    /**
     * @summary 三角形リストを生成
     *
     * @desc
     * <p>this.entity._boundaries を三角形に変換してリストを返す。ただし変換に失敗したときは null を返す。</p>
     *
     * @return {Uint32Array}  三角形リストまたは null
     *
     * @private
     */

  }, {
    key: "_createTriangles",
    value: function _createTriangles() {
      var src_points = this._getCombinedBoundary2DPoints();

      var num_src_points = this._countNumPointsOnBoundaries(); // 境界を登録


      var triangulator = new Triangulator(src_points, 0, 2, num_src_points);
      var index = 0;
      var _iteratorNormalCompletion6 = true;
      var _didIteratorError6 = false;
      var _iteratorError6 = undefined;

      try {
        for (var _iterator6 = this._boundaries[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
          var bo = _step6.value;
          var num_indices = bo.num_points;
          var indices = new Uint32Array(num_indices);

          for (var i = 0; i < num_indices; ++i) {
            indices[i] = index++;
          }

          triangulator.addBoundary(indices);
        }
      } catch (err) {
        _didIteratorError6 = true;
        _iteratorError6 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion6 && _iterator6["return"] != null) {
            _iterator6["return"]();
          }
        } finally {
          if (_didIteratorError6) {
            throw _iteratorError6;
          }
        }
      }

      try {
        // 変換を実行
        return triangulator.run();
      } catch (e) {
        // 変換に失敗
        console.error(e.message);
        return null;
      }
    }
  }, {
    key: "extruded_height",
    set: function set(value) {
      var prev = this._extruded_height;

      if (prev !== value) {
        this._extruded_height = value;

        this._producer.onChangeExtruded();
      }
    }
    /**
     * @summary 押し出し量
     * @type {number}
     */
    ,
    get: function get() {
      return this._extruded_height;
    }
  }]);

  return PolygonEntity;
}(Entity);
/**
 * @summary PolygonEntity の PrimitiveProducer
 *
 * @private
 */


var PrimitiveProducer$4 =
/*#__PURE__*/
function (_Entity$PrimitiveProd) {
  _inherits(PrimitiveProducer, _Entity$PrimitiveProd);

  /**
   * @param {mapray.PolygonEntity} entity
   */
  function PrimitiveProducer(entity) {
    var _this2;

    _classCallCheck(this, PrimitiveProducer);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(PrimitiveProducer).call(this, entity));
    _this2._status = Status$2.INVALID;
    _this2._triangles = null; // 三角形リスト (Uint32Array)
    // プリミティブの要素

    _this2._transform = GeoMath.setIdentity(GeoMath.createMatrix());
    _this2._pivot = GeoMath.createVector3();
    _this2._bbox = [GeoMath.createVector3(), GeoMath.createVector3()];
    _this2._properties = {
      color: GeoMath.createVector3f(),
      opacity: 1.0,
      lighting: false
    }; // プリミティブ

    var primitive = new Primitive(entity.glenv, null, entity._getPolygonMaterial(), _this2._transform);
    primitive.pivot = _this2._pivot;
    primitive.bbox = _this2._bbox;
    primitive.properties = _this2._properties;
    _this2._primitive = primitive;
    return _this2;
  }
  /**
   * @override
   */


  _createClass(PrimitiveProducer, [{
    key: "needsElevation",
    value: function needsElevation() {
      var owner = this.entity;
      return owner.altitude_mode !== AltitudeMode.ABSOLUTE;
    }
    /**
     * @override
     */

  }, {
    key: "createRegions",
    value: function createRegions() {
      var owner = this.entity;

      if (this._status === Status$2.INVALID) {
        // 多角形なし、または三角形に変換できなかったとき
        return [];
      } // 正常な多角形のとき


      var region = new EntityRegion();
      var _iteratorNormalCompletion7 = true;
      var _didIteratorError7 = false;
      var _iteratorError7 = undefined;

      try {
        for (var _iterator7 = owner._boundaries[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
          var bo = _step7.value;
          region.addPoints(bo.points, 0, 3, bo.num_points);
        }
      } catch (err) {
        _didIteratorError7 = true;
        _iteratorError7 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion7 && _iterator7["return"] != null) {
            _iterator7["return"]();
          }
        } finally {
          if (_didIteratorError7) {
            throw _iteratorError7;
          }
        }
      }

      region.addPoint(owner._getPosition());
      return [region];
    }
    /**
     * @override
     */

  }, {
    key: "onChangeElevation",
    value: function onChangeElevation(regions) {
      if (this._status === Status$2.NORMAL) {
        this._status = Status$2.MESH_DIRTY;
      }
    }
    /**
     * @override
     */

  }, {
    key: "getPrimitives",
    value: function getPrimitives(stage) {
      if (this._status === Status$2.INVALID) {
        // 多角形なし、または三角形に変換できなかったとき
        return [];
      } else if (this._status === Status$2.TRIANGLE_DIRTY) {
        this._triangles = this.entity._createTriangles();

        if (this._triangles === null) {
          // 多角形の三角形化に失敗
          this._primitive.mesh = null;
          this._status = Status$2.INVALID;
          return [];
        }

        this._updatePrimitiveMesh();
      } else if (this._status === Status$2.MESH_DIRTY) {
        this._updatePrimitiveMesh();
      }

      this._updatePrimitiveProperties();

      this._status = Status$2.NORMAL;
      return [this._primitive];
    }
    /**
     * @summary 押し出しモードが変更されたことを通知
     */

  }, {
    key: "onChangeExtruded",
    value: function onChangeExtruded() {
      if (this._status === Status$2.NORMAL) {
        this._status = Status$2.MESH_DIRTY;
      }
    }
    /**
     * @summary プロパティが変更されたことを通知
     */

  }, {
    key: "onChangeProperty",
    value: function onChangeProperty() {} // することなし

    /**
     * @summary 境界が変更されたことを通知
     */

  }, {
    key: "onChangeBoundary",
    value: function onChangeBoundary() {
      this._status = Status$2.TRIANGLE_DIRTY;
      this._triangles = null;
      this.needToCreateRegions();
    }
    /**
     * @summary プリミティブの更新
     *
     * 入力:
     *   this.entity
     *   this._triangles
     * 出力:
     *   this._transform
     *   this._pivot
     *   this._bbox
     *   this._primitive.mesh
     *
     * @private
     */

  }, {
    key: "_updatePrimitiveMesh",
    value: function _updatePrimitiveMesh() {
      var cb_data = new BoundaryConbiner(this.entity); // プリミティブの更新
      //   primitive.transform
      //   primitive.pivot
      //   primitive.bbox

      this._updateTransformPivotBBox(cb_data); // メッシュ生成


      var mesh_data = {
        vtype: [{
          name: "a_position",
          size: 3
        }, {
          name: "a_normal",
          size: 3
        }],
        vertices: this._createVertices(cb_data),
        indices: this._createIndices(cb_data)
      };
      var mesh = new Mesh(this.entity.scene.glenv, mesh_data); // メッシュ設定

      this._primitive.mesh = mesh;
    }
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * <pre>
     * 出力:
     *   this._transform
     *   this._pivot
     *   this._bbox
     * </pre>
     *
     * @param {BoundaryConbiner} cb_data  入力データ
     *
     * @private
     */

  }, {
    key: "_updateTransformPivotBBox",
    value: function _updateTransformPivotBBox(cb_data) {
      // 変換行列の更新
      var transform = this._transform;
      transform[12] = cb_data.origin[0];
      transform[13] = cb_data.origin[1];
      transform[14] = cb_data.origin[2]; // 統計

      var xmin = Number.MAX_VALUE;
      var ymin = Number.MAX_VALUE;
      var zmin = Number.MAX_VALUE;
      var xmax = -Number.MAX_VALUE;
      var ymax = -Number.MAX_VALUE;
      var zmax = -Number.MAX_VALUE; // [cb_data.upper, cb_data.lower]

      var points_array = [cb_data.upper];

      if (cb_data.lower) {
        points_array.push(cb_data.lower);
      }

      for (var j = 0; j < points_array.length; ++j) {
        var points = points_array[j];

        for (var i = 0; i < cb_data.num_points; ++i) {
          var b = 3 * i;
          var x = points[b];
          var y = points[b + 1];
          var z = points[b + 2];

          if (x < xmin) {
            xmin = x;
          }

          if (y < ymin) {
            ymin = y;
          }

          if (z < zmin) {
            zmin = z;
          }

          if (x > xmax) {
            xmax = x;
          }

          if (y > ymax) {
            ymax = y;
          }

          if (z > zmax) {
            zmax = z;
          }
        }
      } // 中心点


      var pivot = this._pivot;
      pivot[0] = (xmin + xmax) / 2;
      pivot[1] = (ymin + ymax) / 2;
      pivot[2] = (zmin + zmax) / 2; // 境界箱

      var bbox = this._bbox;
      var bmin = bbox[0];
      var bmax = bbox[1];
      bmin[0] = xmin;
      bmin[1] = ymin;
      bmin[2] = zmin;
      bmax[0] = xmax;
      bmax[1] = ymax;
      bmax[2] = zmax;
    }
    /**
     * @summary 頂点配列の生成
     *
     * @desc
     * 生成される形式は [Px, Py, Pz, Nx, Ny, Nz, ...] のような形で、それぞれの座標はローカル座標系になる。
     * 配列の頂点データは 2 つの領域で分かれ、上面ポリゴンの頂点配列(S1) → 側面ポリゴンの頂点配列(S2) の順序で格納される。
     * ただし cb_data.lower == null のとき、配列は S1 部分しか設定されない。
     *
     * S1 は cb_data.upper に対応する頂点データが同じ順序で格納される。
     *
     * S2 は cb_data.num_points 個の四角形に対する頂点データが順番に並んでいる。
     * 各四角形の頂点データは 左下、右下、左上、右上 の順序で格納されている。
     *
     * 入力: this.entity._boundaries
     *
     * @param {BoundaryConbiner} cb_data  入力データ
     *
     * @return {Float32Array}  Mesh 用の頂点配列
     *
     * @private
     */

  }, {
    key: "_createVertices",
    value: function _createVertices(cb_data) {
      var fpv = 6; // 1頂点データあたりの float 数

      var s1_num_floats = fpv * cb_data.num_points; // 上面のデータサイズ

      var s2_num_floats = cb_data.lower ? fpv * (4 * cb_data.num_points) : 0; // 側面のデータサイズ

      var s3_num_floats = cb_data.lower ? s1_num_floats : 0; // 底面のデータサイズ

      var vertices = new Float32Array(s1_num_floats + s2_num_floats + s3_num_floats); // 上面の法線を取得

      var unormal = GeoMath.normalize3(cb_data.origin, GeoMath.createVector3()); // 上面の頂点データ

      for (var i = 0; i < cb_data.num_points; ++i) {
        var b = 3 * i;
        var px = cb_data.upper[b];
        var py = cb_data.upper[b + 1];
        var pz = cb_data.upper[b + 2];
        var vi = fpv * i;
        vertices[vi] = px; // a_position.x

        vertices[vi + 1] = py; // a_position.y

        vertices[vi + 2] = pz; // a_position.z

        setVec3ToArray(unormal, vertices, vi + 3); // a_normal
      } // 側面の頂点データ


      if (cb_data.lower) {
        var p00 = GeoMath.createVector3(); // 左下位置

        var p10 = GeoMath.createVector3(); // 右下位置

        var p01 = GeoMath.createVector3(); // 左上位置

        var p11 = GeoMath.createVector3(); // 右上位置

        var snormal = GeoMath.createVector3(); // 側面の法線

        var beg_i = 0; // bo の最初の頂点のインデックス

        var _iteratorNormalCompletion8 = true;
        var _didIteratorError8 = false;
        var _iteratorError8 = undefined;

        try {
          for (var _iterator8 = this.entity._boundaries[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
            var bo = _step8.value;
            var end_i = beg_i + bo.num_points; // bo の最後の頂点のインデックス + 1

            for (var _i = beg_i; _i < end_i; ++_i) {
              var i0 = _i;
              var i1 = _i + 1 < end_i ? _i + 1 : beg_i; // 四隅の位置を取得

              var b0 = 3 * i0;
              var b1 = 3 * i1;
              setArrayToVec3(cb_data.lower, b0, p00);
              setArrayToVec3(cb_data.lower, b1, p10);
              setArrayToVec3(cb_data.upper, b0, p01);
              setArrayToVec3(cb_data.upper, b1, p11); // 側面の法線を取得

              setTriangleNormal(p00, p10, p01, snormal); // 四隅の頂点データを設定

              var _vi = s1_num_floats + 4 * fpv * _i;

              setVec3ToArray(p00, vertices, _vi); // a_position

              setVec3ToArray(snormal, vertices, _vi + 3); // a_normal

              _vi += fpv;
              setVec3ToArray(p10, vertices, _vi); // a_position

              setVec3ToArray(snormal, vertices, _vi + 3); // a_normal

              _vi += fpv;
              setVec3ToArray(p01, vertices, _vi); // a_position

              setVec3ToArray(snormal, vertices, _vi + 3); // a_normal

              _vi += fpv;
              setVec3ToArray(p11, vertices, _vi); // a_position

              setVec3ToArray(snormal, vertices, _vi + 3); // a_normal
            }

            beg_i = end_i;
          }
        } catch (err) {
          _didIteratorError8 = true;
          _iteratorError8 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion8 && _iterator8["return"] != null) {
              _iterator8["return"]();
            }
          } finally {
            if (_didIteratorError8) {
              throw _iteratorError8;
            }
          }
        }
      }

      if (cb_data.lower) {
        var bnormal = GeoMath.scale3(-1.0, unormal, GeoMath.createVector3()); // 底面の頂点データ

        for (var _i2 = 0; _i2 < cb_data.num_points; ++_i2) {
          var _b = 3 * _i2;

          var _px = cb_data.lower[_b];
          var _py = cb_data.lower[_b + 1];
          var _pz = cb_data.lower[_b + 2];

          var _vi2 = s1_num_floats + s2_num_floats + fpv * _i2;

          vertices[_vi2] = _px; // a_position.x

          vertices[_vi2 + 1] = _py; // a_position.y

          vertices[_vi2 + 2] = _pz; // a_position.z

          setVec3ToArray(bnormal, vertices, _vi2 + 3); // a_normal
        }
      }

      return vertices;
    }
    /**
     * @summary インデックス配列の生成
     *
     * 入力: this._triangles
     *
     * @param {BoundaryConbiner} cb_data  入力データ
     *
     * @return {Uint32Array}  インデックス配列
     *
     * @private
     */

  }, {
    key: "_createIndices",
    value: function _createIndices(cb_data) {
      // 頂点の並びは _createVertices() を参照
      var num_upper_triangles = this._triangles.length / 3;
      var num_side_triangles = cb_data.lower ? 2 * cb_data.num_points : 0;
      var num_bottom_triangles = cb_data.lower ? num_upper_triangles : 0;
      var indices = new Uint32Array(3 * (num_upper_triangles + num_side_triangles + num_bottom_triangles)); // 前半に上面のポリゴンを設定

      indices.set(this._triangles); // 側面のポリゴンを設定

      if (cb_data.lower) {
        var num_quads = cb_data.num_points;
        var ioffset = 3 * num_upper_triangles; // indices 内の現在の四角形のオフセット

        var voffset = cb_data.num_points; // 頂点配列内の現在の四角形のオフセット

        for (var i = 0; i < num_quads; ++i, ioffset += 6, voffset += 4) {
          // 左下三角形
          indices[ioffset] = voffset;
          indices[ioffset + 1] = voffset + 1;
          indices[ioffset + 2] = voffset + 2; // 右上三角形

          indices[ioffset + 3] = voffset + 2;
          indices[ioffset + 4] = voffset + 1;
          indices[ioffset + 5] = voffset + 3;
        }
      } // 底面のポリゴンを設定


      if (cb_data.lower) {
        var len = this._triangles.length / 3;

        var _voffset = cb_data.num_points + 4 * cb_data.num_points;

        for (var _i3 = 0; _i3 < len; ++_i3) {
          indices[(num_upper_triangles + num_side_triangles + _i3) * 3 + 0] = this._triangles[_i3 * 3 + 0] + _voffset;
          indices[(num_upper_triangles + num_side_triangles + _i3) * 3 + 1] = this._triangles[_i3 * 3 + 2] + _voffset;
          indices[(num_upper_triangles + num_side_triangles + _i3) * 3 + 2] = this._triangles[_i3 * 3 + 1] + _voffset;
        }
      }

      return indices;
    }
    /**
     * @summary プリミティブのプロパティを更新
     *
     * 入力: this.entity
     * 出力: this._properties
     *
     * @private
     */

  }, {
    key: "_updatePrimitiveProperties",
    value: function _updatePrimitiveProperties() {
      var owner = this.entity;
      var props = this._properties;
      GeoMath.copyVector3(owner._color, props.color);
      props.opacity = owner._opacity;
      props.lighting = this.extruded_height !== 0.0;
    }
  }]);

  return PrimitiveProducer;
}(Entity.PrimitiveProducer);
/**
 * @summary PolygonEntity の FlakePrimitiveProducer
 *
 * @private
 */


var FlakePrimitiveProducer$2 =
/*#__PURE__*/
function (_Entity$FlakePrimitiv) {
  _inherits(FlakePrimitiveProducer, _Entity$FlakePrimitiv);

  /**
   * @param {mapray.PolygonEntity} entity
   */
  function FlakePrimitiveProducer(entity) {
    var _this3;

    _classCallCheck(this, FlakePrimitiveProducer);

    _this3 = _possibleConstructorReturn(this, _getPrototypeOf(FlakePrimitiveProducer).call(this, entity));
    _this3._material = entity._getPolygonMaterial();
    _this3._properties = null;
    _this3._area_manager = new PolygonAreaManager(entity);
    return _this3;
  }
  /**
   * @override
   */


  _createClass(FlakePrimitiveProducer, [{
    key: "getAreaStatus",
    value: function getAreaStatus(area) {
      return this._area_manager.getAreaStatus(area);
    }
    /**
     * @override
     */

  }, {
    key: "createMesh",
    value: function createMesh(area, dpows, dem) {
      // ConvexPolygon の配列、または Entity.AreaStatus.FULL
      var polygons = this._area_manager.getAreaContent(area);

      var msize = Math.PI * Math.pow(2, 1 - area.z);
      var x_min = area.x * msize - Math.PI;
      var y_min = Math.PI - (area.y + 1) * msize;
      var div_x = 1 << dpows[0];
      var div_y = 1 << dpows[1]; // サブメッシュの配列を生成

      var submeshes = this._createSubmeshes(x_min, y_min, x_min + msize, y_min + msize, div_x, div_y, polygons); // メッシュ生成


      var mesh_data = {
        vtype: [{
          name: "a_position",
          size: 3
        }, {
          name: "a_normal",
          size: 3
        }],
        vertices: this._createVertices(submeshes, area, dem),
        indices: this._createIndices(submeshes)
      };
      return new Mesh(this.entity.scene.glenv, mesh_data);
    }
    /**
     * @override
     */

  }, {
    key: "getMaterialAndProperties",
    value: function getMaterialAndProperties(stage) {
      if (this._properties === null) {
        var entity = this.entity;
        this._properties = {
          color: GeoMath.createVector3f(entity._color),
          opacity: entity._opacity,
          lighting: false
        };
      }

      return {
        material: this._material,
        properties: this._properties
      };
    }
    /**
     * @summary 押し出しモードが変更されたことを通知
     */

  }, {
    key: "onChangeExtruded",
    value: function onChangeExtruded() {} // flake_mode なので押し出しモードは関係ない

    /**
     * @summary プロパティが変更されたことを通知
     */

  }, {
    key: "onChangeProperty",
    value: function onChangeProperty() {
      this._properties = null;
    }
    /**
     * @summary 境界が変更されたことを通知
     */

  }, {
    key: "onChangeBoundary",
    value: function onChangeBoundary() {
      this._area_manager.notifyForUpdateContent();

      this.notifyForUpdate();
    }
    /**
     * @summary 頂点配列を生成
     *
     * @param {iterable.<Submesh>} submeshes
     * @param {mapray.Area}        area
     * @param {mapray.DemBinary}   dem
     *
     * @return {Float32Array}
     *
     * @private
     */

  }, {
    key: "_createVertices",
    value: function _createVertices(submeshes, area, dem) {
      var origin = AreaUtil.getCenter(area, GeoMath.createVector3());
      var sampler = dem.newSampler(area); // 頂点配列を生成

      var num_vertices = 0;
      var _iteratorNormalCompletion9 = true;
      var _didIteratorError9 = false;
      var _iteratorError9 = undefined;

      try {
        for (var _iterator9 = submeshes[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
          var smesh = _step9.value;
          num_vertices += smesh.getNumVertices();
        }
      } catch (err) {
        _didIteratorError9 = true;
        _iteratorError9 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion9 && _iterator9["return"] != null) {
            _iterator9["return"]();
          }
        } finally {
          if (_didIteratorError9) {
            throw _iteratorError9;
          }
        }
      }

      var vertices = new Float32Array(6 * num_vertices); // 頂点配列に座標を書き込む

      var offset = 0;
      var _iteratorNormalCompletion10 = true;
      var _didIteratorError10 = false;
      var _iteratorError10 = undefined;

      try {
        for (var _iterator10 = submeshes[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
          var _smesh = _step10.value;
          offset = _smesh.addVertices(origin, sampler, vertices, offset);
        }
      } catch (err) {
        _didIteratorError10 = true;
        _iteratorError10 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion10 && _iterator10["return"] != null) {
            _iterator10["return"]();
          }
        } finally {
          if (_didIteratorError10) {
            throw _iteratorError10;
          }
        }
      }

      return vertices;
    }
    /**
     * @summary インデックス配列を生成
     *
     * @param {iterable.<Submesh>} submeshes
     *
     * @return {Uint32Array}
     *
     * @private
     */

  }, {
    key: "_createIndices",
    value: function _createIndices(submeshes) {
      // インデックス配列を生成
      var num_triangles = 0;
      var _iteratorNormalCompletion11 = true;
      var _didIteratorError11 = false;
      var _iteratorError11 = undefined;

      try {
        for (var _iterator11 = submeshes[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
          var smesh = _step11.value;
          num_triangles += smesh.getNumTriangles();
        }
      } catch (err) {
        _didIteratorError11 = true;
        _iteratorError11 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion11 && _iterator11["return"] != null) {
            _iterator11["return"]();
          }
        } finally {
          if (_didIteratorError11) {
            throw _iteratorError11;
          }
        }
      }

      var indices = new Uint32Array(3 * num_triangles); // インデックス配列にインデックスを書き込む

      var voffset = 0;
      var ioffset = 0;
      var _iteratorNormalCompletion12 = true;
      var _didIteratorError12 = false;
      var _iteratorError12 = undefined;

      try {
        for (var _iterator12 = submeshes[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
          var _smesh2 = _step12.value;
          ioffset = _smesh2.addIndices(voffset, indices, ioffset);
          voffset += _smesh2.getNumVertices();
        }
      } catch (err) {
        _didIteratorError12 = true;
        _iteratorError12 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion12 && _iterator12["return"] != null) {
            _iterator12["return"]();
          }
        } finally {
          if (_didIteratorError12) {
            throw _iteratorError12;
          }
        }
      }

      return indices;
    }
    /**
     * @summary サブメッシュの配列を生成
     *
     * <p>polygons は領域と交差する ConvexPolygon の配列である。ただし領域が多角形で覆われているときは
     * Entity.AreaStatus.FULL になる場合がある。</p>
     *
     * @param {number} x_min  領域の最小 x 座標
     * @param {number} y_min  領域の最小 y 座標
     * @param {number} x_max  領域の最大 x 座標
     * @param {number} y_max  領域の最大 y 座標
     * @param {number} div_x  領域の x 方向の分割数
     * @param {number} div_y  領域の y 方向の分割数
     * @param {iterable.<mapray.ConvexPolygon>|mapray.Entity.AreaStatus} polygons
     *
     * @return {iterable.<Submesh>}  サブメッシュの配列
     *
     * @private
     */

  }, {
    key: "_createSubmeshes",
    value: function _createSubmeshes(x_min, y_min, x_max, y_max, div_x, div_y, polygons) {
      if (polygons === Entity.AreaStatus.FULL) {
        // 領域内は多角形に覆われている
        return [new RectSubmesh(x_min, y_min, x_max, y_max, div_x, div_y)];
      } else if (polygons.length == 0) {
        // 領域内に多角形は無い
        return [];
      } else if (div_x == 1 && div_y == 1) {
        // これ以上分割できないので切り取り多角形を返す
        var t1 = [x_min, y_min, x_max, y_min, x_min, y_max]; // 左下三角形

        var t2 = [x_min, y_max, x_max, y_min, x_max, y_max]; // 右上三角形

        var m1 = this._create_clipped_polygons_submeshes(t1, polygons);

        var m2 = this._create_clipped_polygons_submeshes(t2, polygons);

        return m1.concat(m2);
      } else {
        if (div_x >= div_y) {
          // 左右分割
          var msize = (x_max - x_min) / 2;
          var div_w = div_x / 2;

          var _m = this._create_submeshes_sp(x_min, y_min, x_min + msize, y_max, div_w, div_y, polygons);

          var _m2 = this._create_submeshes_sp(x_min + msize, y_min, x_max, y_max, div_w, div_y, polygons);

          return _m.concat(_m2);
        } else {
          // 上下分割
          var _msize = (y_max - y_min) / 2;

          var _div_w = div_y / 2;

          var _m3 = this._create_submeshes_sp(x_min, y_min, x_max, y_min + _msize, div_x, _div_w, polygons);

          var _m4 = this._create_submeshes_sp(x_min, y_min + _msize, x_max, y_max, div_x, _div_w, polygons);

          return _m3.concat(_m4);
        }
      }
    }
    /**
     * @summary サブメッシュの配列を生成
     *
     * @desc
     * <p>_createSubmeshes() との違いは polygons に Entity.AreaStatus.FULL を指定できない。
     * また、polygons には領域の外側の多角形が含まれている可能性がある。</p>
     *
     * @param {number} x_min  領域の最小 x 座標
     * @param {number} y_min  領域の最小 y 座標
     * @param {number} x_max  領域の最大 x 座標
     * @param {number} y_max  領域の最大 y 座標
     * @param {number} div_x  領域の x 方向の分割数
     * @param {number} div_y  領域の y 方向の分割数
     * @param {iterable.<mapray.ConvexPolygon>} polygons
     *
     * @return {Submesh[]}  サブメッシュの配列
     *
     * @private
     */

  }, {
    key: "_create_submeshes_sp",
    value: function _create_submeshes_sp(x_min, y_min, x_max, y_max, div_x, div_y, polygons) {
      // 領域を凸多角形に変換
      var area_rect = ConvexPolygon.createByRectangle(x_min, y_min, x_max, y_max);
      var selected_polygons = [];
      var _iteratorNormalCompletion13 = true;
      var _didIteratorError13 = false;
      var _iteratorError13 = undefined;

      try {
        for (var _iterator13 = polygons[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
          var polygon = _step13.value;

          if (polygon.includes(area_rect)) {
            // polygon は area_rect を覆う
            // つまり area_rect は全体の多角形に覆われている
            selected_polygons = Entity.AreaStatus.FULL;
            break;
          }

          try {
            if (area_rect.hasIntersection(polygon)) {
              // 領域と交差しているので polygon 追加
              selected_polygons.push(polygon);
            }
          } catch (e) {// polygon の交差判定に失敗したときは polygon は無いことにする
          }
        }
      } catch (err) {
        _didIteratorError13 = true;
        _iteratorError13 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion13 && _iterator13["return"] != null) {
            _iterator13["return"]();
          }
        } finally {
          if (_didIteratorError13) {
            throw _iteratorError13;
          }
        }
      }

      return this._createSubmeshes(x_min, y_min, x_max, y_max, div_x, div_y, selected_polygons);
    }
    /**
     * @summary 凸多角形のサブメッシュの配列を生成
     *
     * @desc
     * <p>area_triangle の三角形で src_polygons の凸多角形を切り取り、それらの切り取られた凸多角形に対応する
     * PolygonsSubmesh インスタンスの配列を生成する。</p>
     *
     * arit = Area Right Isosceles Triangle (領域直角二等辺三角形)
     *
     * @param {number[]}                        arit_coords   領域の三角形座標配列 (左下または右上の三角形)
     * @param {iterable.<mapray.ConvexPolygon>} src_polygons  切り取り対象の凸多角形の配列
     *
     * @return {PolygonsSubmesh[]}  PolygonsSubmesh の配列
     *
     * @private
     */

  }, {
    key: "_create_clipped_polygons_submeshes",
    value: function _create_clipped_polygons_submeshes(arit_coords, src_polygons) {
      var area_polygon = new ConvexPolygon(arit_coords);
      var clipped_polygons = [];
      var _iteratorNormalCompletion14 = true;
      var _didIteratorError14 = false;
      var _iteratorError14 = undefined;

      try {
        for (var _iterator14 = src_polygons[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
          var polygon = _step14.value;

          try {
            var clipped = area_polygon.getIntersection(polygon);

            if (clipped !== null) {
              clipped_polygons.push(clipped);
            }
          } catch (e) {// polygon の切り抜きに失敗したときは polygon の切り抜きは返さない
          }
        }
      } catch (err) {
        _didIteratorError14 = true;
        _iteratorError14 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion14 && _iterator14["return"] != null) {
            _iterator14["return"]();
          }
        } finally {
          if (_didIteratorError14) {
            throw _iteratorError14;
          }
        }
      }

      if (clipped_polygons.length > 0) {
        return [new PolygonsSubmesh(arit_coords, clipped_polygons)];
      } else {
        return [];
      }
    }
  }]);

  return FlakePrimitiveProducer;
}(Entity.FlakePrimitiveProducer);
/**
 * @summary 多角形の境界
 *
 * @classdesc
 * <p>多角形の1つの境界を表現する。</p>
 * <p>外側境界のときは反時計回り、内側境界のときは時計回りで格納される。</p>
 *
 * @private
 */


var Boundary =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>points は addOuterBoundary(), addInnerBoundary() と同じ形式である。</p>
   *
   * @param {number[]} points    境界の頂点データ
   * @param {boolean}  is_inner  内側境界か?
   */
  function Boundary(points, is_inner) {
    _classCallCheck(this, Boundary);

    var num_points = Math.floor(points.length / 3);
    this._points = new Float64Array(3 * num_points);
    this._num_points = num_points;
    var is_ccw = Boundary.isCCW(points, num_points);
    var si;
    var si_step;

    if (!is_inner && is_ccw || is_inner && !is_ccw) {
      // 順方向
      si = 0;
      si_step = 3;
    } else {
      // 逆方向
      si = 3 * (num_points - 1);
      si_step = -3;
    } // 内部の配列にコピー


    for (var i = 0; i < num_points; ++i) {
      this._points[3 * i] = points[si];
      this._points[3 * i + 1] = points[si + 1];
      this._points[3 * i + 2] = points[si + 2];
      si += si_step;
    }
  }
  /**
   * @summary 頂点座標の配列
   * @type {number[]}
   * @readonly
   */


  _createClass(Boundary, [{
    key: "points",
    get: function get() {
      return this._points;
    }
    /**
     * @summary 頂点数
     * @type {number}
     * @readonly
     */

  }, {
    key: "num_points",
    get: function get() {
      return this._num_points;
    }
    /**
     * @summary 境界は反時計回りか?
     *
     * @param {number[]} points  境界の頂点データ
     *
     * @return {boolean}  反時計回りのとき true, それ以外のとき false
     */

  }], [{
    key: "isCCW",
    value: function isCCW(points, num_points) {
      // 頂上の点、同じ高さなら左側優先
      var top_i;
      var top_x = -Number.MAX_VALUE;
      var top_y = -Number.MAX_VALUE;

      for (var i = 0; i < num_points; ++i) {
        var x = points[3 * i];
        var y = points[3 * i + 1];

        if (y > top_y || y == top_y && x < top_x) {
          top_i = i;
          top_x = x;
          top_y = y;
        }
      } // top の前方の点


      var next_i = top_i == num_points - 1 ? 0 : top_i + 1;
      var next_x = points[3 * next_i];
      var next_y = points[3 * next_i + 1]; // top の後方の点

      var prev_i = top_i == 0 ? num_points - 1 : top_i - 1;
      var prev_x = points[3 * prev_i];
      var prev_y = points[3 * prev_i + 1]; // prev と next は top より下または同じ高さだが、少なくともどちらか一方は top より下になる
      // またエッジは交差しないことが前提なので、2 つのエッジの内角は 0 度より大きく 180 度未満になる
      // したがって a, b の行列式が正のとき反時計回り、それ以外のとき時計回り

      var ax = next_x - top_x;
      var ay = next_y - top_y;
      var bx = prev_x - top_x;
      var by = prev_y - top_y;
      return ax * by - bx * ay > 0;
    }
  }]);

  return Boundary;
}();
/**
 * @summary 境界線データを結合
 *
 * @classdesc
 * <p>pe._bounaries に対応する上頂点と底頂点の LOCS 平坦化配列を取得する。</p>
 * <p>pe._extruded_height === 0 のときは lower に null を設定する。</p>
 *
 * <pre>
 * プロパティ:
 *   origin: Vector3       // LOCS の原点位置 (GOCS)
 *   num_points: number    // upper の頂点数
 *   upper: Float64Array   // 上頂点 (LOCS, 順序は pe._bounaries.points の連結)
 *   lower: Float64Array   // 底頂点 (LOCS, 順序は upper と同じ, nullable)
 * </pre>
 *
 * @private
 */


var BoundaryConbiner =
/**
 * @desc
 * <pre>
 * 入力:
 *   pe.viewer
 *   pe.altitude_mode
 *   pe._extruded_height
 *   pe._bounaries
 * </pre>
 *
 * @param {mapray.PolygonEntity} pe  呼び出し側のポリゴンエンティティ
 */
function BoundaryConbiner(pe) {
  _classCallCheck(this, BoundaryConbiner);

  /*
  pe._extruded_height !== 0             == 0

              ---  _.-*---*._        _.-*---*._
  upper_points    *-_      _-*      *-_      _-*
              --- |  *----*  |         *----*
                  |  |    |  |
              --- |  |    |  |
  lower_points    *-_|    |_-*         (null)
              ---    *----*
  */
  var viewer = pe.scene.viewer;
  var altitude_mode = pe.altitude_mode;

  var src_points = pe._getCombinedBoundaryPoints();

  var num_points = pe._countNumPointsOnBoundaries();

  var base_points = Float64Array.from(src_points);

  if (altitude_mode === AltitudeMode.RELATIVE) {
    var elevation = viewer.getExistingElevation(pe._getPosition());

    for (var i = 0; i < num_points; ++i) {
      var ai = 3 * i + 2;
      base_points[ai] += elevation;
    }
  }

  var upper_points = null;
  var lower_points = null;

  if (pe._extruded_height !== 0) {
    if (altitude_mode === AltitudeMode.CLAMP) {
      upper_points = base_points;
      lower_points = Float64Array.from(src_points);

      for (var _i4 = 0; _i4 < num_points; ++_i4) {
        var _ai = 3 * _i4 + 2;

        lower_points[_ai] = 0;
      }
    } else {
      // altitude_mode !== AltitudeMode.ABSOLUTE || altitude_mode !== AltitudeMode.RELATIVE
      lower_points = base_points;
      upper_points = Float64Array.from(src_points);

      for (var _i5 = 0; _i5 < num_points; ++_i5) {
        var _ai2 = 3 * _i5 + 2;

        upper_points[_ai2] = lower_points[_ai2] + pe._extruded_height;
      }
    }
  } else {
    upper_points = base_points;
  }

  var origin = pe._getPosition().getAsGocs(GeoMath.createVector3()); // LOCS 平坦化配列


  var upper_ocs_points = GeoPoint.toGocsArray(upper_points, num_points, new Float64Array(3 * num_points));

  for (var _i6 = 0; _i6 < num_points; ++_i6) {
    var d = 3 * _i6;
    upper_ocs_points[d] -= origin[0];
    upper_ocs_points[d + 1] -= origin[1];
    upper_ocs_points[d + 2] -= origin[2];
  }

  var lower_ocs_points = null;

  if (lower_points) {
    // ASSERT: lower_points != null
    lower_ocs_points = GeoPoint.toGocsArray(lower_points, num_points, new Float64Array(3 * num_points));

    for (var _i7 = 0; _i7 < num_points; ++_i7) {
      var _d = 3 * _i7;

      lower_ocs_points[_d] -= origin[0];
      lower_ocs_points[_d + 1] -= origin[1];
      lower_ocs_points[_d + 2] -= origin[2];
    }
  } // プロパティを設定


  this.origin = origin;
  this.num_points = num_points;
  this.upper = upper_ocs_points;
  this.lower = lower_ocs_points;
};
/**
 * @summary 多角形の領域管理
 *
 * @private
 */


var PolygonAreaManager =
/*#__PURE__*/
function (_QAreaManager) {
  _inherits(PolygonAreaManager, _QAreaManager);

  /**
   * @param {mapray.PolygonEntity} entity  管理対象のエンティティ
   */
  function PolygonAreaManager(entity) {
    var _this4;

    _classCallCheck(this, PolygonAreaManager);

    _this4 = _possibleConstructorReturn(this, _getPrototypeOf(PolygonAreaManager).call(this));
    _this4._entity = entity;
    return _this4;
  }
  /**
   * @override
   */


  _createClass(PolygonAreaManager, [{
    key: "getInitialContent",
    value: function getInitialContent() {
      var src_indices = this._entity._createTriangles() || [];
      var num_src_indices = src_indices.length;

      var src_coords = this._entity._getCombinedBoundary2DPoints();

      var content = []; // ConvexPolygon の配列

      for (var _si = 0; _si < num_src_indices; _si += 3) {
        var i0 = src_indices[_si];
        var i1 = src_indices[_si + 1];
        var i2 = src_indices[_si + 2];

        this._add_polygon_to_array(src_coords, i0, i1, i2, content);
      }

      return content;
    }
    /**
     * @override
     */

  }, {
    key: "createAreaContent",
    value: function createAreaContent(min_x, min_y, msize, parent_content) {
      // 単位球メルカトルでの領域に変換
      var x_area_min = Math.PI * min_x;
      var y_area_min = Math.PI * min_y;
      var x_area_max = Math.PI * (min_x + msize);
      var y_area_max = Math.PI * (min_y + msize); // 領域を凸多角形に変換

      var area_rect = ConvexPolygon.createByRectangle(x_area_min, y_area_min, x_area_max, y_area_max);
      var content = []; // ConvexPolygon の配列

      var _iteratorNormalCompletion15 = true;
      var _didIteratorError15 = false;
      var _iteratorError15 = undefined;

      try {
        for (var _iterator15 = parent_content[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) {
          var polygon = _step15.value;

          if (polygon.includes(area_rect)) {
            // polygon は area_rect を覆う
            // つまり area_rect は全体の多角形に覆われている
            return Entity.AreaStatus.FULL;
          }

          try {
            if (area_rect.hasIntersection(polygon)) {
              // 領域と交差しているので polygon 追加
              content.push(polygon);
            }
          } catch (e) {// polygon の交差判定に失敗したときは polygon は無いことにする
          }
        }
      } catch (err) {
        _didIteratorError15 = true;
        _iteratorError15 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion15 && _iterator15["return"] != null) {
            _iterator15["return"]();
          }
        } finally {
          if (_didIteratorError15) {
            throw _iteratorError15;
          }
        }
      }

      return content.length > 0 ? content : Entity.AreaStatus.EMPTY;
    }
    /**
     * @summary 三角形を凸多角形として追加
     *
     * @param {number[]} src_coords  入力頂点の座標配列 (経緯度)
     * @param {number}   si0         三角形の頂点 0
     * @param {number}   si1         三角形の頂点 1
     * @param {number}   si2         三角形の頂点 2
     * @param {mapray.ConvexPolygon[]} dst_polygons  出力先の ConvexPolygon 配列
     *
     * @private
     */

  }, {
    key: "_add_polygon_to_array",
    value: function _add_polygon_to_array(src_coords, si0, si1, si2, dst_polygons) {
      var Degree = GeoMath.DEGREE;
      var RAngle = Math.PI / 2; // 直角

      var TwoPI = 2 * Math.PI; // 2π
      // 三角形の頂点座標配列 (単位球メルカトル座標系) を作成

      var vertices = [];
      var mx_min_1 = Number.MAX_VALUE; // オフセット処理前の最小 mx 座標

      for (var _i8 = 0, _arr = [si0, si1, si2]; _i8 < _arr.length; _i8++) {
        var _si2 = _arr[_i8];
        var lon = src_coords[2 * _si2] * Degree;
        var lat = src_coords[2 * _si2 + 1] * Degree;

        if (Math.abs(lat) >= RAngle) {
          // 緯度の絶対値が RAngle 以上の頂点が存在する三角形は除外
          // ※ まだ検討していないので、とりあえずの処置
          return;
        }

        var mx = lon;
        var my = GeoMath.invGudermannian(lat);
        vertices.push(mx);
        vertices.push(my);
        mx_min_1 = Math.min(mx, mx_min_1);
      } // mx_min_2: mx 座標が mx_min_1 だった頂点のオフセット後の mx 座標


      var mx_min_2 = mx_min_1 - TwoPI * (Math.floor((mx_min_1 - Math.PI) / TwoPI) + 1);

      if (mx_min_2 < -Math.PI || mx_min_2 >= Math.PI) {
        // 数値計算誤差により稀に区間からはみ出る可能性があるので
        mx_min_2 = -Math.PI;
      } // Assert: -Math.PI <= mx_min_2 < Math.PI
      // mx 座標にオフセットを適用


      var mx_max_2 = -Number.MAX_VALUE; // オフセット後の最大 mx 座標

      for (var i = 0; i < 3; ++i) {
        var ix = 2 * i;
        var mx_1 = vertices[ix]; // オフセット前の mx 座標
        // mx_2: オフセット後の mx 座標

        var dx_1 = mx_1 - mx_min_1; // Assert: dx_1 >= 0

        var mx_2 = mx_min_2 + dx_1; // Assert: mx_2 >= mx_min_2
        // Assert: (mx_1 == mx_min_1) ⇒ (mx_2 == mx_min_2)

        vertices[ix] = mx_2;
        mx_max_2 = Math.max(mx_2, mx_max_2);
      } // オフセットを適用した三角形を加える


      dst_polygons.push(new ConvexPolygon(vertices)); // 三角形が 180 度子午線をまたぐとき
      // 360 度左にずらした三角形をもう1つ加える

      if (mx_max_2 > Math.PI) {
        for (var _i9 = 0; _i9 < 3; ++_i9) {
          var _ix = 2 * _i9;

          var _mx_ = vertices[_ix]; // オフセット後の mx 座標

          var mx_3 = _mx_ - TwoPI; // 360 度左にずらした mx 座標

          vertices[_ix] = mx_3;
        }

        dst_polygons.push(new ConvexPolygon(vertices));
      }
    }
  }]);

  return PolygonAreaManager;
}(QAreaManager);
/**
 * @summary サブメッシュ
 *
 * @private
 */


var Submesh =
/*#__PURE__*/
function () {
  /**
   */
  function Submesh() {
    _classCallCheck(this, Submesh);
  }
  /**
   * @summary 頂点数を取得
   *
   * @return {number}  頂点数
   *
   * @abstract
   */


  _createClass(Submesh, [{
    key: "getNumVertices",
    value: function getNumVertices() {
      throw "";
    }
    /**
     * @summary 三角形数を取得
     *
     * @return {number}  三角形数
     *
     * @abstract
     */

  }, {
    key: "getNumTriangles",
    value: function getNumTriangles() {
      throw "";
    }
    /**
     * @summary 頂点配列に頂点データを書き込む
     *
     * @param {mapray.Vector3} origin    座標系の原点 (GOCS)
     * @param {mapray.Sampler} sampler   DEM サンプラー
     * @param {number[]}       vertices  書き込み先の配列
     * @param {number}         offset    書き込み開始インデックス
     *
     * @return {number}  offset + 書き込んだ要素数
     *
     * @abstract
     */

  }, {
    key: "addVertices",
    value: function addVertices(origin, sampler, vertices, offset) {
      throw "";
    }
    /**
     * @summary インデックス配列にインデックスを書き込む
     *
     * @param {number}   voffset  this 用頂点の先頭の頂点インデックス
     * @param {number[]} indices  書き込み先の配列
     * @param {number}   ioffset  書き込み開始インデックス
     *
     * @return {number}  ioffset + 書き込んだ要素数
     *
     * @abstract
     */

  }, {
    key: "addIndices",
    value: function addIndices(voffset, indices, ioffset) {
      throw "";
    }
  }]);

  return Submesh;
}();
/**
 * @summary 矩形サブメッシュ
 *
 * @private
 */


var RectSubmesh =
/*#__PURE__*/
function (_Submesh) {
  _inherits(RectSubmesh, _Submesh);

  /**
   * @param {number} x_min
   * @param {number} y_min
   * @param {number} x_max
   * @param {number} y_max
   * @param {number} div_x
   * @param {number} div_y
   */
  function RectSubmesh(x_min, y_min, x_max, y_max, div_x, div_y) {
    var _this5;

    _classCallCheck(this, RectSubmesh);

    _this5 = _possibleConstructorReturn(this, _getPrototypeOf(RectSubmesh).call(this));
    _this5._x_min = x_min;
    _this5._y_min = y_min;
    _this5._x_max = x_max;
    _this5._y_max = y_max;
    _this5._div_x = div_x;
    _this5._div_y = div_y;
    return _this5;
  }
  /**
   * @override
   */


  _createClass(RectSubmesh, [{
    key: "getNumVertices",
    value: function getNumVertices() {
      return (this._div_x + 1) * (this._div_y + 1);
    }
    /**
     * @override
     */

  }, {
    key: "getNumTriangles",
    value: function getNumTriangles() {
      return 2 * this._div_x * this._div_y;
    }
    /**
     * @override
     */

  }, {
    key: "addVertices",
    value: function addVertices(origin, sampler, vertices, offset) {
      // 刻み幅
      var mx_step = (this._x_max - this._x_min) / this._div_x;
      var my_step = (this._y_max - this._y_min) / this._div_y;
      var end_iu = this._div_x + 1;
      var end_iv = this._div_y + 1;
      var index = offset;

      for (var iv = 0, my = this._y_min; iv < end_iv; ++iv, my += my_step) {
        var ey = Math.exp(my);
        var ey2 = ey * ey;
        var sinφ = (ey2 - 1) / (ey2 + 1);
        var cosφ = 2 * ey / (ey2 + 1);

        for (var iu = 0, mx = this._x_min; iu < end_iu; ++iu, mx += mx_step) {
          var sinλ = Math.sin(mx);
          var cosλ = Math.cos(mx);
          var height = sampler.sample(mx, my);
          var radius = GeoMath.EARTH_RADIUS + height; // 法線 (GOCS)

          var nx = cosφ * cosλ;
          var ny = cosφ * sinλ;
          var nz = sinφ; // 位置 (GOCS)

          var gx = radius * nx;
          var gy = radius * ny;
          var gz = radius * nz;
          vertices[index++] = gx - origin[0]; // x

          vertices[index++] = gy - origin[1]; // y

          vertices[index++] = gz - origin[2]; // z

          vertices[index++] = nx; // nx

          vertices[index++] = ny; // ny

          vertices[index++] = nz; // nz
        }
      }

      return index;
    }
    /**
     * @override
     */

  }, {
    key: "addIndices",
    value: function addIndices(voffset, indices, ioffset) {
      var div_x = this._div_x;
      var div_y = this._div_y;
      var index = ioffset;

      for (var y = 0; y < div_y; ++y) {
        for (var x = 0; x < div_x; ++x) {
          var i00 = voffset + (div_x + 1) * y + x; // 左下頂点

          var i10 = i00 + 1; // 右下頂点

          var i01 = i00 + div_x + 1; // 左上頂点

          var i11 = i01 + 1; // 右上頂点
          // 左下三角形

          indices[index++] = i00;
          indices[index++] = i10;
          indices[index++] = i01; // 右上三角形

          indices[index++] = i01;
          indices[index++] = i10;
          indices[index++] = i11;
        }
      }

      return index;
    }
  }]);

  return RectSubmesh;
}(Submesh);
/**
 * @summary 凸多角形集合サブメッシュ
 *
 * @private
 */


var PolygonsSubmesh =
/*#__PURE__*/
function (_Submesh2) {
  _inherits(PolygonsSubmesh, _Submesh2);

  /**
   * this の生存中はパラメータのオブジェクトを変更しないこと。
   *
   * @param {number[]}                     arit_coords  領域の三角形座標配列 (左下または右上の三角形)
   * @param {iterable.<mapray.ConvexPolygon>} polygons  arit_coords の上にある凸多角形集合
   */
  function PolygonsSubmesh(arit_coords, polygons) {
    var _this6;

    _classCallCheck(this, PolygonsSubmesh);

    _this6 = _possibleConstructorReturn(this, _getPrototypeOf(PolygonsSubmesh).call(this));
    _this6._arit_coords = arit_coords;
    _this6._polygons = polygons;
    _this6._num_vertices = 0;
    _this6._num_triangles = 0;
    var _iteratorNormalCompletion16 = true;
    var _didIteratorError16 = false;
    var _iteratorError16 = undefined;

    try {
      for (var _iterator16 = polygons[Symbol.iterator](), _step16; !(_iteratorNormalCompletion16 = (_step16 = _iterator16.next()).done); _iteratorNormalCompletion16 = true) {
        var polygon = _step16.value;
        _this6._num_vertices += polygon.num_vertices;
        _this6._num_triangles += polygon.num_vertices - 2;
      }
    } catch (err) {
      _didIteratorError16 = true;
      _iteratorError16 = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion16 && _iterator16["return"] != null) {
          _iterator16["return"]();
        }
      } finally {
        if (_didIteratorError16) {
          throw _iteratorError16;
        }
      }
    }

    return _this6;
  }
  /**
   * @override
   */


  _createClass(PolygonsSubmesh, [{
    key: "getNumVertices",
    value: function getNumVertices() {
      return this._num_vertices;
    }
    /**
     * @override
     */

  }, {
    key: "getNumTriangles",
    value: function getNumTriangles() {
      return this._num_triangles;
    }
    /**
     * @override
     */

  }, {
    key: "addVertices",
    value: function addVertices(origin, sampler, vertices, offset) {
      var plane = this._get_elevation_plane(sampler);

      var index = offset;
      var _iteratorNormalCompletion17 = true;
      var _didIteratorError17 = false;
      var _iteratorError17 = undefined;

      try {
        for (var _iterator17 = this._polygons[Symbol.iterator](), _step17; !(_iteratorNormalCompletion17 = (_step17 = _iterator17.next()).done); _iteratorNormalCompletion17 = true) {
          var polygon = _step17.value;
          index = this._add_polygon_vertices(polygon, plane, origin, vertices, index);
        }
      } catch (err) {
        _didIteratorError17 = true;
        _iteratorError17 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion17 && _iterator17["return"] != null) {
            _iterator17["return"]();
          }
        } finally {
          if (_didIteratorError17) {
            throw _iteratorError17;
          }
        }
      }

      return index;
    }
    /**
     * @override
     */

  }, {
    key: "addIndices",
    value: function addIndices(voffset, indices, ioffset) {
      var iofs_next = ioffset;
      var vofs_next = voffset;
      var _iteratorNormalCompletion18 = true;
      var _didIteratorError18 = false;
      var _iteratorError18 = undefined;

      try {
        for (var _iterator18 = this._polygons[Symbol.iterator](), _step18; !(_iteratorNormalCompletion18 = (_step18 = _iterator18.next()).done); _iteratorNormalCompletion18 = true) {
          var polygon = _step18.value;
          iofs_next = this._add_polygon_indices(polygon, vofs_next, indices, iofs_next);
          vofs_next += polygon.num_vertices;
        }
      } catch (err) {
        _didIteratorError18 = true;
        _iteratorError18 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion18 && _iterator18["return"] != null) {
            _iterator18["return"]();
          }
        } finally {
          if (_didIteratorError18) {
            throw _iteratorError18;
          }
        }
      }

      return iofs_next;
    }
    /**
     * @summary 凸多角形の頂点を追加
     *
     * @param {mapray.ConvexPolygon} polygon   凸多角形
     * @param {number[]}             plane     平面係数
     * @param {mapray.Vector3}       origin    座標系の原点 (GOCS)
     * @param {number[]}             vertices  書き込み先の配列
     * @param {number}               offset    書き込み開始インデックス
     *
     * @return {number}  offset + 書き込んだ要素数
     *
     * @private
     */

  }, {
    key: "_add_polygon_vertices",
    value: function _add_polygon_vertices(polygon, plane, origin, vertices, offset) {
      var index = offset;
      var num_vertices = polygon.num_vertices;
      var src_vertices = polygon.vertices;

      for (var vi = 0; vi < num_vertices; ++vi) {
        var mx = src_vertices[2 * vi];
        var my = src_vertices[2 * vi + 1];
        var ey = Math.exp(my);
        var ey2 = ey * ey;
        var sinλ = Math.sin(mx);
        var cosλ = Math.cos(mx);
        var sinφ = (ey2 - 1) / (ey2 + 1);
        var cosφ = 2 * ey / (ey2 + 1); // mx*plane[0] + my*plane[1] + height*plane[2] + plane[3] == 0

        var height = -(mx * plane[0] + my * plane[1] + plane[3]) / plane[2];
        var radius = GeoMath.EARTH_RADIUS + height; // 法線 (GOCS)

        var nx = cosφ * cosλ;
        var ny = cosφ * sinλ;
        var nz = sinφ; // 位置 (GOCS)

        var gx = radius * nx;
        var gy = radius * ny;
        var gz = radius * nz;
        vertices[index++] = gx - origin[0]; // x

        vertices[index++] = gy - origin[1]; // y

        vertices[index++] = gz - origin[2]; // z

        vertices[index++] = nx; // nx

        vertices[index++] = ny; // ny

        vertices[index++] = nz; // nz
      }

      return index;
    }
    /**
     * @summary 凸多角形のインデックスを追加
     *
     * @param {mapray.ConvexPolygon} polygon  凸多角形
     * @param {number}               voffset  this 用頂点の先頭の頂点インデックス
     * @param {number[]}             indices  書き込み先の配列
     * @param {number}               ioffset  書き込み開始インデックス
     *
     * @return {number}  ioffset + 書き込んだ要素数
     *
     * @private
     */

  }, {
    key: "_add_polygon_indices",
    value: function _add_polygon_indices(polygon, voffset, indices, ioffset) {
      var index = ioffset;
      var num_triangles = polygon.num_vertices - 2;

      for (var i = 1; i <= num_triangles; ++i) {
        indices[index++] = voffset;
        indices[index++] = voffset + i;
        indices[index++] = voffset + i + 1;
      }

      return index;
    }
    /**
     * @summary 平面ベースで標高を計算するための係数を取得
     *
     * @param {mapray.Sampler} sampler
     *
     * @return {number[]}  平面係数 [x, y, z, w]
     *
     * @private
     */

  }, {
    key: "_get_elevation_plane",
    value: function _get_elevation_plane(sampler) {
      var coords = this._arit_coords; // 三角形の頂点の高さを取得

      var z_coords = new Array(3);

      for (var i = 0; i < 3; ++i) {
        var mx = coords[2 * i];
        var my = coords[2 * i + 1];
        z_coords[i] = sampler.sample(mx, my);
      }

      var ox = coords[0];
      var oy = coords[1];
      var oz = z_coords[0];
      var x1 = coords[2] - ox;
      var y1 = coords[3] - oy;
      var z1 = z_coords[1] - oz;
      var x2 = coords[4] - ox;
      var y2 = coords[5] - oy;
      var z2 = z_coords[2] - oz; // [nx, ny, nz] = [x1, y1, z1] x [x2, y2, z2]

      var nx = y1 * z2 - z1 * y2;
      var ny = z1 * x2 - x1 * z2;
      var nz = x1 * y2 - y1 * x2;
      return [nx, ny, nz, -ox * nx - oy * ny - oz * nz];
    }
  }]);

  return PolygonsSubmesh;
}(Submesh);
/**
 * @summary 配列からベクトルを設定
 *
 * array[index] から vec に設定する。
 *
 * @private
 */


function setArrayToVec3(array, index, vec) {
  vec[0] = array[index];
  vec[1] = array[index + 1];
  vec[2] = array[index + 2];
}
/**
 * @summary 配列からベクトルを設定
 *
 * vec から array[index] に設定する。
 *
 * @private
 */


function setVec3ToArray(vec, array, index) {
  array[index] = vec[0];
  array[index + 1] = vec[1];
  array[index + 2] = vec[2];
}
/**
 * @summary 3頂点から正規化法線ベクトルを設定
 * @private
 */


function setTriangleNormal(p0, p1, p2, normal) {
  for (var i = 0; i < 3; ++i) {
    temp_normal_ax[i] = p1[i] - p0[i];
    temp_normal_ay[i] = p2[i] - p0[i];
  }

  GeoMath.cross3(temp_normal_ax, temp_normal_ay, normal);
  GeoMath.normalize3(normal, normal);
  return normal;
}

var temp_normal_ax = GeoMath.createVector3();
var temp_normal_ay = GeoMath.createVector3();
/**
 * @summary 内部ステータス
 * @enum {object}
 * @constant
 * @private
 */

var Status$2 = {
  INVALID: {
    id: "INVALID"
  },
  NORMAL: {
    id: "NORMAL"
  },
  TRIANGLE_DIRTY: {
    id: "TRIANGLE_DIRTY"
  },
  MESH_DIRTY: {
    id: "MESH_DIRTY"
  }
};

// https://tc39.github.io/ecma262/#sec-typedarray-objects

typedArrayConstructor('Int8', function (init) {
  return function Int8Array(data, byteOffset, length) {
    return init(this, data, byteOffset, length);
  };
});

/**
 * glTF の bufferView に対応
 * @memberof mapray.gltf
 * @private
 */
var BufferView =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {number}              index  バッファビュー索引
   */
  function BufferView(ctx, index) {
    _classCallCheck(this, BufferView);

    // glTF の bufferView オブジェクト (specification/2.0/schema/bufferView.schema.json)
    var jbufferView = ctx.gjson.bufferViews[index];
    this._buffer = ctx.findBuffer(jbufferView.buffer);
    this._byteLength = jbufferView.byteLength;
    this._target = jbufferView.target; // ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER

    this._byteOffset = jbufferView.byteOffset !== undefined ? jbufferView.byteOffset : 0;
    this._byteStride = jbufferView.byteStride !== undefined ? jbufferView.byteStride : 0;
  }
  /**
   * 参照する gltf.Buffer インスタンスを取得
   * @type {mapray.gltf.Buffer}
   * @readonly
   */


  _createClass(BufferView, [{
    key: "rebuildBySplitter",

    /**
     * バッファ分割用の再構築処理
     *
     * @param {mapray.gltf.Buffer} buffer  部分バッファ
     */
    value: function rebuildBySplitter(buffer) {
      // 部分バッファ全体を参照するようにする
      this._buffer = buffer;
      this._byteLength = buffer.byteLength;
      this._byteOffset = 0;
    }
  }, {
    key: "buffer",
    get: function get() {
      return this._buffer;
    }
    /**
     * ファッファ先頭からのバイトオフセット
     * @type {number}
     * @readonly
     */

  }, {
    key: "byteOffset",
    get: function get() {
      return this._byteOffset;
    }
    /**
     * インタリーブのバイトストライド
     * @type {number}
     * @readonly
     */

  }, {
    key: "byteStride",
    get: function get() {
      return this._byteStride;
    }
  }]);

  return BufferView;
}();

/**
 * glTF の accessor に対応
 * @memberof mapray.gltf
 * @private
 */

var Accessor =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {number}              index  アクセサ索引
   */
  function Accessor(ctx, index) {
    _classCallCheck(this, Accessor);

    // glTF の accessor オブジェクト (specification/2.0/schema/accessor.schema.json)
    var jaccessor = ctx.gjson.accessors[index];
    this._type = jaccessor.type; // 文字列: SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4

    this._componentType = jaccessor.componentType; // GL_UNSIGNED_INT ...

    this._count = jaccessor.count; // >= 1

    this._bufferView = new BufferView(ctx, jaccessor.bufferView);
    this._byteOffset = jaccessor.byteOffset !== undefined ? jaccessor.byteOffset : 0;
    this._normalized = jaccessor.normalized || false;
    this._min = jaccessor.min ? jaccessor.min.slice() : null;
    this._max = jaccessor.max ? jaccessor.max.slice() : null;
    this._index = index;
  }
  /**
   * 対応する glTF オブジェクトでの索引を取得
   * @type {number}
   * @readonly
   */


  _createClass(Accessor, [{
    key: "getRangeInBuffer",

    /**
     * バッファ内でのデータ範囲を取得
     *
     * @return {object}  データ範囲 = { first: 先頭オフセット, last: 末尾オフセット + 1 }
     */
    value: function getRangeInBuffer() {
      var view = this._bufferView;
      var compo_size = Accessor._ComponentData[this._componentType].bytes;
      var data_size = compo_size * Accessor._NumComponents[this._type]; // データのバイト数

      var stride = view.byteStride == 0 ? data_size : view.byteStride; // ストライド

      var first_offset = this._byteOffset + view.byteOffset; // バッファ内での先頭オフセット

      return {
        first: first_offset,
        last: first_offset + stride * (this._count - 1) + data_size // バッファ内での末尾オフセット + 1

      };
    }
    /**
     * バイトオーダーを修正
     *
     * @param  {mapray.BitVector} modmap  修正マップ
     */

  }, {
    key: "modifyByteOrder",
    value: function modifyByteOrder(modmap) {
      var compo_data = Accessor._ComponentData[this._componentType];
      var compo_bytes = compo_data.bytes;

      if (compo_bytes == 1) {
        return; // 1 バイト要素はバイトオーダーがないので処理しない
      }

      var num_compos = Accessor._NumComponents[this._type]; // 属性の要素数

      var byte_offset = this._byteOffset + this._bufferView.byteOffset; // バッファ先頭からのバイト数

      var compo_stride = this._bufferView.byteStride == 0 ? // 要素単位のストライド
      num_compos : this._bufferView.byteStride / compo_bytes;
      var arraybuffer = this._bufferView.buffer.binary;
      var dataview = new DataView(arraybuffer, byte_offset);
      var typedarray = new compo_data.typedarray(arraybuffer, byte_offset);
      var getCompo = compo_data.getcompo; // DataView データ取得関数

      var compo_shorts = compo_bytes / 2; // 1 要素の short 数

      var short_offset = byte_offset / 2; // バッファ先頭からの short 数

      var short_stride = compo_stride * compo_shorts; // short 単位のストライド

      for (var i = 0; i < this._count; ++i) {
        var short_base_index = short_offset + i * short_stride;
        var compo_base_index = i * compo_stride;

        for (var c = 0; c < num_compos; ++c) {
          var short_index = short_base_index + c * compo_shorts;

          if (modmap.getBit(short_index)) {
            continue; // すでに修正済みの要素なのでスキップ
          }

          var compo_index = compo_base_index + c; // リトルエンディアン (glTF 仕様) を想定して要素を読み込む

          var value = getCompo.call(dataview, compo_index * compo_bytes, true); // ネイティブエンディアン (WebGL 仕様) で要素を書き戻す

          typedarray[compo_index] = value;
          modmap.setBit(short_index, true);
        }
      }
    }
    /**
     * 範囲チェック
     *
     * @param  {number} first  バッファに対する開始位置
     * @param  {number} last   バッファに対する終了位置 + 1
     * @return {boolean}       最初のバイトが範囲に含まれるか?
     */

  }, {
    key: "isIncluded",
    value: function isIncluded(first, last) {
      var byte_offset = this._byteOffset + this._bufferView.byteOffset;
      return first <= byte_offset && byte_offset < last;
    }
    /**
     * バッファ分割用の再構築処理
     *
     * @param {mapray.gltf.Buffer} buffer  部分バッファ
     * @param {number}             first   元バッファに対する buffer の開始位置
     */

  }, {
    key: "rebuildBySplitter",
    value: function rebuildBySplitter(buffer, first) {
      this._index = -1; // 元バッファ先頭からのデータのバイト位置

      var old_byte_offset = this._byteOffset + this._bufferView.byteOffset; // 部分バッファ先頭からのデータのバイト位置

      this._byteOffset = old_byte_offset - first; // bufferView を部分バッファと一致するように更新

      this._bufferView.rebuildBySplitter(buffer);
    }
  }, {
    key: "index",
    get: function get() {
      return this._index;
    }
    /**
     * 参照する gltf.BufferView インスタンスを取得
     * @type {mapray.gltf.BufferView}
     * @readonly
     */

  }, {
    key: "bufferView",
    get: function get() {
      return this._bufferView;
    }
    /**
     * データの型を取得
     * @type {string}
     * @readonly
     */

  }, {
    key: "type",
    get: function get() {
      return this._type;
    }
    /**
     * データ要素の型を取得
     * @type {number}
     * @readonly
     */

  }, {
    key: "componentType",
    get: function get() {
      return this._componentType;
    }
    /**
     * データの個数を取得
     * @type {number}
     * @readonly
     */

  }, {
    key: "count",
    get: function get() {
      return this._count;
    }
    /**
     * バッファビュー先頭からのバイトオフセットを取得
     * @type {number}
     * @readonly
     */

  }, {
    key: "byteOffset",
    get: function get() {
      return this._byteOffset;
    }
    /**
     * 正規化するか?
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "normalized",
    get: function get() {
      return this._normalized;
    }
    /**
     * 座標の最小値
     * @type {?number[]}
     * @readonly
     */

  }, {
    key: "min",
    get: function get() {
      return this._min;
    }
    /**
     * 座標の最大値
     * @type {?number[]}
     * @readonly
     */

  }, {
    key: "max",
    get: function get() {
      return this._max;
    }
  }]);

  return Accessor;
}();

Accessor._NumComponents = {
  'SCALAR': 1,
  'VEC2': 2,
  'VEC3': 3,
  'VEC4': 4,
  'MAT2': 4,
  'MAT3': 9,
  'MAT4': 16
};
Accessor._ComponentData = {
  5120: {
    bytes: 1,
    getcompo: DataView.prototype.getInt8,
    typedarray: Int8Array
  },
  // BYTE
  5121: {
    bytes: 1,
    getcompo: DataView.prototype.getUint8,
    typedarray: Uint8Array
  },
  // UNSIGNED_BYTE
  5122: {
    bytes: 2,
    getcompo: DataView.prototype.getInt16,
    typedarray: Int16Array
  },
  // SHORT
  5123: {
    bytes: 2,
    getcompo: DataView.prototype.getUint16,
    typedarray: Uint16Array
  },
  // UNSIGNED_SHORT
  5125: {
    bytes: 4,
    getcompo: DataView.prototype.getUint32,
    typedarray: Uint32Array
  },
  // UNSIGNED_INT
  5126: {
    bytes: 4,
    getcompo: DataView.prototype.getFloat32,
    typedarray: Float32Array
  } // FLOAT

};

/**
 * glTF の material に対応
 * @memberof mapray.gltf
 * @private
 */

var Material$1 =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {number}              index  マテリアル索引
   */
  function Material(ctx, index) {
    _classCallCheck(this, Material);

    var jmaterial = ctx.gjson.materials[index];
    this._commonData = new CommonData(jmaterial, ctx);
    this._pbrMetallicRoughness = {
      baseColorFactor: [1.0, 1.0, 1.0, 1.0],
      baseColorTexture: null,
      metallicFactor: 1.0,
      roughnessFactor: 1.0,
      metallicRoughnessTexture: null
    };
    this._doubleSided = false;
    this._alphaMode = "OPAQUE";
    this._alphaCutoff = 0.5;
    this._emissiveFactor = [0.0, 0.0, 0.0];
    this._emissiveTexture = null;
    this._normalTexture = null;
    this._occlusionTexture = null; // glTF の material オブジェクト (specification/2.0/schema/material.schema.json)

    this._setupPbrMetallicRoughness(jmaterial, ctx);

    this._setupGenericParameters(jmaterial, ctx);
  }
  /**
   * glTF オブジェクトの共通データ
   *
   * @type {mapray.gltf.CommonData}
   * @readonly
   */


  _createClass(Material, [{
    key: "_setupPbrMetallicRoughness",

    /**
     * this._pbrMetallicRoughness を設定
     *
     * @param {object}              jmaterial  glTF の material オブジェクト
     * @param {mapray.gltf.Context} ctx        読み込みコンテキスト
     * @private
     */
    value: function _setupPbrMetallicRoughness(jmaterial, ctx) {
      if (jmaterial.pbrMetallicRoughness === undefined) {
        return;
      } // glTF の pbrMetallicRoughness オブジェクト (specification/2.0/schema/material.pbrMetallicRoughness.schema.json)


      var src = jmaterial.pbrMetallicRoughness;
      var dst = this._pbrMetallicRoughness;

      if (src.baseColorFactor !== undefined) {
        dst.baseColorFactor = src.baseColorFactor.slice();
      }

      if (src.baseColorTexture !== undefined) {
        dst.baseColorTexture = new TextureInfo(src.baseColorTexture, ctx);
        ctx.addTextureInfo(dst.baseColorTexture);
      }

      if (src.metallicFactor !== undefined) {
        dst.metallicFactor = src.metallicFactor;
      }

      if (src.roughnessFactor !== undefined) {
        dst.roughnessFactor = src.roughnessFactor;
      }

      if (src.metallicRoughnessTexture !== undefined) {
        dst.metallicRoughnessTexture = new TextureInfo(src.metallicRoughnessTexture, ctx);
        ctx.addTextureInfo(dst.metallicRoughnessTexture);
      }
    }
    /**
     * this._doubleSided などを設定
     *
     * @param {object}              jmaterial  glTF の material オブジェクト
     * @param {mapray.gltf.Context} ctx        読み込みコンテキスト
     * @private
     */

  }, {
    key: "_setupGenericParameters",
    value: function _setupGenericParameters(jmaterial, ctx) {
      if (jmaterial.doubleSided !== undefined) {
        this._doubleSided = jmaterial.doubleSided;
      }

      if (jmaterial.alphaMode !== undefined) {
        this._alphaMode = jmaterial.alphaMode;
      }

      if (jmaterial.alphaCutoff !== undefined) {
        this._alphaCutoff = jmaterial.alphaCutoff;
      }

      if (jmaterial.emissiveFactor !== undefined) {
        this._emissiveFactor = jmaterial.emissiveFactor.slice();
      }

      if (jmaterial.emissiveTexture !== undefined) {
        this._emissiveTexture = new TextureInfo(jmaterial.emissiveTexture, ctx);
        ctx.addTextureInfo(this._emissiveTexture);
      }

      if (jmaterial.normalTexture !== undefined) {
        this._normalTexture = new NormalTextureInfo(jmaterial.normalTexture, ctx);
        ctx.addTextureInfo(this._normalTexture);
      }

      if (jmaterial.occlusionTexture !== undefined) {
        this._occlusionTexture = new OcclusionTextureInfo(jmaterial.occlusionTexture, ctx);
        ctx.addTextureInfo(this._occlusionTexture);
      }
    }
  }, {
    key: "commonData",
    get: function get() {
      return this._commonData;
    }
    /**
     * MetallicRoughness PBR パラメータ
     * @type {object}
     * @readonly
     */

  }, {
    key: "pbrMetallicRoughness",
    get: function get() {
      return this._pbrMetallicRoughness;
    }
    /**
     * 両面レンダリングの有無
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "doubleSided",
    get: function get() {
      return this._doubleSided;
    }
    /**
     * αモード
     * @type {string}
     * @readonly
     */

  }, {
    key: "alphaMode",
    get: function get() {
      return this._alphaMode;
    }
    /**
     * αカットオフ
     * @type {number}
     * @readonly
     */

  }, {
    key: "alphaCutoff",
    get: function get() {
      return this._alphaCutoff;
    }
    /**
     * 自己発光係数
     * @type {mapray.Vector3}
     * @readonly
     */

  }, {
    key: "emissiveFactor",
    get: function get() {
      return this._emissiveFactor;
    }
    /**
     * 自己発光テクスチャ
     * @type {?mapray.gltf.TextureInfo}
     * @readonly
     */

  }, {
    key: "emissiveTexture",
    get: function get() {
      return this._emissiveTexture;
    }
    /**
     * 法線テクスチャ
     * @type {?mapray.gltf.NormalTextureInfo}
     * @readonly
     */

  }, {
    key: "normalTexture",
    get: function get() {
      return this._normalTexture;
    }
    /**
     * 遮蔽テクスチャ
     * @type {?mapray.gltf.OcclusionTextureInfo}
     * @readonly
     */

  }, {
    key: "occlusionTexture",
    get: function get() {
      return this._occlusionTexture;
    }
  }]);

  return Material;
}();

/**
 * glTF の primitive に対応
 * @memberof mapray.gltf
 * @private
 */

var Primitive$1 =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {object}              jprimitive  glTF の primitive オブジェクト (specification/2.0/schema/mesh.primitive.schema.json)
   * @param {mapray.gltf.Context} ctx         読み込みコンテキスト
   */
  function Primitive(jprimitive, ctx) {
    _classCallCheck(this, Primitive);

    this._mode = jprimitive.mode !== undefined ? jprimitive.mode : 4;
    this._attributes = {};
    this._indices = null;
    this._material = null;

    this._setupAttributes(jprimitive.attributes, ctx);

    this._setupIndices(jprimitive, ctx);

    this._setupMaterial(jprimitive, ctx);
  }
  /**
   * プリミティブモード
   *
   * @type {number}
   * @readonly
   */


  _createClass(Primitive, [{
    key: "_setupAttributes",

    /**
     * this._attributes を設定
     *
     * @param {object}              jattributes  glTF の primitive/attributes オブジェクト
     * @param {mapray.gltf.Context} ctx          読み込みコンテキスト
     * @private
     */
    value: function _setupAttributes(jattributes, ctx) {
      for (var name in jattributes) {
        var accessor = new Accessor(ctx, jattributes[name]);
        this._attributes[name] = accessor;
        ctx.addAccessor(accessor, "ATTRIBUTE");
      }
    }
    /**
     * this._indices を設定
     *
     * @param {object}              jprimitive  glTF の primitive オブジェクト
     * @param {mapray.gltf.Context} ctx         読み込みコンテキスト
     * @private
     */

  }, {
    key: "_setupIndices",
    value: function _setupIndices(jprimitive, ctx) {
      if (jprimitive.indices !== undefined) {
        var accessor = new Accessor(ctx, jprimitive.indices);
        this._indices = accessor;
        ctx.addAccessor(accessor, "INDEX");
      }
    }
    /**
     * this._material を設定
     *
     * @param {object}              jprimitive  glTF の primitive オブジェクト
     * @param {mapray.gltf.Context} ctx         読み込みコンテキスト
     * @private
     */

  }, {
    key: "_setupMaterial",
    value: function _setupMaterial(jprimitive, ctx) {
      if (jprimitive.material !== undefined) {
        this._material = new Material$1(ctx, jprimitive.material);
      }
    }
  }, {
    key: "mode",
    get: function get() {
      return this._mode;
    }
    /**
     * @summary 頂点属性の辞書
     *
     * <p>頂点属性名から Accessor を引く辞書</p>
     *
     * @type {object}
     * @readonly
     */

  }, {
    key: "attributes",
    get: function get() {
      return this._attributes;
    }
    /**
     * インデックス
     *
     * @type {?mapray.gltf.Accessor}
     * @readonly
     */

  }, {
    key: "indices",
    get: function get() {
      return this._indices;
    }
    /**
     * マテリアル
     *
     * @type {?mapray.gltf.Material}
     * @readonly
     */

  }, {
    key: "material",
    get: function get() {
      return this._material;
    }
  }]);

  return Primitive;
}();

/**
 * glTF の mesh に対応
 * @memberof mapray.gltf
 * @private
 */

var Mesh$1 =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {number}              index  メッシュ索引
   */
  function Mesh(ctx, index) {
    _classCallCheck(this, Mesh);

    this._primitives = []; // glTF の mesh オブジェクト (specification/2.0/schema/mesh.schema.json)

    var jmesh = ctx.gjson.meshes[index];
    var jprimitives = jmesh.primitives;

    for (var i = 0; i < jprimitives.length; ++i) {
      // glTF の primitive オブジェクト (specification/2.0/schema/mesh.primitive.schema.json)
      var jprimitive = jprimitives[i];

      this._primitives.push(new Primitive$1(jprimitive, ctx));
    }
  }
  /**
   * プリミティブの配列を取得
   *
   * @type {mapray.gltf.Primitive[]}
   * @readonly
   */


  _createClass(Mesh, [{
    key: "primitives",
    get: function get() {
      return this._primitives;
    }
  }]);

  return Mesh;
}();

/**
 * glTF の node に対応
 * @memberof mapray.gltf
 * @private
 */

var Node$1 =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {number}              index  ノード索引
   */
  function Node(ctx, index) {
    _classCallCheck(this, Node);

    // glTF の node オブジェクト (specification/2.0/schema/node.schema.json)
    var jnode = ctx.gjson.nodes[index];
    this._commonData = new CommonData(jnode, ctx);
    this._children = [];
    this._matrix = null;
    this._mesh = null;

    this._setupChildren(jnode, ctx);

    this._setupMatrix(jnode);

    this._setupMesh(jnode, ctx);
  }
  /**
   * glTF オブジェクトの共通データ
   *
   * @type {mapray.gltf.CommonData}
   * @readonly
   */


  _createClass(Node, [{
    key: "_setupChildren",

    /**
     * this._children を設定
     *
     * @param {object}              jnode  glTF の node オブジェクト
     * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
     * @private
     */
    value: function _setupChildren(jnode, ctx) {
      var children = jnode.children;
      if (children === undefined) return;

      for (var i = 0; i < children.length; ++i) {
        var index = children[i];

        this._children.push(new Node(ctx, index));
      }
    }
    /**
     * this._matrix を設定
     *
     * @param {object} jnode  glTF の node オブジェクト
     * @private
     */

  }, {
    key: "_setupMatrix",
    value: function _setupMatrix(jnode) {
      if (jnode.matrix) {
        // 行列指定
        this._matrix = GeoMath.createMatrix(jnode.matrix);
      } else if (jnode.scale || jnode.rotation || jnode.translation) {
        // SQT 指定
        var _ref = jnode.scale || [1, 1, 1],
            _ref2 = _slicedToArray(_ref, 3),
            sx = _ref2[0],
            sy = _ref2[1],
            sz = _ref2[2];

        var _ref3 = jnode.rotation || [0, 0, 0, 1],
            _ref4 = _slicedToArray(_ref3, 4),
            qx = _ref4[0],
            qy = _ref4[1],
            qz = _ref4[2],
            qw = _ref4[3];

        var _ref5 = jnode.translation || [0, 0, 0],
            _ref6 = _slicedToArray(_ref5, 3),
            tx = _ref6[0],
            ty = _ref6[1],
            tz = _ref6[2]; //                        [ 1 - 2y^2 - 2z^2,      2x y - 2w z,      2x z + 2w y ]
        // rotation[x, y, z, w] = [     2x y + 2w z,  1 - 2x^2 - 2z^2,      2y z - 2w x ]
        //                        [     2x z - 2w y,      2y z + 2w x,  1 - 2x^2 - 2y^2 ]


        this._matrix = GeoMath.createMatrix([(1 - 2 * (qy * qy + qz * qz)) * sx, 2 * (qx * qy + qz * qw) * sx, 2 * (qx * qz - qy * qw) * sx, 0, 2 * (qx * qy - qz * qw) * sy, (1 - 2 * (qx * qx + qz * qz)) * sy, 2 * (qx * qw + qy * qz) * sy, 0, 2 * (qy * qw + qx * qz) * sz, 2 * (qy * qz - qx * qw) * sz, (1 - 2 * (qx * qx + qy * qy)) * sz, 0, tx, ty, tz, 1]);
      }
    }
    /**
     * this._mesh を設定
     *
     * @param {object}              jnode  glTF の node オブジェクト
     * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
     * @private
     */

  }, {
    key: "_setupMesh",
    value: function _setupMesh(jnode, ctx) {
      var index = jnode.mesh;
      if (index === undefined) return; // メッシュなしのノード

      this._mesh = new Mesh$1(ctx, index);
    }
  }, {
    key: "commonData",
    get: function get() {
      return this._commonData;
    }
    /**
     * 子ノードの配列を取得
     * @type {mapray.gltf.Node[]}
     * @readonly
     */

  }, {
    key: "children",
    get: function get() {
      return this._children;
    }
    /**
     * 変換行列を取得
     * @type {?mapray.Matrix}
     * @readonly
     */

  }, {
    key: "matrix",
    get: function get() {
      return this._matrix;
    }
    /**
     * メッシュを取得
     * @type {?mapray.gltf.Mesh}
     * @readonly
     */

  }, {
    key: "mesh",
    get: function get() {
      return this._mesh;
    }
  }]);

  return Node;
}();

/**
 * @summary glTF scene
 *
 * @classdesc
 * <p>glTF の scene に対応するオブジェクトである。</p>
 *
 * @memberof mapray.gltf
 * @private
 * @see https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/schema/scene.schema.json
 */

var Scene$1 =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {number}              index  シーン索引
   */
  function Scene(ctx, index) {
    _classCallCheck(this, Scene);

    // glTF の scene オブジェクト
    var jscene = ctx.gjson.scenes[index];
    this._commonData = new CommonData(jscene, ctx);
    this._root_nodes = [];
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
      for (var _iterator = (jscene.nodes || [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
        var node_index = _step.value;

        this._root_nodes.push(new Node$1(ctx, node_index));
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator["return"] != null) {
          _iterator["return"]();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }
  }
  /**
   * glTF オブジェクトの共通データ
   *
   * @type {mapray.gltf.CommonData}
   * @readonly
   */


  _createClass(Scene, [{
    key: "commonData",
    get: function get() {
      return this._commonData;
    }
    /**
     * 最上位ノードの配列
     *
     * @type {mapray.gltf.Node[]}
     * @readonly
     */

  }, {
    key: "root_nodes",
    get: function get() {
      return this._root_nodes;
    }
    /**
     * @summary シーン名を取得
     *
     * <p>シーン名が存在すればシーン名の文字列を返し、存在しなければ null を返す。</p>
     *
     * @type {?string}
     * @readonly
     */

  }, {
    key: "name",
    get: function get() {
      return this._commonData.getName();
    }
  }]);

  return Scene;
}();

/**
 * バッファの分割を補助
 *
 * @memberof mapray.gltf
 * @private
 */
var BufferSplitter =
/*#__PURE__*/
function () {
  /**
   */
  function BufferSplitter() {
    _classCallCheck(this, BufferSplitter);

    // 処理しやすいように最初と最後はにダミーの断片を置く
    var frag0 = new Fragment(-2, -1);
    var frag1 = new Fragment(Math.pow(2, 32) + 1, Math.pow(2, 32) + 2);
    frag0.next = frag1;
    frag1.prev = frag0;
    this._fragments = frag0;
  }
  /**
   * 分割を更新
   *
   * @param {mapray.gltf.Accessor} accessor  バッファを参照するアクセサ
   */


  _createClass(BufferSplitter, [{
    key: "update",
    value: function update(accessor) {
      var range = accessor.getRangeInBuffer();

      this._updateByRange({
        first: BufferSplitter._floor4(range.first),
        last: range.last
      });
    }
    /**
     * 分割の更新を終了
     *
     * @param {mapray.gltf.Buffer} buffer  分割されるバッファ
     */

  }, {
    key: "close",
    value: function close(buffer) {
      // 先頭のダミーを削除
      this._fragments = this._fragments.next; // 部分バッファを設定

      for (var frag = this._fragments;; frag = frag.next) {
        if (frag.next === null) {
          // 最後のダミーを削除
          frag.prev.next = null;
          break;
        }

        frag.buffer = buffer.createSubBuffer(frag.first, frag.last);
      }
    }
    /**
     * アクセサを部分バッファで再構築
     *
     * @param {mapray.gltf.Accessor} accessor  再構築するアクセサ
     */

  }, {
    key: "rebuildAccessor",
    value: function rebuildAccessor(accessor) {
      for (var frag = this._fragments; frag !== null; frag = frag.next) {
        if (accessor.isIncluded(frag.first, frag.last)) {
          accessor.rebuildBySplitter(frag.buffer, frag.first);
          break;
        }
      }
    }
    /**
     * 分割を更新
     *
     * @param {object} range  Accessor の範囲
     * @private
     */

  }, {
    key: "_updateByRange",
    value: function _updateByRange(range) {
      for (var frag = this._fragments; frag.next !== null;) {
        if (frag.isInside(range)) {
          // frag 断片と frag.next 断片の間に新しい range 断片を挿入
          var frag0 = frag;
          var frag1 = frag.next;
          var fragx = new Fragment(range.first, range.last);
          frag0.next = fragx;
          frag1.prev = fragx;
          fragx.prev = frag0;
          fragx.next = frag1;
          break;
        } else if (frag.isTouch(range)) {
          // range に frag を統合し、frag を削除し、frag.prev から始める
          var _frag = frag.prev;
          var _frag2 = frag.next;
          _frag.next = _frag2;
          _frag2.prev = _frag;
          range = frag.mergeRange(range);
          frag = _frag;
        } else {
          frag = frag.next;
        }
      }
    }
    /**
     * 4 の倍数に切り下げ
     *
     * @param  {number} value  切り下げる値
     * @return {number}        value を 4 の倍数に切り下げた整数
     * @private
     */

  }], [{
    key: "_floor4",
    value: function _floor4(value) {
      return 4 * Math.floor(value / 4);
    }
  }]);

  return BufferSplitter;
}();
/**
 * バッファの断片
 *
 * @memberof mapray.gltf.BufferSplitter
 * @private
 */


var Fragment =
/*#__PURE__*/
function () {
  /**
   * @param {number} first  先頭オフセット
   * @param {number} last   末尾オフセット + 1
   */
  function Fragment(first, last) {
    _classCallCheck(this, Fragment);

    this.first = first;
    this.last = last;
    this.buffer = null; // 部分バッファ

    this.prev = null;
    this.next = null;
  }
  /**
   * range は frag と frag.next の間の内側か?
   *
   * @param  {object} range
   * @return {boolean}
   * @private
   */


  _createClass(Fragment, [{
    key: "isInside",
    value: function isInside(range) {
      return this.last < range.first && range.last < this.next.first;
    }
    /**
     * range は frag と接触しているか?
     *
     * @param  {object} range
     * @return {boolean}
     */

  }, {
    key: "isTouch",
    value: function isTouch(range) {
      return this.last >= range.first && range.last >= this.first;
    }
    /**
     * this と range を結合した range を取得
     *
     * @param  {object} range
     * @return {object}
     */

  }, {
    key: "mergeRange",
    value: function mergeRange(range) {
      return {
        first: Math.min(this.first, range.first),
        last: Math.max(this.last, range.last)
      };
    }
  }]);

  return Fragment;
}();

/**
 * @summary ビット配列
 *
 * @memberof mapray
 * @private
 */
var BitVector =
/*#__PURE__*/
function () {
  /**
   * 初期値はすべてのビットが false である。
   *
   * @param {number} length  ビット数
   */
  function BitVector(length) {
    _classCallCheck(this, BitVector);

    this._length = length;
    this._array = new Uint32Array(Math.ceil(length / 32));
  }
  /**
   * @summary ビット数
   * @type {number}
   * @readonly
   */


  _createClass(BitVector, [{
    key: "setBit",

    /**
     * @summary ビットを設定
     *
     * @param {number}  index  インデックス
     * @param {boolean} value  値
     */
    value: function setBit(index, value) {
      var uint32_index = Math.floor(index / 32);
      var uint32_value = this._array[uint32_index];
      var uint32_mask = 1 << index % 32;
      this._array[uint32_index] = value ? uint32_value | uint32_mask : uint32_value & ~uint32_mask;
    }
    /**
     * @summary ビットを取得
     *
     * @param  {number}  index  インデックス
     * @return {boolean}        値
     */

  }, {
    key: "getBit",
    value: function getBit(index) {
      var uint32_index = Math.floor(index / 32);
      var uint32_value = this._array[uint32_index];
      var uint32_mask = 1 << index % 32;
      return (uint32_value & uint32_mask) != 0;
    }
  }, {
    key: "length",
    get: function get() {
      return this._length;
    }
  }]);

  return BitVector;
}();

/**
 * コンテキストでの Buffer 管理アイテム
 *
 * @memberof mapray.gltf
 * @private
 */

var BufferEntry =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.gltf.Buffer} buffer  バッファ
   */
  function BufferEntry(buffer) {
    _classCallCheck(this, BufferEntry);

    this._buffer = buffer;
    this._attrib_accessors = [];
    this._index_accessors = [];
  }
  /**
   * 管理対象のバッファを取得
   *
   * @type {mapray.gltf.Buffer}
   * @readonly
   */


  _createClass(BufferEntry, [{
    key: "addAttributeAccessor",

    /**
     * 頂点属性で使われている Accessor インスタンスを追加
     */
    value: function addAttributeAccessor(accessor) {
      this._attrib_accessors.push(accessor);
    }
    /**
     * インデックスで使われている Accessor インスタンスを追加
     */

  }, {
    key: "addIndexAccessor",
    value: function addIndexAccessor(accessor) {
      this._index_accessors.push(accessor);
    }
    /**
     * バイナリをマシンのバイトオーダーに合わせて書き換え
     */

  }, {
    key: "rewriteByteOrder",
    value: function rewriteByteOrder() {
      var modmap = new BitVector(Math.ceil(this._buffer.byteLength / 2));
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this._getUnitedOriginalAccessors()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var accessor = _step.value;
          accessor.modifyByteOrder(modmap);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    }
    /**
     * バッファを分割し、Accessor を再構築
     */

  }, {
    key: "splitBufferAndRebuildAccessors",
    value: function splitBufferAndRebuildAccessors() {
      this._splitBufferAndRebuildAccessors(this._attrib_accessors);

      this._splitBufferAndRebuildAccessors(this._index_accessors);
    }
    /**
     * バッファを分割し、Accessor を再構築
     *
     * @param {iterable.<mapray.gltf.Accessor>} accessors  入力 Accessor 反復子
     */

  }, {
    key: "_splitBufferAndRebuildAccessors",
    value: function _splitBufferAndRebuildAccessors(accessors) {
      var splitter = new BufferSplitter();
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = BufferEntry._getOriginalAccessors(accessors)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var accessor = _step2.value;
          splitter.update(accessor);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      splitter.close(this._buffer);
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = accessors[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var _accessor = _step3.value;
          splitter.rebuildAccessor(_accessor);
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }
    }
    /**
     * バッファを参照ている原初 Accessor の反復子
     *
     * @return {iterable.<mapray.gltf.Accessor>}  原初 Accessor 反復子
     * @private
     */

  }, {
    key: "_getUnitedOriginalAccessors",
    value: function _getUnitedOriginalAccessors() {
      return BufferEntry._getOriginalAccessors(this._attrib_accessors.concat(this._index_accessors));
    }
    /**
     * 原初 Accessor の反復子を取得
     *
     * @param  {iterable.<mapray.gltf.Accessor>} accessors  入力 Accessor 反復子
     * @return {iterable.<mapray.gltf.Accessor>}            原初 Accessor 反復子
     * @private
     */

  }, {
    key: "buffer",
    get: function get() {
      return this._buffer;
    }
  }], [{
    key: "_getOriginalAccessors",
    value: function _getOriginalAccessors(accessors) {
      var orig_accessors = new Map();
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = accessors[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var accessor = _step4.value;
          var key = accessor.index;

          if (!orig_accessors.has(key)) {
            orig_accessors.set(key, accessor);
          }
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) {
            _iterator4["return"]();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }

      return orig_accessors.values();
    }
  }]);

  return BufferEntry;
}();

/**
 * コンテキストでの Image 管理アイテム
 *
 * @memberof mapray.gltf
 * @private
 */
var ImageEntry =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.gltf.Image} image  イメージ
   */
  function ImageEntry(image) {
    _classCallCheck(this, ImageEntry);

    this._image = image;
    this._texinfo_objects = [];
  }
  /**
   * イメージを取得
   * @type {mapray.gltf.Texture}
   * @readonly
   */


  _createClass(ImageEntry, [{
    key: "addTextureInfo",

    /**
     * TextureInfo インスタンスを追加
     *
     * @param {mapray.gltf.TextureInfo} info  追加する TextureInfo インスタンス
     */
    value: function addTextureInfo(info) {
      this._texinfo_objects.push(info);
    }
    /**
     * テクスチャ情報を再構築
     */

  }, {
    key: "rebuildTextureInfo",
    value: function rebuildTextureInfo() {
      var texinfo_objects = this._texinfo_objects;

      if (texinfo_objects.length <= 1) {
        // イメージが複数の TextureInfo から参照されないので
        // 何も変更しない
        return;
      } // この画像を使っている代表テクスチャ


      var representative_texture = texinfo_objects[0].texture; // この画像を使っている (テクスチャ情報内の) テクスチャを
      // 代表テクスチャに置き換える

      for (var i = 1; i < texinfo_objects.length; ++i) {
        texinfo_objects[i].texture = representative_texture;
      }
    }
  }, {
    key: "image",
    get: function get() {
      return this._image;
    }
  }]);

  return ImageEntry;
}();

/**
 * glTF の buffer に対応
 * @memberof mapray.gltf
 * @private
 */
var Buffer =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.gltf.Context} [ctx]    読み込みコンテキスト
   * @param {number}              [index]  buffers 索引
   */
  function Buffer(ctx, index) {
    var _this = this;

    _classCallCheck(this, Buffer);

    if (ctx === undefined) {
      // 引数なし構築 (特殊インスタンス用)
      this._index = -1;
      this._byteLength = 0;
      this._uri = null;
      this._binary = null;
    } else {
      this._index = index; // glTF の buffer オブジェクト (specification/2.0/schema/buffer.schema.json)

      var jbuffer = ctx.gjson.buffers[index];
      this._byteLength = jbuffer.byteLength;

      if (jbuffer.uri !== undefined) {
        ctx.onStartLoadBuffer();
        ctx.loadBinary(jbuffer.uri).then(function (buffer) {
          // バイナリデータの取得に成功
          _this._binary = buffer;
          ctx.onFinishLoadBuffer();
        })["catch"](function (error) {
          // バイナリデータの取得に失敗
          console.error(error);
          ctx.onFinishLoadBuffer(error);
        });
      } else {
        // todo: GLB-stored Buffer
        this._uri = null;
        this._binary = null;
      }
    }
  }
  /**
   * 対応する glTF オブジェクトでの索引を取得
   * @type {number}
   * @readonly
   */


  _createClass(Buffer, [{
    key: "createSubBuffer",

    /**
     * 部分バッファを生成
     *
     * @param  {number} first  最初のバイト位置
     * @param  {number} last   最後のバイト位置 + 1
     * @return {mapray.gltf.Buffer}  部分バッファ
     */
    value: function createSubBuffer(first, last) {
      var subBuffer = new Buffer();
      subBuffer._byteLength = last - first;
      subBuffer._binary = this._binary.slice(first, last);
      return subBuffer;
    }
  }, {
    key: "index",
    get: function get() {
      return this._index;
    }
    /**
     * バイナリデータ
     * @type {ArrayBuffer}
     * @readonly
     */

  }, {
    key: "binary",
    get: function get() {
      return this._binary;
    }
    /**
     * バイナリデータのバイト数を取得
     * @type {number}
     * @readonly
     */

  }, {
    key: "byteLength",
    get: function get() {
      return this._byteLength;
    }
  }]);

  return Buffer;
}();

/**
 * glTF の image に対応
 * @memberof mapray.gltf
 * @private
 */

var Image$1 =
/*#__PURE__*/
function () {
  /**
   * 初期化
   * @param {mapray.gltf.Context} ctx    読み込みコンテキスト
   * @param {number}              index  images 索引
   */
  function Image(ctx, index) {
    var _this = this;

    _classCallCheck(this, Image);

    this._index = index; // glTF の image オブジェクト (specification/2.0/schema/image.schema.json)

    var jimage = ctx.gjson.images[index];

    if (jimage.uri !== undefined) {
      ctx.onStartLoadImage();
      ctx.loadImage(jimage.uri).then(function (image) {
        _this._image = image;
        ctx.onFinishLoadImage();
      })["catch"](function (error) {
        ctx.onFinishLoadImage(error);
      });
    } else if (jimage.bufferView !== undefined) {
      this._bufferView = new BufferView(ctx, jimage.bufferView);
    } // mimeType は "image/jpeg" または "image/png" で bufferView のときは必須
    // uri のときは任意であるが mimeType が指定されているとき、タイプは mimeType と解釈する


    this._mimeType = jimage.mimeType;
    this._image = null;
  }
  /**
   * 対応する glTF オブジェクトでの索引を取得
   * @type {number}
   * @readonly
   */


  _createClass(Image, [{
    key: "index",
    get: function get() {
      return this._index;
    }
    /**
     * 画像データ
     * @type {HTMLImageElement}
     * @readonly
     */

  }, {
    key: "image",
    get: function get() {
      return this._image;
    }
  }]);

  return Image;
}();

/**
 * glTF 読込みコンテキスト
 *
 * @memberof mapray.gltf
 * @private
 */

var Context =
/*#__PURE__*/
function () {
  /**
   * @param  {object} body       Tool.load() の同名パラメータを参照
   * @param  {object} [options]  Tool.load() の同名パラメータを参照
   */
  function Context(body, options) {
    _classCallCheck(this, Context);

    var opts = options || {};
    this._gjson = body;
    this._base_resource = opts.base_resource;
    this._binary_type = opts.binary_type;
    this._image_type = opts.image_type;
    this._supported_extensions = opts.supported_extensions || [];
    this._resolve = null; // Promise の resolve() 関数

    this._reject = null; // Promise の reject() 関数

    this._used_extensions = new Set(); // コンテンツが使用する拡張機能名の集合

    this._scenes = [];
    this._default_scene_index = -1;
    this._buffer_entries = []; // 共有用バッファの管理 (疎配列)

    this._image_entries = []; // 共有用イメージの管理 (疎配列)

    this._body_finished = false; // body の解析を終えたか?

    this._load_count = 0; // 現在リクエスト中のオブジェクト数

    this._load_error = null; // エラーが発生したときのエラーオブジェクト

    this._settled = false; // Promise の状態が Fulfilled または Rejected か?
  }
  /**
   * @summary glTF の読込みと解析
   *
   * @return {Promise}  読込み Promise (mapray.gltf.Content)
   */


  _createClass(Context, [{
    key: "load",
    value: function load() {
      var _this = this;

      return new Promise(function (resolve, reject) {
        _this._resolve = resolve;
        _this._reject = reject; // glTF バージョンを確認

        var version = _this._loadVersion();

        if (version.major < 2) {
          reject(new Error("glTF version error"));
          return;
        } // コンテンツに必須の拡張機能をサポートしているかを確認


        var supported_ext = _this._getSupportedExtensionNames();

        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
          for (var _iterator = _this._enumRequiredExtensionNames()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var required_ext = _step.value;

            if (!supported_ext.has(required_ext)) {
              reject(new Error("glTF extension error: " + required_ext));
              return;
            }
          }
        } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion && _iterator["return"] != null) {
              _iterator["return"]();
            }
          } finally {
            if (_didIteratorError) {
              throw _iteratorError;
            }
          }
        }

        _this._loadExtensionsUsed();

        _this._loadScenes();

        _this._loadDefaultSceneIndex();

        _this._onFinishLoadBody();
      });
    }
    /**
     * glTF バージョンを解析
     *
     * @return {object}  { major: major_version, minor: minor_version }
     * @private
     */

  }, {
    key: "_loadVersion",
    value: function _loadVersion() {
      // asset.schema
      var asset = this._gjson.asset; // 必須

      var version = asset.version; // 必須

      var version_array = /^(\d+)\.(\d+)/.exec(version);
      var major_version = Number(version_array[1]);
      var minor_version = Number(version_array[2]);
      return {
        major: major_version,
        minor: minor_version
      };
    }
    /**
     * @summary 必須の拡張機能の名前を列挙
     *
     * @desc
     * <p>glTF アセットから必須の拡張機能を解析して、
     *    その拡張機能の名前を列挙する。</p>
     *
     * @return {iterable.<string>}  拡張機能名の列挙
     *
     * @private
     */

  }, {
    key: "_enumRequiredExtensionNames",
    value: function _enumRequiredExtensionNames() {
      return this._gjson.extensionsRequired || [];
    }
    /**
     * @summary 対応可能な拡張機能の名前の集合を取得
     *
     * @desc
     * <p>glTF のローダーとクライアントが対応できる拡張機能の
     *    名前の集合を取得する。</p>
     *
     * @return {Set.<string>}  拡張機能名の集合
     *
     * @private
     */

  }, {
    key: "_getSupportedExtensionNames",
    value: function _getSupportedExtensionNames() {
      // ローダー自身が対応できる拡張機能
      // ※ 今のところサポートできる拡張機能はない
      var supported_extensions_by_loader = []; // ローダーを呼び出す側が対応できる拡張機能

      var supported_extensions_by_client = this._supported_extensions;
      return new Set(supported_extensions_by_loader.concat(supported_extensions_by_client));
    }
    /**
     * @summary コンテンツが使用する拡張機能を読み込む
     *
     * @desc
     * <p>extensionsUsed プロパティを読み込み this._used_extensions を設定する。</p>
     *
     * @private
     */

  }, {
    key: "_loadExtensionsUsed",
    value: function _loadExtensionsUsed() {
      this._used_extensions = new Set(this._gjson.extensionsUsed || []);
    }
    /**
     * @summary すべてのシーンを読み込む
     *
     * <p>シーンを読み込み、オブジェクトを this._scenes の配列に設定する。</p>
     *
     * @private
     */

  }, {
    key: "_loadScenes",
    value: function _loadScenes() {
      var num_scenes = (this._gjson.scenes || []).length;
      var scenes = [];

      for (var index = 0; index < num_scenes; ++index) {
        scenes.push(new Scene$1(this, index));
      }

      this._scenes = scenes;
    }
    /**
     * @summary 既定シーンの索引を読み込む
     *
     * <p>既定のシーン索引を解析し、this._default_scene_index に設定する。</p>
     *
     * @private
     */

  }, {
    key: "_loadDefaultSceneIndex",
    value: function _loadDefaultSceneIndex() {
      if (typeof this._gjson.scene == 'number') {
        this._default_scene_index = this._gjson.scene;
      }
    }
    /**
     * glTF 最上位オブジェクト
     * @type {object}
     * @readonly
     */

  }, {
    key: "extractUsedExtensions",

    /**
     * @summary 拡張機能の抽出
     *
     * @desc
     * <p>拡張機能固有オブジェクト extensions から extensionsUsed
     *    に存在するものだけを抽出する。</p>
     *
     * @param {object} extensions
     *
     * @return {object}
     */
    value: function extractUsedExtensions(extensions) {
      var dict = {};

      for (var key in extensions) {
        if (this._used_extensions.has(key)) {
          dict[key] = extensions[key];
        }
      }

      return dict;
    }
    /**
     * バッファデータの読み込みを開始
     * @param {mapray.gltf.Context} ctx  読み込みコンテキスト
     * @param {string}              url  バッファデータの URL
     * @private
     */

  }, {
    key: "loadBinary",
    value: function loadBinary(path) {
      return this._base_resource.loadSubResource(path, this._binary_type);
    }
  }, {
    key: "loadImage",
    value: function loadImage(path) {
      return this._base_resource.loadSubResource(path, this._image_type);
    }
    /**
     * バッファを検索
     * @param  {number} index        バッファ索引
     * @return {mapray.gltf.Buffer}  gltf.Buffer オブジェクト
     */

  }, {
    key: "findBuffer",
    value: function findBuffer(index) {
      if (this._buffer_entries[index] === undefined) {
        this._buffer_entries[index] = new BufferEntry(new Buffer(this, index));
      }

      return this._buffer_entries[index].buffer;
    }
    /**
     * イメージを検索
     * @param  {number} index       イメージ索引
     * @return {mapray.gltf.Image}  gltf.Image オブジェクト
     */

  }, {
    key: "findImage",
    value: function findImage(index) {
      if (this._image_entries[index] === undefined) {
        this._image_entries[index] = new ImageEntry(new Image$1(this, index));
      }

      return this._image_entries[index].image;
    }
    /**
     * gltf.Accessor を追加
     *
     * @param {mapray.gltf.Accessor} accessor  アクセサオブジェクト
     * @param {string}               usage     用途 ("ATTRIBUTE" | "INDEX")
     */

  }, {
    key: "addAccessor",
    value: function addAccessor(accessor, usage) {
      var entry = this._buffer_entries[accessor.bufferView.buffer.index];

      switch (usage) {
        case "ATTRIBUTE":
          entry.addAttributeAccessor(accessor);
          break;

        case "INDEX":
          entry.addIndexAccessor(accessor);
          break;
      }
    }
    /**
     * gltf.TextureInfo を追加
     *
     * @param {mapray.gltf.TextureInfo} info  テクスチャ情報
     */

  }, {
    key: "addTextureInfo",
    value: function addTextureInfo(info) {
      var image = info.texture.source;
      var entry = this._image_entries[image.index];
      entry.addTextureInfo(info);
    }
    /**
     * バイナリを読み込み始めたときの処理
     */

  }, {
    key: "onStartLoadBuffer",
    value: function onStartLoadBuffer() {
      this._load_count += 1;
    }
    /**
     * バイナリを読み込み終わったときの処理
     *
     * @param {Error} [error]  失敗したときのエラーオブジェクト
     */

  }, {
    key: "onFinishLoadBuffer",
    value: function onFinishLoadBuffer(error) {
      if (error) {
        this._load_error = error;
      }

      this._load_count -= 1;

      this._onFinishLoadSomething();
    }
    /**
     * 画像を読み込み始めたときの処理
     */

  }, {
    key: "onStartLoadImage",
    value: function onStartLoadImage() {
      this._load_count += 1;
    }
    /**
     * 画像を読み込み終わったときの処理
     *
     * @param {Error} [error]  失敗したときのエラーオブジェクト
     */

  }, {
    key: "onFinishLoadImage",
    value: function onFinishLoadImage(error) {
      if (error) {
        this._load_error = error;
      }

      this._load_count -= 1;

      this._onFinishLoadSomething();
    }
    /**
     * glTF 本体を読み込み終わったときの処理
     * @private
     */

  }, {
    key: "_onFinishLoadBody",
    value: function _onFinishLoadBody() {
      this._body_finished = true;

      this._onFinishLoadSomething();
    }
    /**
     * 何かを読み込み終わったときの処理
     * @private
     */

  }, {
    key: "_onFinishLoadSomething",
    value: function _onFinishLoadSomething() {
      if (this._settled) ; else if (this._load_error !== null) {
        // どこかで失敗した
        this._reject(this._load_error);

        this._settled = true;
      } else if (this._body_finished && this._load_count == 0) {
        // 外部ファイルも含めて、すべて読み込み終わった
        this._rewriteBuffersForByteOrder();

        this._splitBuffersAndRebuildAccessors();

        this._rebuildTextureInfo();

        this._resolve(new Content(this, this._scenes, this._default_scene_index));

        this._settled = true;
      }
    }
    /**
     * すべてのバッファのバイトオーダーを書き換える
     * @private
     */

  }, {
    key: "_rewriteBuffersForByteOrder",
    value: function _rewriteBuffersForByteOrder() {
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this._buffer_entries[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var entry = _step2.value;

          if (entry !== undefined) {
            entry.rewriteByteOrder();
          }
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
    }
    /**
     * バッファを分割し、Accessor を再構築
     * @private
     */

  }, {
    key: "_splitBuffersAndRebuildAccessors",
    value: function _splitBuffersAndRebuildAccessors() {
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = this._buffer_entries[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var entry = _step3.value;

          if (entry !== undefined) {
            entry.splitBufferAndRebuildAccessors();
          }
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }
    }
    /**
     * テクスチャ情報を再構築
     * @private
     */

  }, {
    key: "_rebuildTextureInfo",
    value: function _rebuildTextureInfo() {
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = this._image_entries[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var entry = _step4.value;

          if (entry !== undefined) {
            entry.rebuildTextureInfo();
          }
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) {
            _iterator4["return"]();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }
    }
  }, {
    key: "gjson",
    get: function get() {
      return this._gjson;
    }
  }]);

  return Context;
}();

/**
 * glTF 関連のツール
 *
 * @memberof mapray.gltf
 * @private
 */

var Tool =
/*#__PURE__*/
function () {
  function Tool() {
    _classCallCheck(this, Tool);
  }

  _createClass(Tool, null, [{
    key: "load",

    /**
     * @summary glTF データを解析してオブジェクトを構築
     *
     * @param  {object} body       データの本体 (JSON オブジェクト)
     * @param  {object} [options]  オプション集合
     * @param  {string} [options.base_resouece]     基底となるリソース
     * @param  {any} [options.binary_type]  バイナリタイプ
     * @param  {any} [options.image_type]   イメージタイプ
     * @param  {string[]} [options.supported_extensions]  ローダーを呼び出す側が対応できる glTF 拡張機能のリスト
     * @return {Promise}           読込み Promise (mapray.gltf.Content)
     */
    value: function load(body, options) {
      var context = new Context(body, options);
      return context.load();
    }
  }]);

  return Tool;
}();

/**
 * @summary シーンの読み込み
 * @memberof mapray
 */

var SceneLoader =
/*#__PURE__*/
function (_Loader) {
  _inherits(SceneLoader, _Loader);

  /**
   * @desc
   * <p>url で指定したシーンデータの読み込みを開始し、scene にエンティティを構築する。</p>
   * <p>読み込みが終了したとき options.callback を呼び出す。</p>
   * @param {mapray.Scene} scene      読み込み先のシーン
   * @param {string}       resource        シーンリソース
   * @param {object}       [options]  オプション集合
   * @param {mapray.SceneLoader.TransformCallback} [options.transform]  リソース要求変換関数
   * @param {mapray.SceneLoader.FinishCallback}    [options.callback]   終了コールバック関数
   */
  function SceneLoader(scene, resource) {
    var _this;

    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

    _classCallCheck(this, SceneLoader);

    if (resource instanceof Resource) ; else if (typeof resource === "string") {
      resource = new URLResource(resource, {
        type: "json",
        transform: options.transform
      });
    } else {
      throw new Error("Unsupported Resource: " + resource);
    }

    _this = _possibleConstructorReturn(this, _getPrototypeOf(SceneLoader).call(this, scene, resource, {
      onLoad: options.callback
    }));
    _this._transform = options.transform || defaultTransformCallback$1;
    _this._glenv = scene.glenv;
    _this._references = {};
    _this._finished = false;
    return _this;
  }
  /**
   * @summary オブジェクト参照を取得
   * @desc
   * <p>注意: シーンの読み込みが終了したことを確認してからこのメソッドを呼び出すこと。</p>
   * @param  {string}                                   id  識別子
   * @return {?(mapray.ModelContainer|mapray.Entity)}  オブジェクト
   */


  _createClass(SceneLoader, [{
    key: "getReference",
    value: function getReference(id) {
      var ref = this._references[id];
      return ref !== undefined ? ref : null;
    }
    /**
     * @summary オブジェクト参照を設定
     * @desc
     * <p>オブジェクト item を識別子 id で参照できるように this に設定する。</p>
     * @param {string}                                   id    識別子
     * @param {mapray.ModelContainer|mapray.Entity} item  オブジェクト
     * @private
     */

  }, {
    key: "_setReference",
    value: function _setReference(id, item) {
      // 参照を設定
      this._references[id] = item;
    }
  }, {
    key: "_load",
    value: function _load() {
      var _this2 = this;

      return this._resource.load(ResourceType.SCENE).then(function (oscene) {
        // JSON データの取得に成功
        _this2._check_cancel();

        return _this2._load_object(oscene);
      });
    }
    /**
     * JSON シーンオブジェクトを解析
     * @private
     */

  }, {
    key: "_load_object",
    value: function _load_object(oscene) {
      var _this3 = this;

      return Promise.resolve().then(function () {
        return _this3._load_model_register(oscene);
      }).then(function () {
        return _this3._postload_object(oscene);
      });
    }
    /**
     * 残りのオブジェクトを読み込む
     * @private
     */

  }, {
    key: "_postload_object",
    value: function _postload_object(oscene) {
      if (this.status !== Loader.Status.LOADING) return;

      this._load_entity_list(oscene);
    }
    /**
     * @private
     */

  }, {
    key: "_load_model_register",
    value: function _load_model_register(oscene) {
      var model_register = oscene["model_register"];
      if (!model_register) return;
      var keys = Object.keys(model_register);
      var asyncTasks = [];

      for (var i = 0; i < keys.length; ++i) {
        var id = keys[i];
        var model = model_register[id];
        asyncTasks.push(this._load_model_container(oscene, id, model));
      }

      return Promise.all(asyncTasks);
    }
    /**
     * @private
     */

  }, {
    key: "_load_model_container",
    value: function _load_model_container(oscene, id, model) {
      var _this4 = this;

      var url = model.link;
      if (!this._resource.resolveResourceSupported()) return Promise.reject(new Error("Sub Resource is not supported"));

      var gltf_resource = this._resource.resolveResource(url, ResourceType.MODEL);

      return gltf_resource.load(url, ResourceType.MODEL).then(function (json) {
        // モデルデータの取得に成功
        _this4._check_cancel(); // データを解析して gltf.Content を構築


        return Tool.load(json, {
          base_resource: gltf_resource,
          binary_type: ResourceType.BINARY,
          image_type: ResourceType.IMAGE,
          supported_extensions: ModelContainer.getSupportedExtensions_glTF()
        });
      }).then(function (content) {
        // モデルデータの構築に成功
        var container = new ModelContainer(_this4._scene, content);

        if (model.offset_transform) {
          var matrix = SceneLoader.parseOffsetTransform(model.offset_transform);
          container.setOffsetTransform(matrix);
        }

        _this4._setReference(id, container);
      });
    }
    /**
     * @private
     */

  }, {
    key: "_load_entity_list",
    value: function _load_entity_list(oscene) {
      var entity_list = oscene["entity_list"];
      if (!entity_list) return;
      var scene = this._scene;

      for (var i = 0; i < entity_list.length; ++i) {
        var item = entity_list[i];
        var type = item.type;
        var entity = null;

        switch (type) {
          case "markerline":
            entity = new MarkerLineEntity(scene, {
              json: item,
              refs: this._references
            });
            break;

          case "text":
            entity = new TextEntity(scene, {
              json: item,
              refs: this._references
            });
            break;

          case "model":
            entity = new ModelEntity(scene, {
              json: item,
              refs: this._references
            });
            break;

          case "polygon":
            entity = new PolygonEntity(scene, {
              json: item,
              refs: this._references
            });
            break;

          default:
            console.error("mapray: unknown entity type: " + type);
            break;
        }

        if (entity) {
          scene.addEntity(entity);
          var id = item.id;

          if (id) {
            this._setReference(id, entity);
          }
        }
      }
    }
    /**
     * スキーマ <OFFSET-TRANSFORM> のオブジェクトを解析
     *
     * @param  {object} offset_transform  <OFFSET-TRANSFORM> オブジェクト
     * @return {mapray.Matrix}            オフセット変換行列
     * @package
     */

  }], [{
    key: "parseOffsetTransform",
    value: function parseOffsetTransform(offset_transform) {
      var ot = offset_transform; // <OFFSET-TRANSFORM-PARAMS>

      var translate = ot.translate || [0, 0, 0];
      var orientation = new Orientation(ot.heading, ot.tilt, ot.roll);
      var scale = ot.scale !== undefined ? ot.scale : [1, 1, 1]; // <PARAM-SCALE3>

      if (typeof scale == 'number') {
        // スケールをベクトルに正規化
        scale = [scale, scale, scale];
      } // scale -> orientation -> translate 順の変換


      var matrix = GeoMath.createMatrix();
      orientation.getTransformMatrix(scale, matrix);
      matrix[12] = translate[0];
      matrix[13] = translate[1];
      matrix[14] = translate[2];
      return matrix;
    }
  }]);

  return SceneLoader;
}(Loader);
/**
 * @summary 終了コールバック
 * @callback FinishCallback
 * @desc
 * <p>シーンの読み込みが終了したときに呼び出される関数の型である。</p>
 * @param {mapray.SceneLoader} loader     読み込みを実行したローダー
 * @param {boolean}            isSuccess  成功したとき true, 失敗したとき false
 * @memberof mapray.SceneLoader
 */

/**
 * @summary リソース要求変換関数
 * @callback TransformCallback
 * @desc
 * <p>リソースのリクエスト時に URL などを変換する関数の型である。</p>
 *
 * @param  {string}                          url   変換前のリソース URL
 * @param  {mapray.SceneLoader.ResourceType} type  リソースの種類
 * @return {mapray.SceneLoader.TransformResult}    変換結果を表すオブジェクト
 *
 * @example
 * function( url, type ) {
 *     return {
 *         url:         url,
 *         credentials: mapray.CredentialMode.SAME_ORIGIN,
 *         headers: {
 *             'Header-Name': 'Header-Value'
 *         }
 *     };
 * }
 *
 * @memberof mapray.SceneLoader
 */

/**
 * @summary リソース要求変換関数の変換結果
 * @typedef {object} TransformResult
 * @desc
 * <p>関数型 {@link mapray.SceneLoader.TransformCallback} の戻り値のオブジェクト構造である。</p>
 * <p>注意: 現在のところ、リソースの種類が {@link mapray.SceneLoader.ResourceType|ResourceType}.IMAGE のとき、headers プロパティの値は無視される。</p>
 * @property {string}                url                 変換後のリソース URL
 * @property {mapray.CredentialMode} [credentials=OMIT]  クレデンシャルモード
 * @property {object}                [headers={}]        リクエストに追加するヘッダーの辞書 (キーがヘッダー名、値がヘッダー値)
 * @memberof mapray.SceneLoader
 */

/**
 * @summary リソースの種類
 * @enum {object}
 * @memberof mapray.SceneLoader
 * @constant
 * @see mapray.SceneLoader.TransformCallback
 */


var ResourceType = {
  /**
   * シーン JSON ファイル
   */
  SCENE: {
    id: "SCENE"
  },

  /**
   * モデルファイル
   */
  MODEL: {
    id: "MODEL"
  },

  /**
   * バイナリファイル
   */
  BINARY: {
    id: "BINARY"
  },

  /**
   * テクスチャ画像ファイル
   */
  IMAGE: {
    id: "IMAGE"
  }
};
SceneLoader.ResourceType = ResourceType;
SceneLoader._defaultHeaders = {};

function defaultTransformCallback$1(url, type) {
  return {
    url: url
  };
}

/**
 * @summary 追加コンテナの表示制御
 *
 * @class ContainerController
 */
var ContainerController =
/*#__PURE__*/
function () {
  /**
   * @summary コンストラクタ
   * @param {HTMLElement}                         container           ルートコンテナ(Viewerクラスのcontainer_element)
   * @param {object}                              options             表示オプション
   * @param {boolean}                             options.visibility  表示・非表示
   * @param {ContainerPosition}                   options.position    表示位置
   * @memberof ContainerController
   */
  function ContainerController(container, options) {
    _classCallCheck(this, ContainerController);

    this._visibility = options && options.visibility || true;
    this._position = options && options.position || ContainerPosition.TOP_LEFT;
    var container_element;

    if (typeof container == "string") {
      // コンテナを ID 指定したとき
      container_element = document.getElementById(container);
    } else {
      // コンテナを直接要素で指定のとき
      container_element = container;
    }

    this._viewer_container = container_element;
    this._container = null;
    this._is_compact = false;
    var self = this;
    window.addEventListener("resize", function () {
      self._sizeChanged();
    }, false);
  }
  /**
   * @summary 表示・非表示の設定
   *
   * @param {boolean} visibility
   * @memberof ContainerController
   */


  _createClass(ContainerController, [{
    key: "setVisibility",
    value: function setVisibility(visibility) {
      this._visibility = visibility; // 表示状態の更新

      this._setContainerVisibility();
    }
    /**
     * @summary 表示位置
     *
     * @param {ContainerPosition}   position
     * @memberof ContainerController
     */

  }, {
    key: "setPosition",
    value: function setPosition(position) {
      this._position = position; // コンテナの再作成

      this._deleteContainer();

      this.createContainer();
    }
    /**
     * @summary コンテナの表示設定
     *
     * @memberof ContainerController
     */

  }, {
    key: "_setContainerVisibility",
    value: function _setContainerVisibility() {
      if (this._container) {
        this._visibility ? this._container.style.visibility = "visible" : this._container.style.visibility = "collapse";
      }
    }
    /**
     * @summary インスタンスの破棄
     *
     * @memberof ContainerController
     */

  }, {
    key: "_destroy",
    value: function _destroy() {
      var self = this;
      window.removeEventListener("resize", function () {
        self._sizeChanged();
      }, false);

      this._deleteContainer();
    }
    /**
     * @summary 追加コンテナの削除
     *
     * @memberof ContainerController
     */

  }, {
    key: "_deleteContainer",
    value: function _deleteContainer() {
      var parent_container = this._container.parentElement;
      parent_container.removeChild(this._container);
      this._container = null;
    }
    /**
     * @summary リサイズイベント
     *
     * @memberof ContainerController
     * @abstract
     */

  }, {
    key: "_sizeChanged",
    value: function _sizeChanged() {}
    /**
     * @summary 追加コンテナの作成
     *
     * @memberof ContainerController
     * @abstract
     */

  }, {
    key: "createContainer",
    value: function createContainer() {}
  }]);

  return ContainerController;
}();
/**
 * @summary ロゴ・著作権表示位置の列挙型
 * @enum {object}
 * @memberof ContainerController
 * @constant
 */


var ContainerPosition = {
  /**
   * 左上
   */
  TOP_LEFT: {
    id: "top-left"
  },

  /**
   * 右上
   */
  TOP_RIGHT: {
    id: "top-right"
  },

  /**
   * 左下
   */
  BOTTOM_LEFT: {
    id: "bottom-left"
  },

  /**
   * 右下
   */
  BOTTOM_RIGHT: {
    id: "bottom-right"
  }
};
{
  ContainerController._compact_size = 500;
  ContainerController.ContainerPosition = ContainerPosition;
}

/**
 * @summary ロゴの表示制御
 *
 * @class LogoController
 * @extends {mapray.ContainerController}
 */

var LogoController =
/*#__PURE__*/
function (_ContainerController) {
  _inherits(LogoController, _ContainerController);

  /**
   * @summary コンストラクタ
   * @param {HTMLElement}                                 container           ルートコンテナ(Viewerクラスのcontainer_element)
   * @param {object}                                      options             表示オプション
   * @param {boolean}                                     options.visibility  表示・非表示
   * @param {ContainerController.ContainerPosition}       options.position    表示位置
   * @memberof LogoController
   */
  function LogoController(container, options) {
    var _this;

    _classCallCheck(this, LogoController);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(LogoController).call(this, container, options));
    _this._position = options && options.position || ContainerController.ContainerPosition.BOTTOM_LEFT;
    return _this;
  }
  /**
   * @summary リサイズイベント
   *
   * @memberof LogoController
   */


  _createClass(LogoController, [{
    key: "_sizeChanged",
    value: function _sizeChanged() {
      if (this._container) {
        var sub_container = this._container.children[0];
        var parent_container = this._container.parentElement;

        if (parent_container.parentElement.clientWidth < ContainerController._compact_size) {
          sub_container.classList.add("mapray-logo-compact");
        } else {
          sub_container.classList.remove("mapray-logo-compact");
        }
      }
    }
    /**
     * @summary 追加コンテナの作成
     *
     * @memberof LogoController
     */

  }, {
    key: "createContainer",
    value: function createContainer() {
      var name = "control-" + this._position.id;

      var parent_container = this._viewer_container.getElementsByClassName(name)[0];

      var main_container = document.createElement("div");
      main_container.className = "control";
      var sub_container = document.createElement("a");
      sub_container.className = "mapray-logo";
      sub_container.href = "https://mapray.com";
      sub_container.target = "_blank";
      main_container.appendChild(sub_container);
      this._container = main_container;
      parent_container.appendChild(this._container);

      this._sizeChanged();
    }
  }]);

  return LogoController;
}(ContainerController);

/**
 * @summary 著作権表示の表示制御
 *
 * @class AttributionController
 * @extends {mapray.ContainerController}
 */

var AttributionController =
/*#__PURE__*/
function (_ContainerController) {
  _inherits(AttributionController, _ContainerController);

  /**
   * @summary コンストラクタ
   * @param {HTMLElement}                             container                       ルートコンテナ(Viewerクラスのcontainer_element)
   * @param {object}                                  options                         表示オプション
   * @param {boolean}                                 options.isVisible               表示・非表示
   * @param {ContainerController.ContainerPosition}   options.position                表示位置
   * @param {array}                                   options.attributions            著作権リスト
   * @param {string}                                  options.attributions.display    表示名
   * @param {string}                                  options.attributions.link       リンク
   * @memberof AttributionController
   */
  function AttributionController(container, options) {
    var _this;

    _classCallCheck(this, AttributionController);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(AttributionController).call(this, container, options));
    _this._position = options && options.position || ContainerController.ContainerPosition.BOTTOM_RIGHT;
    _this._attributions = [];

    if (options && options.attributions) {
      _this.copyAttributions(options.attributions);
    } else {
      _this.copyAttributions(AttributionController._default_attribution);
    }

    return _this;
  }
  /**
   * @summary 著作権表示の追加
   *
   * @param {object}  attribution            著作権表示オブジェクト
   * @param {string}  attribution.display    表示名
   * @param {string}  attribution.link       リンク
   * @memberof AttributionController
   */


  _createClass(AttributionController, [{
    key: "addAttribution",
    value: function addAttribution(attribution) {
      this._attributions.push(attribution); // コンテナの再作成


      this._deleteContainer();

      this.createContainer();
    }
    /**
     * @summary 著作権表示のリセット
     *
     * @memberof AttributionController
     */

  }, {
    key: "clearAttribution",
    value: function clearAttribution() {
      this._attributions = []; // コンテナの再作成

      this._deleteContainer();

      this.createContainer();
    }
    /**
     * @summary リサイズイベント
     *
     * @memberof AttributionController
     */

  }, {
    key: "_sizeChanged",
    value: function _sizeChanged() {
      if (this._container) {
        var parent_container = this._container.parentElement;

        if (parent_container.parentElement.clientWidth < ContainerController._compact_size) {
          this._container.classList.add("mapray-attribution-compact");
        } else {
          this._container.classList.remove("mapray-attribution-compact");
        }
      }
    }
    /**
     * @summary 追加コンテナの作成
     *
     * @memberof AttributionController
     */

  }, {
    key: "createContainer",
    value: function createContainer() {
      var name = "control-" + this._position.id;

      var parent_container = this._viewer_container.getElementsByClassName(name)[0];

      var main_container = document.createElement("div");
      main_container.classList.add("control");
      main_container.classList.add("mapray-attribution");
      var sub_container = document.createElement("div");
      sub_container.classList.add("mapray-attribution-container");
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this._attributions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var attribution = _step.value;

          if (attribution.display) {
            var attribution_container = document.createElement("a");

            if (attribution.link) {
              attribution_container.href = attribution.link;
              attribution_container.target = "_blank";
            }

            var text = document.createTextNode(attribution.display);
            attribution_container.appendChild(text);
            sub_container.appendChild(attribution_container);
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      main_container.appendChild(sub_container);
      this._container = main_container;
      parent_container.appendChild(this._container);

      this._sizeChanged();
    }
  }, {
    key: "copyAttributions",
    value: function copyAttributions(src) {
      this._attributions = src.map(function (d) {
        return d;
      });
    }
  }]);

  return AttributionController;
}(ContainerController); // クラス変数の定義


{
  AttributionController._default_attribution = [{
    display: "©Mapray",
    link: "https://mapray.com"
  }, {
    display: "©JAXA",
    link: "http://www.jaxa.jp/"
  }, {
    display: "測量法に基づく国土地理院長承認(複製)H30JHf626",
    link: "https://www.gsi.go.jp/kiban/index.html"
  }];
}

/**
 * @summary 表示管理
 * @classdesc
 * <p>mapray の表示を管理するクラスである。</p>
 * @memberof mapray
 */

var Viewer =
/*#__PURE__*/
function () {
  /**
   * @param {string|Element}                  container                           コンテナ (ID または要素)
   * @param {object}                          [options]                           生成オプション
   * @param {mapray.DemProvider}              [options.dem_provider]              DEM プロバイダ
   * @param {mapray.ImageProvider}            [options.image_provider]            画像プロバイダ
   * @param {array}                           [options.layers]                    地図レイヤー情報の配列
   * @param {boolean}                         [options.ground_visibility=true]    地表の可視性
   * @param {boolean}                         [options.entity_visibility=true]    エンティティの可視性
   * @param {mapray.RenderCallback}           [options.render_callback]           レンダリングコールバック
   * @param {mapray.Viewer.RenderMode}        [options.render_mode]               レンダリングモード
   * @param {mapray.DebugStats}               [options.debug_stats]               デバッグ統計オブジェクト
   * @param {mapray.LogoController}           [options.logo_controller]           ロゴ表示制御オブジェクト
   * @param {mapray.AttributionController}    [options.attribution_controller]    著作権表示制御オブジェクト
   */
  function Viewer(container, options) {
    _classCallCheck(this, Viewer);

    var container_element;

    if (typeof container == "string") {
      // コンテナを ID 指定したとき
      container_element = document.getElementById(container);
    } else {
      // コンテナを直接要素で指定のとき
      container_element = container;
    }

    var canvas = this._createCanvas(container_element); // インスタンス変数


    this._container_element = container_element;
    this._canvas_element = canvas;
    this._glenv = new GLEnv(canvas);
    this._camera = new Camera(canvas);
    this._animation = this._createAnimationBindingBlock();
    this._dem_provider = this._createDemProvider(options);
    this._image_provider = this._createImageProvider(options);
    this._layers = this._createLayerCollection(options);
    this._globe = new Globe(this._glenv, this._dem_provider);
    this._tile_texture_cache = new TileTextureCache(this._glenv, this._image_provider);
    this._scene = new Scene(this, this._glenv);
    this._ground_visibility = Viewer._getBoolOption(options, "ground_visibility", true);
    this._entity_visibility = Viewer._getBoolOption(options, "entity_visibility", true);
    this._render_mode = options && options.render_mode || RenderMode.SURFACE;
    this._debug_stats = options && options.debug_stats || null;
    this._render_callback = this._createRenderCallback(options);
    this._frame_req_id = 0;
    this._previous_time = undefined;
    this._is_destroyed = false; // マウス・Attribution開発

    this._logo_controller = options && options.logo_controller || new LogoController(this._container_element);
    this._attribution_controller = options && options.attribution_controller || new AttributionController(this._container_element); // ロゴ・著作権表示用コンテナの作成

    this._createLogoAttributionContainer();

    this._logo_controller.createContainer();

    this._attribution_controller.createContainer(); // 最初のフレームの準備


    this._requestNextFrame();

    this._updateCanvasSize();
  }
  /**
   * @summary インスタンスを破棄
   *
   * @desc
   * <p>次の順番で処理を行い、インスタンスを破棄する。</p>
   *
   * <ol>
   *   <li>アニメーションフレームを止める。(this.{@link mapray.Viewer#render_callback render_callback} の {@link mapray.RenderCallback#onUpdateFrame onUpdateFrame()} が呼び出されなくなる)</li>
   *   <li>this.{@link mapray.Viewer#render_callback render_callback} の {@link mapray.RenderCallback#onStop onStop()} を呼び出す。({@link mapray.RenderCallback#onStart onStart()} がすでに呼び出されている場合)</li>
   *   <li>{@link mapray.RenderCallback} インスタンスを this から切り離す。({@link mapray.RenderCallback#viewer} プロパティは null を返すようになる)</li>
   *   <li>this.{@link mapray.Viewer#canvas_element canvas_element} を this.{@link mapray.Viewer#container_element container_element} から取り外す。(キャンバスは表示されなくなる)</li>
   *   <li>データプロバイダのリクエスト、シーンデータのロードの取り消しを試みる。</li>
   * </ol>
   *
   * <p>このメソッドを呼び出した後は this に直接的または間接的にアクセスすることはできない。ただし {@link mapray.Viewer#destroy destroy()} の呼び出しは除く。</p>
   *
   * <p>このメソッドは {@link mapray.RenderCallback} のメソッドから呼び出してはならない。</p>
   */


  _createClass(Viewer, [{
    key: "destroy",
    value: function destroy() {
      if (this._is_destroyed) {
        // すでに this は破棄済み
        return;
      } // フレームを止める


      if (this._frame_req_id != 0) {
        window.maprayCancelAnimationFrame(this._frame_req_id);
        this._frame_req_id = 0;
      } // RenderCallback の取り外し


      this._render_callback.detach();

      this._render_callback = this._createRenderCallback(); // NullRenderCallback
      // キャンバスをコンテナから外す

      this._container_element.removeChild(this._canvas_element); // DemProvider のリクエストを取り消す


      this._globe.cancel(); // ImageProvider のリクエストを取り消す


      this._tile_texture_cache.cancel(); // 各レイヤーの のリクエストを取り消す


      this._layers.cancel(); // 各 SceneLoader の読み込みを取り消す


      this._scene.cancelLoaders(); // マウス・Attribution開発


      this._logo_controller._destroy();

      this._attribution_controller._destroy();

      this._attribution_controller = null; // ロゴ・著作権用コンテナの削除

      this._deleteLogoAttributionContainer(); // 破棄確定


      this._is_destroyed = true;
    }
    /**
     * キャンバス要素を生成
     * @param  {Element}           container
     * @return {HTMLCanvasElement}
     * @private
     */

  }, {
    key: "_createCanvas",
    value: function _createCanvas(container) {
      var canvas = document.createElement("canvas");
      canvas.className = "mapray-canvas";
      canvas.style.width = "100%";
      canvas.style.height = "100%";
      container.appendChild(canvas);
      return canvas;
    }
    /**
     * DemProvider を生成
     * @private
     */

  }, {
    key: "_createDemProvider",
    value: function _createDemProvider(options) {
      if (options && options.dem_provider) return options.dem_provider;else return new StandardDemProvider("/dem/", ".bin");
    }
    /**
     * animation.BindingBlock を生成
     * @private
     */

  }, {
    key: "_createAnimationBindingBlock",
    value: function _createAnimationBindingBlock() {
      var _this = this;

      var abb = new EasyBindingBlock();
      abb.addDescendantUnbinder(function () {
        _this._unbindDescendantAnimations();
      });
      return abb;
    }
    /**
     * ImageProvider を生成
     * @private
     */

  }, {
    key: "_createImageProvider",
    value: function _createImageProvider(options) {
      if (options && options.image_provider) return options.image_provider;else return new StandardImageProvider("http://cyberjapandata.gsi.go.jp/xyz/std/", ".png", 256, 0, 18);
    }
    /**
     * LayerCollection を生成
     * @private
     */

  }, {
    key: "_createLayerCollection",
    value: function _createLayerCollection(options) {
      var layers = options && options.layers ? options.layers : {};
      return new LayerCollection(this._glenv, layers);
    }
    /**
     * RenderCallback を生成
     * @private
     */

  }, {
    key: "_createRenderCallback",
    value: function _createRenderCallback(options) {
      var callback;
      if (options && options.render_callback) callback = options.render_callback;else callback = new NullRenderCallback();
      callback.attach(this);
      return callback;
    }
    /**
     * @summary ロゴ・著作権表示用コンテナの作成
     *
     * @memberof Viewer
     */

  }, {
    key: "_createLogoAttributionContainer",
    value: function _createLogoAttributionContainer() {
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = Viewer._positions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var position = _step.value;
          var container = document.createElement("div");
          container.className = position;

          this._container_element.appendChild(container);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    }
    /**
     * @summary ロゴ・著作権表示用コンテナの削除
     *
     * @memberof Viewer
     */

  }, {
    key: "_deleteLogoAttributionContainer",
    value: function _deleteLogoAttributionContainer() {
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = Viewer._positions[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var position = _step2.value;
          var container = document.getElementById(position);

          if (container) {
            this._container_element.removeChild(position);
          }
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
    }
    /**
     * ブール値のオプションを取得
     * @private
     */

  }, {
    key: "setVisibility",

    /**
     * @summary 可視性を設定
     * @desc
     * <p>target に属するオブジェクトを表示するかどうかを指定する。</p>
     * <p>可視性は Viewer の構築子の ground_visibility と entity_visibility オプションでも指定することができる。</p>
     *
     * @param {mapray.Viewer.Category} target      表示対象
     * @param {boolean}                visibility  表示するとき true, 表示しないとき false
     *
     * @see {@link mapray.Viewer#getVisibility}
     */
    value: function setVisibility(target, visibility) {
      switch (target) {
        case Category.GROUND:
          this._ground_visibility = visibility;
          break;

        case Category.ENTITY:
          this._entity_visibility = visibility;
          break;

        default:
          throw new Error("invalid target: " + target);
      }
    }
    /**
     * @summary 可視性を取得
     * @desc
     * <p>target に属するオブジェクトを表示するかどうかを取得する。</p>
     *
     * @param  {mapray.Viewer.Category} target  表示対象
     * @return {boolean}  表示するとき true, 表示しないとき false
     *
     * @see {@link mapray.Viewer#setVisibility}
     */

  }, {
    key: "getVisibility",
    value: function getVisibility(target, visibility) {
      switch (target) {
        case Category.GROUND:
          return this._ground_visibility;

        case Category.ENTITY:
          return this._entity_visibility;

        default:
          throw new Error("invalid target: " + target);
      }
    }
    /**
     * @summary 指定位置の標高を取得
     * @desc
     * <p>緯度 lat, 経度 lon が示す場所の標高を返す。</p>
     * <p>現在メモリに存在する DEM データの中で最も正確度が高いデータから標高を計算する。</p>
     * <p>さらに正確度が高い DEM データがサーバーに存在すれば、それを非同期に読み込む。そのため時間を置いてこのメソッドを呼び出すと、さらに正確な値が取得できることがある。</p>
     * @param  {number} lat  緯度 (Degrees)
     * @param  {number} lon  経度 (Degrees)
     * @return {number}      標高 (Meters)
     */

  }, {
    key: "getElevation",
    value: function getElevation(lat, lon) {
      // 正規化緯経度 (Degrees)
      var _lon = lon + 180 * Math.floor((90 - lat) / 360 + Math.floor((90 + lat) / 360));

      var nlat = 90 - Math.abs(90 - lat + 360 * Math.floor((90 + lat) / 360)); // 正規化緯度 [-90,90]

      var nlon = _lon - 360 - 360 * Math.floor((_lon - 180) / 360); // 正規化緯度 [-180,180)
      // 単位球メルカトル座標

      var xm = nlon * GeoMath.DEGREE;
      var ym = GeoMath.invGudermannian(nlat * GeoMath.DEGREE); // 基底タイル座標 (左上(0, 0)、右下(1, 1))

      var dPI = 2 * Math.PI;
      var xt = xm / dPI + 0.5;
      var yt = 0.5 - ym / dPI;

      if (yt < 0 || yt > 1) {
        // 緯度が Web メルカトルの範囲外 (極に近い)
        return 0;
      } // 正確度が最も高い DEM タイルの取得


      var globe = this._globe;
      var dem = globe.findHighestAccuracy(xt, yt);

      if (dem === null) {
        // まだ標高を取得することができない
        return 0;
      } // 標高をサンプル


      var ρ = globe.dem_provider.getResolutionPower();
      var size = 1 << ρ; // 2^ρ

      var pow = Math.pow(2, dem.z); // 2^ze

      var uf = size * (pow * xt - dem.x);
      var vf = size * (pow * yt - dem.y);
      var ui = GeoMath.clamp(Math.floor(uf), 0, size - 1);
      var vi = GeoMath.clamp(Math.floor(vf), 0, size - 1);
      var heights = dem.getHeights(ui, vi);
      var h00 = heights[0];
      var h10 = heights[1];
      var h01 = heights[2];
      var h11 = heights[3]; // 標高を補間

      var s = uf - ui;
      var t = vf - vi;
      return (h00 * (1 - s) + h10 * s) * (1 - t) + (h01 * (1 - s) + h11 * s) * t;
    }
    /**
     * @summary 現行の標高を取得
     *
     * @desc
     * <p>現在メモリーにある最高精度の標高値を取得する。</p>
     * <p>まだ DEM データが存在しない、または経度, 緯度が範囲外の場所は標高を 0 とする。</p>
     *
     * <p>このメソッドは DEM のリクエストは発生しない。また DEM のキャッシュには影響を与えない。</p>
     *
     * <p>一般的に画面に表示されていない場所は標高の精度が低い。</p>
     *
     * @param  {mapray.GeoPoint} position  位置 (高度は無視される)
     * @return {number}                    標高
     *
     * @see mapray.Viewer#getExistingElevations
     */

  }, {
    key: "getExistingElevation",
    value: function getExistingElevation(position) {
      var array = [position.longitude, position.latitude, 0];

      this._globe.getExistingElevations(1, array, 0, 3, array, 2, 3);

      return array[2];
    }
    /**
     * @summary 現行の標高 (複数) を取得
     *
     * @desc
     * <p>現在メモリーにある最高精度の標高値を一括で取得する。</p>
     * <p>まだ DEM データが存在しない、または経度, 緯度が範囲外の場所は標高を 0 とする。</p>
     *
     * <p>このメソッドは DEM のリクエストは発生しない。また DEM のキャッシュには影響を与えない。</p>
     *
     * <p>一般的に画面に表示されていない場所は標高の精度が低い。</p>
     *
     * @param  {number}   num_points  入出力データ数
     * @param  {number[]} src_array   入力配列 (経度, 緯度, ...)
     * @param  {number}   src_offset  入力データの先頭インデックス
     * @param  {number}   src_stride  入力データのストライド
     * @param  {number[]} dst_array   出力配列 (標高, ...)
     * @param  {number}   dst_offset  出力データの先頭インデックス
     * @param  {number}   dst_stride  出力データのストライド
     * @return {number[]}             dst_array
     *
     * @see mapray.Viewer#getExistingElevation
     */

  }, {
    key: "getExistingElevations",
    value: function getExistingElevations(num_points, src_array, src_offset, src_stride, dst_array, dst_offset, dst_stride) {
      return this._globe.getExistingElevations(num_points, src_array, src_offset, src_stride, dst_array, dst_offset, dst_stride);
    }
    /**
     * @summary レイと地表の交点を取得
     * @desc
     * <p>ray と地表の最も近い交点を取得する。ただし交点が存在しない場合は null を返す。</p>
     * @param  {mapray.Ray}      ray  レイ (GOCS)
     * @return {?mapray.Vector3}      交点または null
     */

  }, {
    key: "getRayIntersection",
    value: function getRayIntersection(ray) {
      var globe = this._globe;

      if (globe.status !== Globe.Status.READY) {
        // Globe の準備ができていない
        return null;
      }

      var distance = globe.root_flake.findRayDistance(ray, Number.MAX_VALUE);

      if (distance === Number.MAX_VALUE) {
        // 交点が見つからなかった
        return null;
      } // P = Q + distance V


      var p = GeoMath.createVector3();
      var q = ray.position;
      var v = ray.direction;
      p[0] = q[0] + distance * v[0];
      p[1] = q[1] + distance * v[1];
      p[2] = q[2] + distance * v[2];
      return p;
    }
    /**
     * 次のフレーム更新を要求する。
     * @private
     */

  }, {
    key: "_requestNextFrame",
    value: function _requestNextFrame() {
      var _this2 = this;

      this._frame_req_id = window.maprayRequestAnimationFrame(function () {
        return _this2._updateFrame();
      });
    }
    /**
     * フレーム更新のときに呼び出される。
     * @private
     * @see mapray.RenderStage
     */

  }, {
    key: "_updateFrame",
    value: function _updateFrame() {
      var delta_time = this._updateTime();

      this._requestNextFrame();

      this._updateCanvasSize();

      this._render_callback.onUpdateFrameInner(delta_time);

      if (this._debug_stats !== null) {
        this._debug_stats.clearStats();
      }

      var stage = new RenderStage(this);
      stage.render();

      this._finishDebugStats();
    }
    /**
     * @summary 時間の更新
     * @return {number}  前フレームからの経過時間 (秒)
     * @private
     */

  }, {
    key: "_updateTime",
    value: function _updateTime() {
      var now_time = window.maprayNow();
      var delta_time = this._previous_time !== undefined ? (now_time - this._previous_time) / 1000 : 0;
      this._previous_time = now_time;
      return delta_time;
    }
    /**
     * @summary Canvas サイズを更新
     * @private
     */

  }, {
    key: "_updateCanvasSize",
    value: function _updateCanvasSize() {
      var canvas = this._canvas_element; // 要素のサイズとキャンバスのサイズを一致させる

      if (canvas.width != canvas.clientWidth) {
        canvas.width = canvas.clientWidth;
      }

      if (canvas.height != canvas.clientHeight) {
        canvas.height = canvas.clientHeight;
      }
    }
    /**
     * @summary デバッグ統計の最終処理
     * @private
     */

  }, {
    key: "_finishDebugStats",
    value: function _finishDebugStats() {
      var stats = this._debug_stats;

      if (stats === null) {
        // 統計オブジェクトは指定されていない
        return;
      } // 統計値の取得


      stats.num_wait_reqs_dem = this._globe.getNumDemWaitingRequests();
      stats.num_wait_reqs_img = this._tile_texture_cache.getNumWaitingRequests(); // 統計の更新を通知

      stats.onUpdate();
    }
    /**
     * EasyBindingBlock.DescendantUnbinder 処理
     *
     * @private
     */

  }, {
    key: "_unbindDescendantAnimations",
    value: function _unbindDescendantAnimations() {
      this._scene.animation.unbindAllRecursively();
    }
  }, {
    key: "container_element",

    /**
     * @summary コンテナ要素 (キャンバス要素を保有する)
     * @type {Element}
     * @readonly
     */
    get: function get() {
      return this._container_element;
    }
    /**
     * @summary キャンバス要素
     * @type {Element}
     * @readonly
     */

  }, {
    key: "canvas_element",
    get: function get() {
      return this._canvas_element;
    }
    /**
     * @summary アニメーションパラメータ設定
     * @type {mapray.animation.BindingBlock}
     * @readonly
     */

  }, {
    key: "animation",
    get: function get() {
      return this._animation;
    }
    /**
     * DEM データプロバイダ
     * @type {mapray.DemProvider}
     * @readonly
     */

  }, {
    key: "dem_provider",
    get: function get() {
      return this._dem_provider;
    }
    /**
     * @summary 画像プロバイダ
     * @type {mapray.ImageProvider}
     * @readonly
     */

  }, {
    key: "image_provider",
    get: function get() {
      return this._image_provider;
    }
    /**
     * @summary 地図レイヤー管理
     * @type {mapray.LayerCollection}
     * @readonly
     */

  }, {
    key: "layers",
    get: function get() {
      return this._layers;
    }
    /**
     * @summary レンダリングコールバック
     * @type {mapray.RenderCallback}
     * @readonly
     */

  }, {
    key: "render_callback",
    get: function get() {
      return this._render_callback;
    }
    /**
     * @summary レンダリングモード
     * @type {mapray.RenderMode}
     * @readonly
     */

  }, {
    key: "render_mode",
    get: function get() {
      return this._render_mode;
    }
    /**
     * @summary レンダリングモードを設定
     * @type {mapray.RenderMode}
     */
    ,
    set: function set(val) {
      this._render_mode = val;
    }
    /**
     * @summary デバッグ統計オブジェクト
     * @type {?mapray.DebugStats}
     * @readonly
     */

  }, {
    key: "debug_stats",
    get: function get() {
      return this._debug_stats;
    }
    /**
     * @summary カメラ
     * @type {mapray.Camera}
     * @readonly
     */

  }, {
    key: "camera",
    get: function get() {
      return this._camera;
    }
    /**
     * @summary モデルシーン
     * @type {mapray.Scene}
     * @readonly
     */

  }, {
    key: "scene",
    get: function get() {
      return this._scene;
    }
    /**
     * 内部的に実装で使用される WebGL レンダリングコンテキスト情報
     * @type {mapray.GLEnv}
     * @readonly
     * @package
     */

  }, {
    key: "glenv",
    get: function get() {
      return this._glenv;
    }
    /**
     * @type {mapray.Globe}
     * @readonly
     * @package
     */

  }, {
    key: "globe",
    get: function get() {
      return this._globe;
    }
    /**
     * 内部的に実装で使用される地図画像タイル管理
     * @type {mapray.TileTextureCache}
     * @readonly
     * @package
     */

  }, {
    key: "tile_texture_cache",
    get: function get() {
      return this._tile_texture_cache;
    }
    /**
     *
     * @type {mapray.LogoController}
     * @readonly
     * @memberof Viewer
     */

  }, {
    key: "logo_controller",
    get: function get() {
      return this._logo_controller;
    }
    /**
     *
     * @type {mapray.AttributionController}
     * @readonly
     * @memberof Viewer
     */

  }, {
    key: "attribution_controller",
    get: function get() {
      return this._attribution_controller;
    }
  }], [{
    key: "_getBoolOption",
    value: function _getBoolOption(options, name, defaultValue) {
      return options && options[name] !== undefined ? options[name] : defaultValue;
    }
  }]);

  return Viewer;
}();
/**
 * @summary 表示対象の列挙型
 * @desc
 * <p>{@link mapray.Viewer#setVisibility} と {@link mapray.Viewer#getVisibility} メソッドの target 引数に指定する値の型である。</p>
 * @enum {object}
 * @memberof mapray.Viewer
 * @constant
 */


var Category = {
  /**
   * 地表 (レイヤーも含む)
   */
  GROUND: {
    id: "GROUND"
  },

  /**
   * エンティティ
   */
  ENTITY: {
    id: "ENTITY"
  }
};
/**
 * @summary レンダリングモードの列挙型
 * @desc
 * {@link mapray.Viewer} の構築子の options.render_mode パラメータ、または {@link mapray.Viewer#render_mode} プロパティに指定する値の型である。
 * @enum {object}
 * @memberof mapray.Viewer
 * @constant
 */

var RenderMode = {
  /**
   * ポリゴン面 (既定値)
   */
  SURFACE: {
    id: "SURFACE"
  },

  /**
   * ワイヤーフレーム
   */
  WIREFRAME: {
    id: "WIREFRAME"
  }
}; // クラス定数の定義

{
  Viewer.Category = Category;
  Viewer.RenderMode = RenderMode; // マウス・Attribution開発

  Viewer.ContainerPosition = ContainerController.ContainerPosition; // ロゴ・著作権表示用コンテナ名称

  Viewer._positions = ["control-top-left", "control-top-right", "control-bottom-left", "control-bottom-right"];
}

/**
 * @summary クラウド DEM プロバイダ
 * @memberof mapray
 * @extends mapray.DemProvider
 */

var CloudDemProvider =
/*#__PURE__*/
function (_DemProvider) {
  _inherits(CloudDemProvider, _DemProvider);

  /**
   * @param {string} api_key  API キーの文字列
   */
  function CloudDemProvider(api_key) {
    var _this;

    _classCallCheck(this, CloudDemProvider);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(CloudDemProvider).call(this));
    _this._headers = {
      'X-Api-Key': api_key
    };
    return _this;
  }
  /**
   * @override
   */


  _createClass(CloudDemProvider, [{
    key: "requestTile",
    value: function requestTile(z, x, y, callback) {
      var actrl = new AbortController();
      fetch(this._makeURL(z, x, y), {
        headers: this._headers,
        signal: actrl.signal
      }).then(function (response) {
        return response.ok ? response.arrayBuffer() : Promise.reject(Error(response.statusText));
      }).then(function (buffer) {
        // データ取得に成功
        callback(buffer);
      })["catch"](function () {
        // データ取得に失敗または取り消し
        callback(null);
      });
      return actrl;
    }
    /**
     * @override
     */

  }, {
    key: "cancelRequest",
    value: function cancelRequest(id) {
      var actrl = id; // 要求 ID を AbortController に変換

      actrl.abort(); // 取り消したので要求を中止
    }
    /**
     * URL を作成
     * @private
     */

  }, {
    key: "_makeURL",
    value: function _makeURL(z, x, y) {
      return 'https://tiles.mapray.com/dem/' + z + '/' + x + '/' + y + '.bin';
    }
  }]);

  return CloudDemProvider;
}(DemProvider);

var pin_vs_code = "/**\n * テキスト (頂点シェーダ)\n */\n\nattribute vec4 a_position;     // 頂点位置 (モデル座標系)\nattribute vec2 a_offset;       // 頂点変位 (スクリーン座標系)\nattribute vec2 a_texcoord;     // テクスチャ座標\nattribute vec2 a_texmaskcoord; // テクスチャマスク座標\nattribute vec3 a_fg_color;     // 前景色\nattribute vec3 a_bg_color;     // 背景色\n\nuniform mat4 u_obj_to_clip;    // モデル座標系からクリップ座標系への変換\nuniform vec2 u_sparam;         // 画面パラメータ: {2/w, 2/h}\n\nvarying vec2 v_texcoord;       // テクスチャ座標\nvarying vec2 v_texmaskcoord;   // テクスチャマスク座標\nvarying vec3 v_fg_color;       // 前景色\nvarying vec3 v_bg_color;       // 背景色\n\nvoid\nmain()\n{\n    gl_Position = u_obj_to_clip * a_position;\n    gl_Position.xy += a_offset * u_sparam * gl_Position.w;\n    v_texcoord = a_texcoord;\n    v_texmaskcoord = a_texmaskcoord;\n    v_fg_color = a_fg_color;\n    v_bg_color = a_bg_color;\n}\n";

var pin_fs_code = "/**\n * テキスト (フラグメントシェーダ)\n */\n\nprecision mediump float;\n\nvarying vec2 v_texcoord;        // アイコンのテクスチャ座標\nvarying vec2 v_texmaskcoord;    // アイコンマスクのテクスチャ座標\nvarying vec3 v_fg_color;        // 前景色\nvarying vec3 v_bg_color;        // 背景色\n\nuniform sampler2D u_image;      // アイコン画像\nuniform sampler2D u_image_mask; // アイコンマスク画像\n\n\nvoid\nmain()\n{\n    float alpha = texture2D( u_image, v_texcoord ).w;          // 輝度\n    float mask = texture2D( u_image_mask, v_texmaskcoord ).w;  // マスク\n    alpha *= mask;\n    gl_FragColor = vec4(v_fg_color * alpha + v_bg_color * (1.0 - alpha), 1.0);\n}\n";

/**
 * @summary テキストマテリアル
 * @memberof mapray
 * @extends mapray.EntityMaterial
 * @private
 * @see mapray.PinEntity
 */

var PinMaterial =
/*#__PURE__*/
function (_EntityMaterial) {
  _inherits(PinMaterial, _EntityMaterial);

  /**
   * @param {mapray.GLEnv} glenv
   */
  function PinMaterial(glenv) {
    var _this;

    _classCallCheck(this, PinMaterial);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(PinMaterial).call(this, glenv, pin_vs_code, pin_fs_code)); // 不変パラメータを事前設定

    _this.bindProgram();

    _this.setInteger("u_image", PinMaterial.TEXUNIT_IMAGE);

    _this.setInteger("u_image_mask", PinMaterial.TEXUNIT_IMAGE_MASK);

    return _this;
  }
  /**
   * @override
   */


  _createClass(PinMaterial, [{
    key: "isTranslucent",
    value: function isTranslucent(stage, primitive) {
      return false;
    }
    /**
     * @override
     */

  }, {
    key: "setParameters",
    value: function setParameters(stage, primitive) {
      var props = primitive.properties; // mat4 u_obj_to_clip

      this.setObjToClip(stage, primitive); // 画面パラメータ: {2/w, 2/h}
      // vec2 u_sparam

      var sparam = PinMaterial._sparam;
      sparam[0] = 2 / stage._width;
      sparam[1] = 2 / stage._height;
      this.setVector2("u_sparam", sparam); // テクスチャのバインド
      // sampler2D u_image

      var image = props["image"];
      this.bindTexture2D(PinMaterial.TEXUNIT_IMAGE, image.handle); // テクスチャマスクのバインド
      // sampler2D u_image_mask

      var image_mask = props["image_mask"];
      this.bindTexture2D(PinMaterial.TEXUNIT_IMAGE_MASK, image_mask.handle);
    }
  }]);

  return PinMaterial;
}(EntityMaterial); // クラス定数の定義


{
  PinMaterial.TEXUNIT_IMAGE = 0; // 画像のテクスチャユニット

  PinMaterial.TEXUNIT_IMAGE_MASK = 1; // 画像のテクスチャユニット
  // 計算用一時領域

  PinMaterial._sparam = GeoMath.createVector2f();
  PinMaterial._bg_color = GeoMath.createVector3f();
  PinMaterial._fg_color = GeoMath.createVector3f();
}

/**
 * @summary アイコン画像のローダーです。
 * 何らかのプロパティを指定し、アイコンが読み込まれます。
 * 同一リソースが要求された場合は、読み込み中または読み込み済みのアイコンを返却します。
 * 同一リソースであるかの判定には、getKey(prop)関数により返却される値を用います。
 */

var IconLoader =
/*#__PURE__*/
function () {
  function IconLoader() {
    _classCallCheck(this, IconLoader);

    this._cache = new Map();
  }
  /**
   * @desc
   * プロパティに応じたアイコンを返却します。すでに同一リソースを生成した場合は生成済みのインスタンスを返却し、そうでない場合はdoCreate(prop)により生成します。
   * @param {any} prop
   */


  _createClass(IconLoader, [{
    key: "create",
    value: function create(prop) {
      var key = this.getKey(prop);

      var value = this._cache.get(key);

      if (!value) this._cache.set(key, value = this.doCreate(prop));
      return value;
    }
    /**
     * プロパティに応じたアイコンを生成します。(オーバーライドされることを想定した関数です)
     * @param {any} prop プロパティ
     */

  }, {
    key: "doCreate",
    value: function doCreate(prop) {}
    /**
     * プロパティに応じたキーを返却します。(必要に応じてオーバーライドされることを想定した関数です)。
     * ディフォルトでは、プロパティ自体がキーとなるように動作します。
     * @param {any} prop プロパティ
     */

  }, {
    key: "getKey",
    value: function getKey(prop) {
      return prop;
    }
    /**
     * プロパティに応じたアイコンの読み込みを開始し、インスタンスを返却します。読み込みは開始しますが読み込み完了していない可能性があります。
     * @param {any} prop プロパティ
     */

  }, {
    key: "load",
    value: function load(prop) {
      var icon = this.create(prop);
      icon.load();
      return icon;
    }
  }]);

  return IconLoader;
}();
/**
 * @summary アイコン画像ローダーのアイコンです。抽象クラスです。
 * ステータスの管理、読み込み完了後の通知等を行います。
 * @private
 */


var IconLoaderItem =
/*#__PURE__*/
function () {
  function IconLoaderItem() {
    _classCallCheck(this, IconLoaderItem);

    this._status = IconLoaderItem.Status.NOT_LOADED;
    this.funcs = [];
  }
  /**
   * @summary アイコンの状態
   * @type {IconLoaderItem.Status}
   * @readonly
   */


  _createClass(IconLoaderItem, [{
    key: "isLoaded",
    value: function isLoaded() {
      return this._status === IconLoaderItem.Status.LOADED;
    }
    /**
     * @summary アイコンの読み込みが完了した時点で呼び出されるコールバック関数を登録します。
     * この関数を呼び出した時点で読み込みが完了している場合は、即座にコールバック関数を実行します。
     * @param {function}
     */

  }, {
    key: "onEnd",
    value: function onEnd(func) {
      var alreadyDone = this._status === IconLoaderItem.Status.LOADED || this._status === IconLoaderItem.Status.ABORTED;
      if (alreadyDone) func(this);else this.funcs.push(func);
    }
    /**
     * @summary アイコンを読み込み関数(doLoad())を実行し、成功時、失敗時それぞれ後続処理を行います。
     */

  }, {
    key: "load",
    value: function load() {
      var _this = this;

      if (this._status === IconLoaderItem.Status.NOT_LOADED) {
        this._status = IconLoaderItem.Status.LOADING;
        return this.doLoad().then(function (image) {
          _this._icon = image;
          _this._status = IconLoaderItem.Status.LOADED;

          for (var i = 0; i < _this.funcs.length; i++) {
            _this.funcs[i](_this);
          }

          _this.funcs.length = 0;
        })["catch"](function (error) {
          _this._status = IconLoaderItem.Status.ABORTED;

          for (var i = 0; i < _this.funcs.length; i++) {
            _this.funcs[i](_this);
          }

          _this.funcs.length = 0;
        });
      }
    }
    /**
     * @summary アイコンを読み込みます。この関数はオーバーライドされることを想定されています。
     * @param {function} onload  成功時のコールバック
     * @param {function} onerror 失敗時のコールバック
     */

  }, {
    key: "doLoad",
    value: function doLoad(onload, onerror) {
      return Promise.reject(new Error("doLoad() is not implemented in: " + this.constructor.name));
    }
  }, {
    key: "draw",

    /**
     * @summary アイコンをキャンバスコンテキストに描画します。
     * @param {CanvasRenderingContext2D} context
     * @param {number} x
     * @param {number} y
     * @param {number} width
     * @param {number} height
     */
    value: function draw(context, x, y, width, height) {
      context.drawImage(this.icon, x, y, width, height);
    }
  }, {
    key: "status",
    get: function get() {
      return this._status;
    }
  }, {
    key: "icon",
    get: function get() {
      return this._icon;
    }
  }, {
    key: "width",
    get: function get() {
      return this.icon ? this.icon.width : -1;
    }
  }, {
    key: "height",
    get: function get() {
      return this.icon ? this.icon.height : -1;
    }
  }]);

  return IconLoaderItem;
}();

IconLoaderItem.Status = {
  NOT_LOADED: "not loaded",
  LOADING: "loading",
  LOADED: "loaded",
  ABORTED: "aborted"
};
/**
 * @summary アイコン画像のURLを指定してアイコンを読み込むアイコンローダーです。
 * urlは下記のように生成します。
 * url = urlPrefix + id + urlSuffix
 * @private
 */

var URLTemplateIconLoader =
/*#__PURE__*/
function (_IconLoader) {
  _inherits(URLTemplateIconLoader, _IconLoader);

  /**
   * @param {string} urlPrefix
   * @param {string} urlSuffix
   */
  function URLTemplateIconLoader(urlPrefix, urlSuffix) {
    var _this2;

    _classCallCheck(this, URLTemplateIconLoader);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(URLTemplateIconLoader).call(this));
    _this2.urlPrefix = urlPrefix;
    _this2.urlSuffix = urlSuffix;
    return _this2;
  }

  _createClass(URLTemplateIconLoader, [{
    key: "doCreate",
    value: function doCreate(id) {
      return new URLIconLoaderItem(this.urlPrefix + id + this.urlSuffix);
    }
  }]);

  return URLTemplateIconLoader;
}(IconLoader);
/**
 * @summary URLTemplateIconLoaderのアイコンです。

 * @private
 */


var URLIconLoaderItem =
/*#__PURE__*/
function (_IconLoaderItem) {
  _inherits(URLIconLoaderItem, _IconLoaderItem);

  /**
   * @param {string} url
   */
  function URLIconLoaderItem(url) {
    var _this3;

    _classCallCheck(this, URLIconLoaderItem);

    _this3 = _possibleConstructorReturn(this, _getPrototypeOf(URLIconLoaderItem).call(this));
    _this3.url = url;
    return _this3;
  }

  _createClass(URLIconLoaderItem, [{
    key: "doLoad",
    value: function doLoad(onload, onerror) {
      return Dom.loadImage(this.url, {
        crossOrigin: "Anonymous"
      });
    }
  }]);

  return URLIconLoaderItem;
}(IconLoaderItem);
/**
 * @summary テキストアイコンを生成するアイコンローダーです。
 *
 * @private
 */


var TextIconLoader =
/*#__PURE__*/
function (_IconLoader2) {
  _inherits(TextIconLoader, _IconLoader2);

  function TextIconLoader() {
    _classCallCheck(this, TextIconLoader);

    return _possibleConstructorReturn(this, _getPrototypeOf(TextIconLoader).apply(this, arguments));
  }

  _createClass(TextIconLoader, [{
    key: "doCreate",

    /**
     * プロパティに応じたアイコンを生成します。
     * @param {string} prop.text プロパティ
     */
    value: function doCreate(prop) {
      return new TextIconLoaderItem(prop.text, prop.props);
    }
    /**
     * プロパティに応じたキーを返却します。
     * @param {string} prop.text プロパティ
     */

  }, {
    key: "getKey",
    value: function getKey(prop) {
      return prop.text;
    }
  }]);

  return TextIconLoader;
}(IconLoader);
/**
 * @summary TextIconLoaderのアイコンです。
 *
 * @private
 */


var TextIconLoaderItem =
/*#__PURE__*/
function (_IconLoaderItem2) {
  _inherits(TextIconLoaderItem, _IconLoaderItem2);

  /**
   * @param {string}         text                text
   * @param {mapray.Vector2} [props.size]        size in pixel
   * @param {string}         [props.font_family] font family
   */
  function TextIconLoaderItem(text) {
    var _this4;

    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    _classCallCheck(this, TextIconLoaderItem);

    _this4 = _possibleConstructorReturn(this, _getPrototypeOf(TextIconLoaderItem).call(this));
    _this4.text = text;
    _this4.props = props;
    return _this4;
  }
  /**
   * @override
   */


  _createClass(TextIconLoaderItem, [{
    key: "doLoad",
    value: function doLoad(onload, onerror) {
      var props = this.props;
      var size = props.size ? props.size[0] : 20;
      var fontFamily = props.font_family ? "'" + props.font_family + "'" : Dom.SYSTEM_FONT_FAMILY;
      var context = Dom.createCanvasContext(size, size);
      context.textAlign = "center";
      context.textBaseline = "alphabetic";
      context.font = size * 0.6756756757 + "px " + fontFamily;
      context.fillText(this.text, size * 0.5, size * 0.7432432432);
      return Promise.resolve(context.canvas);
    }
    /**
     * @override
     */

  }, {
    key: "draw",
    value: function draw(context, x, y, width, height) {
      context.drawImage(this.icon, x, y, width, height);
    }
  }]);

  return TextIconLoaderItem;
}(IconLoaderItem);
/**
 * @summary 画像からアイコンを生成するアイコンローダーです。
 *
 * @private
 */


var ImageIconLoader =
/*#__PURE__*/
function (_IconLoader3) {
  _inherits(ImageIconLoader, _IconLoader3);

  function ImageIconLoader() {
    _classCallCheck(this, ImageIconLoader);

    return _possibleConstructorReturn(this, _getPrototypeOf(ImageIconLoader).apply(this, arguments));
  }

  _createClass(ImageIconLoader, [{
    key: "doCreate",

    /**
     * プロパティに応じたアイコンを生成します。
     * @param {string} prop.text プロパティ
     */
    value: function doCreate(image_src) {
      return new ImageIconLoaderItem(image_src);
    }
  }]);

  return ImageIconLoader;
}(IconLoader);
/**
 * @summary ImageIconLoaderのアイコンです。
 *
 * @private
 */


var ImageIconLoaderItem =
/*#__PURE__*/
function (_IconLoaderItem3) {
  _inherits(ImageIconLoaderItem, _IconLoaderItem3);

  /**
   * @param {string|HTMLImageElement|HTMLCanvasElement} image_src image source
   */
  function ImageIconLoaderItem(image_src) {
    var _this5;

    _classCallCheck(this, ImageIconLoaderItem);

    _this5 = _possibleConstructorReturn(this, _getPrototypeOf(ImageIconLoaderItem).call(this));
    _this5._image_src = image_src;
    return _this5;
  }
  /**
   * @override
   */


  _createClass(ImageIconLoaderItem, [{
    key: "doLoad",
    value: function doLoad(onload, onerror) {
      var image_src = this._image_src;
      return typeof image_src === "string" ? Dom.loadImage(image_src) : image_src instanceof HTMLImageElement ? Dom.waitForLoad(image_src) : image_src instanceof HTMLCanvasElement ? Promise.resolve(image_src) : Promise.reject(new Error("not supported: " + image_src));
    }
  }]);

  return ImageIconLoaderItem;
}(IconLoaderItem);

/**
 * @summary ピンエンティティ
 * @memberof mapray
 * @extends mapray.Entity
 *
 * @example
 * var pin = new mapray.PinEntity(viewer.scene);
 * pin.addTextPin( "32", new mapray.GeoPoint(139.768, 35.635) );
 * pin.addTextPin( "A", new mapray.GeoPoint(139.768, 35.636), { fg_color: [0.0, 0.0, 1.0], bg_color: [1.0, 0.0, 0.0] } );
 * pin.addTextPin( "始", new mapray.GeoPoint(139.768, 35.637), { size: 50 } );
 * pin.addTextPin( "終", new mapray.GeoPoint(139.768, 35.639), { size: 50, font_family: "Georgia" } );
 * pin.addPin( new mapray.GeoPoint(139.766, 35.6361) );
 * pin.addMakiIconPin( "ferry-15", new mapray.GeoPoint(139.764, 35.6361), { size: 150, fg_color: [0.2, 0.2, 0.2], bg_color: [1.0, 1.0, 1.0] } );
 * pin.addMakiIconPin( "car-15",   new mapray.GeoPoint(139.762, 35.6361), { size: 60, fg_color: [1.0, 1.0, 1.0], bg_color: [0.2, 0.2, 0.2] } );
 * pin.addMakiIconPin( "bus-15",   new mapray.GeoPoint(139.760, 35.6361), { size: 40, fg_color: [1.0, 0.3, 0.1], bg_color: [0.1, 0.3, 1.0] } );
 * pin.addMakiIconPin( "bus-15",   new mapray.GeoPoint(139.759, 35.6361) );
 * pin.addMakiIconPin( "car-15",   new mapray.GeoPoint(139.758, 35.6361) );
 * viewer.scene.addEntity(pin);
 *
 */

var PinEntity =
/*#__PURE__*/
function (_Entity) {
  _inherits(PinEntity, _Entity);

  /**
   * @param {mapray.Scene} scene        所属可能シーン
   * @param {object}       [opts]       オプション集合
   * @param {object}       [opts.json]  生成情報
   * @param {object}       [opts.refs]  参照辞書
   */
  function PinEntity(scene, opts) {
    var _this;

    _classCallCheck(this, PinEntity);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(PinEntity).call(this, scene, opts)); // 要素管理

    _this._entries = []; // 親プロパティ

    _this._parent_props = {
      fg_color: null,
      bg_color: null,
      size: null,
      font_family: null
    }; // Entity.PrimitiveProducer インスタンス

    _this._primitive_producer = new PrimitiveProducer$5(_assertThisInitialized(_this)); // 生成情報から設定

    if (opts && opts.json) {
      _this._setupByJson(opts.json);
    }

    return _this;
  }
  /**
   * @override
   */


  _createClass(PinEntity, [{
    key: "getPrimitiveProducer",
    value: function getPrimitiveProducer() {
      return this._primitive_producer;
    }
    /**
     * @override
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode(prev_mode) {
      this._primitive_producer.onChangeAltitudeMode();
    }
    /**
     * @summary アイコンのピクセルサイズを指定
     * @param {mapray.Vector3} size  アイコンのピクセルサイズ
     */

  }, {
    key: "setSize",
    value: function setSize(size) {
      this._setVector2Property("size", size);
    }
    /**
     * @summary アイコンの色を設定
     * @param {mapray.Vector3} color  アイコンの色
     */

  }, {
    key: "setFGColor",
    value: function setFGColor(color) {
      this._setVector3Property("fg_color", color);
    }
    /**
     * @summary アイコン背景の色を設定
     * @param {mapray.Vector3} color  アイコン背景の色
     */

  }, {
    key: "setBGColor",
    value: function setBGColor(color) {
      this._setVector3Property("bg_color", color);
    }
    /**
     * @summary テキストアイコンのフォントを設定
     * @param {string} font_family  フォントファミリー
     */

  }, {
    key: "setFontFamily",
    value: function setFontFamily(font_family) {
      this._setValueProperty("font_family", font_family);
    }
    /**
     * Add Pin
     * @param {mapray.GeoPoint} position         位置
     * @param {object}          [props]          プロパティ
     * @param {float}           [props.size]     アイコンサイズ
     * @param {mapray.Vector3}  [props.fg_color] アイコン色
     * @param {mapray.Vector3}  [props.bg_color] 背景色
     */

  }, {
    key: "addPin",
    value: function addPin(position, props) {
      this.addTextPin("", position, props);
    }
    /**
     * Add Maki Icon Pin
     * @param {string}          id              ID of Maki Icon
     * @param {mapray.GeoPoint} position         位置
     * @param {object}          [props]          プロパティ
     * @param {float}           [props.size]     アイコンサイズ
     * @param {mapray.Vector3}  [props.fg_color] アイコン色
     * @param {mapray.Vector3}  [props.bg_color] 背景色
     */

  }, {
    key: "addMakiIconPin",
    value: function addMakiIconPin(id, position, props) {
      this._entries.push(new MakiIconPinEntry(this, id, position, props));

      this._primitive_producer.onAddEntry();
    }
    /**
     * Add Text Pin
     * @param {string}          text              ピンに表示されるテキスト
     * @param {mapray.GeoPoint} position           位置
     * @param {object}          [props]            プロパティ
     * @param {float}           [props.size]       アイコンサイズ
     * @param {mapray.Vector3}  [props.fg_color]   アイコン色
     * @param {mapray.Vector3}  [props.bg_color]   背景色
     * @param {string}          [props.font_family] フォントファミリー
     */

  }, {
    key: "addTextPin",
    value: function addTextPin(text, position, props) {
      this._entries.push(new TextPinEntry(this, text, position, props));

      this._primitive_producer.onAddEntry();
    }
    /**
     * @summary 専用マテリアルを取得
     * @private
     */

  }, {
    key: "_getMaterial",
    value: function _getMaterial() {
      var scene = this.scene;

      if (!scene._PinEntity_pin_material) {
        // scene にマテリアルをキャッシュ
        scene._PinEntity_pin_material = new PinMaterial(scene.glenv);
      }

      return scene._PinEntity_pin_material;
    }
    /**
     * @private
     */

  }, {
    key: "_setValueProperty",
    value: function _setValueProperty(name, value) {
      var props = this._parent_props;

      if (props[name] != value) {
        props[name] = value;

        this._primitive_producer.onChangeParentProperty();
      }
    }
    /**
     * @private
     */

  }, {
    key: "_setVector3Property",
    value: function _setVector3Property(name, value) {
      var dst = this._parent_props[name];

      if (!dst) {
        dst = this._parent_props[name] = GeoMath.createVector2f(value);
      } else if (dst[0] !== value[0] || dst[1] !== value[1] || dst[2] !== value[2]) {
        GeoMath.copyVector3(value, dst);

        this._primitive_producer.onChangeParentProperty();
      }
    }
    /**
     * @private
     */

  }, {
    key: "_setVector2Property",
    value: function _setVector2Property(name, value) {
      var dst = this._parent_props[name];

      if (!dst) {
        this._parent_props[name] = GeoMath.createVector2f(value);

        this._primitive_producer.onChangeParentProperty();
      } else if (dst[0] !== value[0] || dst[1] !== value[1]) {
        GeoMath.copyVector2(value, dst);

        this._primitive_producer.onChangeParentProperty();
      }
    }
    /**
     * @private
     */

  }, {
    key: "_setupByJson",
    value: function _setupByJson(json) {
      var position = new GeoPoint();
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = json.entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var entry = _step.value;
          position.setFromArray(entry.position);
          this.addPin(position, entry);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      if (json.size) this.setSize(json.size);
      if (json.fg_color) this.setFGColor(json.fg_color);
      if (json.bg_color) this.setBGColor(json.bg_color);
      if (json.font_family) this.setBGColor(json.font_family);
    }
  }]);

  return PinEntity;
}(Entity); // クラス定数の定義


{
  PinEntity.SAFETY_PIXEL_MARGIN = 1;
  PinEntity.MAX_IMAGE_WIDTH = 4096;
  PinEntity.CIRCLE_SEP_LENGTH = 32;
  PinEntity.DEFAULT_SIZE = GeoMath.createVector2f([30, 30]);
  PinEntity.DEFAULT_FONT_FAMILY = "sans-serif";
  PinEntity.DEFAULT_FG_COLOR = GeoMath.createVector3f([1.0, 1.0, 1.0]);
  PinEntity.DEFAULT_BG_COLOR = GeoMath.createVector3f([0.35, 0.61, 0.81]);
  PinEntity.SAFETY_PIXEL_MARGIN = 1;
  PinEntity.MAX_IMAGE_WIDTH = 4096;
}
/**
 * @summary PrimitiveProducer
 *
 * TODO: relative で標高の変化のたびにテクスチャを生成する必要はないので
 *       Layout でのテクスチャの生成とメッシュの生成を分離する
 *
 * @private
 */

var PrimitiveProducer$5 =
/*#__PURE__*/
function (_Entity$PrimitiveProd) {
  _inherits(PrimitiveProducer, _Entity$PrimitiveProd);

  /**
   * @param {mapray.PinEntity} entity
   */
  function PrimitiveProducer(entity) {
    var _this2;

    _classCallCheck(this, PrimitiveProducer);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(PrimitiveProducer).call(this, entity));
    _this2._glenv = entity.scene.glenv;
    _this2._dirty = true; // プリミティブの要素

    _this2._transform = GeoMath.setIdentity(GeoMath.createMatrix());
    _this2._properties = {
      image: null,
      // 画像
      image_mask: null // マスク画像

    }; // プリミティブ

    var primitive = new Primitive(_this2._glenv, null, entity._getMaterial(), _this2._transform);
    primitive.properties = _this2._properties;
    _this2._primitive = primitive; // プリミティブ配列

    _this2._primitives = [];
    return _this2;
  }
  /**
   * @override
   */


  _createClass(PrimitiveProducer, [{
    key: "createRegions",
    value: function createRegions() {
      var region = new EntityRegion();
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this.entity._entries[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var position = _step2.value.position;
          region.addPoint(position);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      return [region];
    }
    /**
     * @override
     */

  }, {
    key: "onChangeElevation",
    value: function onChangeElevation(regions) {
      this._dirty = true;
    }
    /**
     * @override
     */

  }, {
    key: "getPrimitives",
    value: function getPrimitives(stage) {
      return this._updatePrimitive();
    }
    /**
     * @summary 親プロパティが変更されたことを通知
     */

  }, {
    key: "onChangeParentProperty",
    value: function onChangeParentProperty() {
      this._dirty = true;
    }
    /**
     * @summary 高度モードが変更されたことを通知
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode() {
      this._dirty = true;
    }
    /**
     * @summary エントリが追加されたことを通知
     */

  }, {
    key: "onAddEntry",
    value: function onAddEntry() {
      // 変化した可能性がある
      this.needToCreateRegions();
      this._dirty = true;
    }
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * 入力:
     *   this.entity._entries
     *   this._dirty
     * 出力:
     *   this._transform
     *   this._properties.image
     *   this._primitive.mesh
     *   this._primitives
     *   this._dirty
     *
     * @return {array.<mapray.Prmitive>}  this._primitives
     *
     * @private
     */

  }, {
    key: "_updatePrimitive",
    value: function _updatePrimitive() {
      if (!this._dirty) {
        // 更新する必要はない
        return this._primitives;
      }

      if (this.entity._entries.length == 0) {
        this._primitives = [];
        this._dirty = false;
        return this._primitives;
      } // 各エントリーの GOCS 位置を生成 (平坦化配列)


      var gocs_array = this._createFlatGocsArray(); // プリミティブの更新
      //   primitive.transform


      this._updateTransform(gocs_array);

      var layout = new Layout$1(this, gocs_array);

      if (!layout.isValid()) {
        // 更新に失敗
        this._primitives = [];
        this._dirty = false;
        return this._primitives;
      } // テクスチャ設定


      var properties = this._properties;

      if (properties.image) {
        properties.image.dispose();
      }

      properties.image = layout.texture;

      if (properties.image_mask) {
        properties.image_mask.dispose();
      }

      properties.image_mask = layout.texture_mask; // メッシュ生成

      var mesh_data = {
        vtype: [{
          name: "a_position",
          size: 3
        }, {
          name: "a_offset",
          size: 2
        }, {
          name: "a_texcoord",
          size: 2
        }, {
          name: "a_texmaskcoord",
          size: 2
        }, {
          name: "a_fg_color",
          size: 3
        }, {
          name: "a_bg_color",
          size: 3
        }],
        vertices: layout.vertices,
        indices: layout.indices
      };
      var mesh = new Mesh(this._glenv, mesh_data); // メッシュ設定
      //   primitive.mesh

      var primitive = this._primitive;

      if (primitive.mesh) {
        primitive.mesh.dispose();
      }

      primitive.mesh = mesh; // 更新に成功

      this._primitives = [primitive];
      this._dirty = false;
      return this._primitives;
    }
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * 条件:
     *   this.entity._entries.length > 0
     * 入力:
     *   this.entity._entries.length
     * 出力:
     *   this._transform
     *
     * @param {number[]} gocs_array  GOCS 平坦化配列
     *
     * @private
     */

  }, {
    key: "_updateTransform",
    value: function _updateTransform(gocs_array) {
      var num_entries = this.entity._entries.length;
      var xsum = 0;
      var ysum = 0;
      var zsum = 0;

      for (var i = 0; i < num_entries; ++i) {
        var ibase = 3 * i;
        xsum += gocs_array[ibase];
        ysum += gocs_array[ibase + 1];
        zsum += gocs_array[ibase + 2];
      } // 変換行列の更新


      var transform = this._transform;
      transform[12] = xsum / num_entries;
      transform[13] = ysum / num_entries;
      transform[14] = zsum / num_entries;
    }
    /**
     * @summary GOCS 平坦化配列を取得
     *
     * 入力: this.entity._entries
     *
     * @return {number[]}  GOCS 平坦化配列
     * @private
     */

  }, {
    key: "_createFlatGocsArray",
    value: function _createFlatGocsArray() {
      var num_points = this.entity._entries.length;
      return GeoPoint.toGocsArray(this._getFlatGeoPoints_with_Absolute(), num_points, new Float64Array(3 * num_points));
    }
    /**
     * @summary GeoPoint 平坦化配列を取得 (絶対高度)
     *
     * 入力: this.entity._entries
     *
     * @return {number[]}  GeoPoint 平坦化配列
     * @private
     */

  }, {
    key: "_getFlatGeoPoints_with_Absolute",
    value: function _getFlatGeoPoints_with_Absolute() {
      var owner = this.entity;
      var entries = owner._entries;
      var num_points = entries.length;
      var flat_array = new Float64Array(3 * num_points); // flat_array[] に経度要素と緯度要素を設定

      for (var i = 0; i < num_points; ++i) {
        var pos = entries[i].position;
        flat_array[3 * i] = pos.longitude;
        flat_array[3 * i + 1] = pos.latitude;
      }

      switch (owner.altitude_mode) {
        case AltitudeMode.RELATIVE:
        case AltitudeMode.CLAMP:
          // flat_array[] の高度要素に現在の標高を設定
          owner.scene.viewer.getExistingElevations(num_points, flat_array, 0, 3, flat_array, 2, 3);

          if (owner.altitude_mode === AltitudeMode.RELATIVE) {
            // flat_array[] の高度要素に絶対高度を設定
            for (var _i = 0; _i < num_points; ++_i) {
              flat_array[3 * _i + 2] += entries[_i].position.altitude;
            }
          }

          break;

        default:
          // AltitudeMode.ABSOLUTE
          // flat_array[] の高度要素に絶対高度を設定
          for (var _i2 = 0; _i2 < num_points; ++_i2) {
            flat_array[3 * _i2 + 2] = entries[_i2].position.altitude;
          }

          break;
      }

      return flat_array;
    }
  }]);

  return PrimitiveProducer;
}(Entity.PrimitiveProducer);
/**
 * @summary ピン要素
 * @memberof mapray.PinEntity
 * @private
 */


var AbstractPinEntry =
/*#__PURE__*/
function () {
  function AbstractPinEntry(owner, position, props) {
    _classCallCheck(this, AbstractPinEntry);

    this._owner = owner;
    this._position = position.clone();
    this._props = Object.assign({}, props); // props の複製

    this._copyPropertyVector3f("fg_color"); // deep copy


    this._copyPropertyVector3f("bg_color"); // deep copy


    this._copyPropertyVector2f("size"); // deep copy

  }

  _createClass(AbstractPinEntry, [{
    key: "_loadIcon",
    value: function _loadIcon() {
      throw new Error("loadIcon() is not implemented: " + this.constructor.name);
    }
    /**
     * @summary 位置
     * @type {mapray.GeoPoint}
     * @readonly
     */

  }, {
    key: "_copyPropertyVector3f",

    /**
     * @private
     */
    value: function _copyPropertyVector3f(name) {
      var props = this._props;

      if (props.hasOwnProperty(name)) {
        props[name] = GeoMath.createVector3f(props[name]);
      }
    }
    /**
     * @private
     */

  }, {
    key: "_copyPropertyVector2f",
    value: function _copyPropertyVector2f(name) {
      var props = this._props;

      if (props.hasOwnProperty(name)) {
        if (typeof props[name] === 'number') {
          props[name] = GeoMath.createVector2f([props[name], props[name]]);
        } else {
          props[name] = GeoMath.createVector2f(props[name]);
        }
      }
    }
  }, {
    key: "isLoaded",
    value: function isLoaded() {
      return this._icon.isLoaded();
    }
  }, {
    key: "draw",
    value: function draw(context, x, y, width, height) {
      this._icon.draw(context, x, y, width, height);
    }
  }, {
    key: "position",
    get: function get() {
      return this._position;
    }
    /**
     * @summary アイコンサイズ (Pixels)
     * @type {mapray.Vector2}
     * @readonly
     */

  }, {
    key: "size",
    get: function get() {
      var props = this._props;
      var parent = this._owner._parent_props;
      return props.size || parent.size || (this.icon ? GeoMath.createVector2f([this.icon.width, this.icon.height]) : PinEntity.DEFAULT_SIZE);
    }
    /**
     * @summary アイコン色
     * @type {mapray.Vector3}
     * @readonly
     */

  }, {
    key: "fg_color",
    get: function get() {
      var props = this._props;
      var parent = this._owner._parent_props;
      return props.fg_color || parent.fg_color || PinEntity.DEFAULT_FG_COLOR;
    }
    /**
     * @summary アイコン背景色
     * @type {mapray.Vector3}
     * @readonly
     */

  }, {
    key: "bg_color",
    get: function get() {
      var props = this._props;
      var parent = this._owner._parent_props;
      return props.bg_color || parent.bg_color || PinEntity.DEFAULT_BG_COLOR;
    }
  }, {
    key: "icon",
    get: function get() {
      return this._icon;
    }
  }]);

  return AbstractPinEntry;
}();
/**
 * @summary MakiIcon要素
 * @memberof mapray.PinEntity
 * @private
 */


var MakiIconPinEntry =
/*#__PURE__*/
function (_AbstractPinEntry) {
  _inherits(MakiIconPinEntry, _AbstractPinEntry);

  /**
   * @param {mapray.PinEntity}  owner                所有者
   * @param {string}            id                   MakiアイコンのID
   * @param {mapray.GeoPoint}   position             位置
   * @param {object}            [props]              プロパティ
   * @param {float} [props.size]                     アイコンサイズ
   * @param {mapray.Vector3} [props.fg_color]        アイコン色
   * @param {mapray.Vector3} [props.bg_color]        背景色
   */
  function MakiIconPinEntry(owner, id, position, props) {
    var _this3;

    _classCallCheck(this, MakiIconPinEntry);

    _this3 = _possibleConstructorReturn(this, _getPrototypeOf(MakiIconPinEntry).call(this, owner, position, props));
    _this3._id = id;
    _this3._icon = MakiIconPinEntry.makiIconLoader.load(id);

    _this3._icon.onEnd(function (item) {
      _this3._owner.getPrimitiveProducer()._dirty = true;
    });

    return _this3;
  }

  return MakiIconPinEntry;
}(AbstractPinEntry);

{
  MakiIconPinEntry.makiIconLoader = new URLTemplateIconLoader("https://resource.mapray.com/styles/v1/icons/maki/", ".svg");
}
/**
 * @summary MakiIcon要素
 * @memberof mapray.PinEntity
 * @private
 */

var TextPinEntry =
/*#__PURE__*/
function (_AbstractPinEntry2) {
  _inherits(TextPinEntry, _AbstractPinEntry2);

  /**
   * @param {mapray.PinEntity}  owner                所有者
   * @param {string}            text                 テキスト
   * @param {mapray.GeoPoint}   position             位置
   * @param {object}            [props]              プロパティ
   * @param {float}             [props.size]         アイコンピクセルサイズ
   * @param {mapray.Vector3}    [props.fg_color]     アイコン色
   * @param {mapray.Vector3}    [props.bg_color]     背景色
   * @param {string}            [props.font_family]  フォントファミリー
   */
  function TextPinEntry(owner, text, position, props) {
    var _this4;

    _classCallCheck(this, TextPinEntry);

    _this4 = _possibleConstructorReturn(this, _getPrototypeOf(TextPinEntry).call(this, owner, position, props));
    _this4._text = text;
    _this4._icon = TextPinEntry.textIconLoader.load({
      text: _this4._text,
      props: {
        size: _this4.size,
        font_family: _this4.font_family
      }
    });

    _this4._icon.onEnd(function (item) {
      _this4._owner.getPrimitiveProducer()._dirty = true;
    });

    return _this4;
  }
  /**
   * @summary フォントファミリー
   * @type {string}
   * @readonly
   */


  _createClass(TextPinEntry, [{
    key: "font_family",
    get: function get() {
      var props = this._props;
      var parent = this._owner._parent_props;
      return props.font_family || parent.font_family || PinEntity.DEFAULT_FONT_FAMILY;
    }
  }]);

  return TextPinEntry;
}(AbstractPinEntry);

{
  TextPinEntry.textIconLoader = new TextIconLoader();
}
/**
 * @summary 要素を Canvas 上にレイアウト
 *
 * @memberof mapray.PinEntity
 * @private
 */

var Layout$1 =
/*#__PURE__*/
function () {
  /**
   * @desc
   * 入力:
   *   owner._glenv
   *   owner.entity._entries
   *   owner._transform
   *
   * @param {PrimitiveProducer} owner       所有者
   * @param {number[]}          gocs_array  GOCS 平坦化配列
   */
  function Layout(owner, gocs_array) {
    _classCallCheck(this, Layout);

    this._owner = owner;
    this._items = this._createItemList();
    this._is_valid = true;

    var row_layouts = this._createRowLayouts();

    if (row_layouts.length == 0) {
      // 有効なテキストが1つも無い
      this._is_valid = false;
      return;
    } // アイテムの配置の設定とキャンバスサイズの決定


    var size = this._setupLocation(row_layouts);

    this._texture = this._createTexture(size.width, size.height);
    this._texture_mask = this._createTextureMask();
    this._vertices = this._createVertices(size.width, size.height, gocs_array);
    this._indices = this._createIndices();
  }
  /**
   * @summary 有効なオブジェクトか?
   * @desc
   * <p>無効のとき、他のメソッドは呼び出せない。</p>
   * @return {boolean}  有効のとき true, 無効のとき false
   */


  _createClass(Layout, [{
    key: "isValid",
    value: function isValid() {
      return this._is_valid;
    }
    /**
     * @summary テクスチャ
     * @type {mapray.Texture}
     * @readonly
     */

  }, {
    key: "_createItemList",

    /**
     * @summary レイアウトアイテムのリストを生成
     * @return {array.<mapray.PinEntity.LItem>}
     * @private
     */
    value: function _createItemList() {
      var map = new Map();
      var items = [];
      var counter = 0;
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = this._owner.entity._entries[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var entry = _step3.value;

          if (entry.isLoaded()) {
            var item = map.get(entry.icon);

            if (!item) {
              map.set(entry.icon, item = new LItem$1(this));
              items.push(item);
            }

            item.add(counter++, entry);
          }
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }

      return items;
    }
    /**
     * @summary RowLayout のリストを生成
     * @return {array.<mapray.PinEntity.RowLayout>}
     * @private
     */

  }, {
    key: "_createRowLayouts",
    value: function _createRowLayouts() {
      // アイテムリストの複製
      var items = [].concat(this._items); // RowLayout 内であまり高さに差が出ないように、アイテムリストを高さで整列

      items.sort(function (a, b) {
        return a.height_pixel - b.height_pixel;
      }); // リストを生成

      var row_layouts = [];

      while (items.length > 0) {
        var row_layout = new RowLayout$1(items);

        if (row_layout.isValid()) {
          row_layouts.push(row_layout);
        }
      }

      return row_layouts;
    }
    /**
     * @summary テクスチャを生成
     * @param  {number} width    横幅
     * @param  {number} height   高さ
     * @return {mapray.Texture}  テキストテクスチャ
     * @private
     */

  }, {
    key: "_createTexture",
    value: function _createTexture(width, height) {
      var context = Dom.createCanvasContext(width, height);
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;
        item.draw(context);
      }

      var glenv = this._owner._glenv;
      var opts = {
        usage: Texture.Usage.ICON
      };
      return new Texture(glenv, context.canvas, opts);
    }
  }, {
    key: "_createTextureMask",
    value: function _createTextureMask() {
      var context = Dom.createCanvasContext(3, 3);
      context.fillRect(1, 1, 1, 1);
      var glenv = this._owner._glenv;
      var opts = {
        usage: Texture.Usage.ICON,
        mag_filter: glenv.context.NEAREST
      };
      return new Texture(glenv, context.canvas, opts);
    }
    /**
     * @summary 頂点配列を生成
     *
     * @param  {number}   width       横幅
     * @param  {number}   height      高さ
     * @param  {number[]} gocs_array  GOCS 平坦化配列
     * @return {array.<number>}  頂点配列 [左下0, 右下0, 左上0, 右上0, ...]
     *
     * @private
     */

  }, {
    key: "_createVertices",
    value: function _createVertices(width, height, gocs_array) {
      var vertices = []; // テキスト集合の原点 (GOCS)

      var transform = this._owner._transform;
      var xo = transform[12];
      var yo = transform[13];
      var zo = transform[14];
      /*
           |<size.x->|
           |         |
           |    |<--rx--->|
          ___-------___     ----
         /             \      ^
       /                 \    ry
      |                   |   |  ----
      |                   |   v    ^
      |         c         | ----  size.y
      |                   |   ^    V
      |                   |   |  ----
       \                 /    |
        '----_0___3_----'     |
              |   |           |
              |   |           h
              |   |           |
              |   |           |
              |   |           |
              |   |           v
              1---2 ------------

             >| w |<
      */

      var xn = 1 / width;
      var yn = 1 / height;
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;

        for (var ie = 0; ie < item.entries.length; ie++) {
          var eitem = item.entries[ie];
          var entry = eitem.entry;
          var size = entry.size;
          var rx = size[0] * 1.5 / 2;
          var ry = size[1] * 1.5 / 2;
          var h = ry * 2;
          var w = Math.max(2, rx / 10); // Relativize based on (xo, yo, zo)

          var ibase = eitem.index * 3;
          var xm = gocs_array[ibase] - xo;
          var ym = gocs_array[ibase + 1] - yo;
          var zm = gocs_array[ibase + 2] - zo;
          var fg_color = entry.fg_color;
          var bg_color = entry.bg_color; // Image dimensions (Image Coordinate)

          var xc = item.pos_x;
          var yc = item.pos_y;
          var xsize = item.width;
          var ysize = item.height;

          var vertices_push_texture = function vertices_push_texture(px, py) {
            vertices.push((xc + xsize * px) * xn, 1 - (yc + ysize * py) * yn);
          }; // p0


          vertices.push(xm, ym, zm); // a_position

          vertices.push(-w / 2, h - ry); // a_offset

          vertices_push_texture(0.5 - w / 2 / rx, 1.5 / 2 + 0.5); // a_texcoord

          vertices.push(-0.25 + 0.5, -0.25 + 0.5); // a_texmaskcoord

          vertices.push.apply(vertices, _toConsumableArray(fg_color));
          vertices.push.apply(vertices, _toConsumableArray(bg_color)); // p1

          vertices.push(xm, ym, zm); // a_position

          vertices.push(-w / 2, 0); // a_offset

          vertices_push_texture(0.5 - w / 2 / rx, 1.5 / 2 + 0.5); // a_texcoord

          vertices.push(-0.25 + 0.5, -0.25 + 0.5); // a_texmaskcoord

          vertices.push.apply(vertices, _toConsumableArray(fg_color));
          vertices.push.apply(vertices, _toConsumableArray(bg_color)); // p2

          vertices.push(xm, ym, zm); // a_position

          vertices.push(w / 2, 0); // a_offset

          vertices_push_texture(0.5 + w / 2 / rx, 1.5 / 2 + 0.5); // a_texcoord

          vertices.push(-0.25 + 0.5, -0.25 + 0.5); // a_texmaskcoord

          vertices.push.apply(vertices, _toConsumableArray(fg_color));
          vertices.push.apply(vertices, _toConsumableArray(bg_color)); // p3

          vertices.push(xm, ym, zm); // a_position

          vertices.push(w / 2, h - ry); // a_offset

          vertices_push_texture(0.5 + w / 2 / rx, 1.5 / 2 + 0.5); // a_texcoord

          vertices.push(-0.25 + 0.5, -0.25 + 0.5); // a_texmaskcoord

          vertices.push.apply(vertices, _toConsumableArray(fg_color));
          vertices.push.apply(vertices, _toConsumableArray(bg_color)); // c

          vertices.push(xm, ym, zm); // a_position

          vertices.push(0, h); // a_offset

          vertices_push_texture(0.5, 0.5); // a_texcoord

          vertices.push(0.5, 0.5); // a_texmaskcoord

          vertices.push.apply(vertices, _toConsumableArray(fg_color));
          vertices.push.apply(vertices, _toConsumableArray(bg_color));

          for (var k = 1; k < PinEntity.CIRCLE_SEP_LENGTH; k++) {
            var th = (k / PinEntity.CIRCLE_SEP_LENGTH * 2 - 0.5) * Math.PI;
            var cos_th = Math.cos(th);
            var sin_th = Math.sin(th);
            vertices.push(xm, ym, zm); // a_position

            vertices.push(rx * cos_th, ry * sin_th + h); // a_offset

            vertices_push_texture(1.5 * cos_th / 2 + 0.5, -1.5 * sin_th / 2 + 0.5); // a_texcoord

            vertices.push(cos_th * 0.25 + 0.5, sin_th * 0.25 + 0.5); // a_texmaskcoord

            vertices.push.apply(vertices, _toConsumableArray(fg_color));
            vertices.push.apply(vertices, _toConsumableArray(bg_color));
          }
        }
      }

      return vertices;
    }
    /**
     * @summary インデックス配列を生成
     * @return {array.<number>}  インデックス配列 []
     * @private
     */

  }, {
    key: "_createIndices",
    value: function _createIndices() {
      var indices = [];
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;

        for (var ie = 0; ie < item.entries.length; ie++) {
          var eitem = item.entries[ie];
          var base = (4 + 1 + PinEntity.CIRCLE_SEP_LENGTH - 1) * eitem.index;
          var p = base;
          var p0 = p;
          var p3 = p + 3;
          indices.push(p, p + 1, p + 2);
          indices.push(p, p + 2, p + 3);
          p += 4;
          var centerPos = p++;
          indices.push(centerPos, p0, p3);
          indices.push(centerPos, p3, p);

          for (var j = 1; j < PinEntity.CIRCLE_SEP_LENGTH - 1; j++) {
            indices.push(centerPos, p++, p);
          }

          indices.push(centerPos, p++, p0);
        }
      }

      return indices;
    }
    /**
     * @summary アイテムの配置を設定
     * @param  {array.<mapray.PinEntity.RowLayout>} row_layouts
     * @return {object}                              キャンバスサイズ
     * @private
     */

  }, {
    key: "_setupLocation",
    value: function _setupLocation(row_layouts) {
      var width = 0;
      var height = 0;
      height += PinEntity.SAFETY_PIXEL_MARGIN;

      for (var i = 0; i < row_layouts.length; ++i) {
        var row_layout = row_layouts[i];
        row_layout.locate(height);
        width = Math.max(row_layout.width_assumed, width);
        height += row_layout.height_pixel + PinEntity.SAFETY_PIXEL_MARGIN;
      }

      return {
        width: width,
        height: height
      };
    }
  }, {
    key: "texture",
    get: function get() {
      return this._texture;
    }
    /**
     * @summary テクスチャマスク
     * @type {mapray.Texture}
     * @readonly
     */

  }, {
    key: "texture_mask",
    get: function get() {
      return this._texture_mask;
    }
    /**
     * @summary 頂点配列
     * @desc
     * 条件:
     *   this._entries.length > 0
     * 入力:
     *   this._entries
     *   this._transform
     * @type {Float32Array}
     * @readonly
     */

  }, {
    key: "vertices",
    get: function get() {
      return this._vertices;
    }
    /**
     * @summary インデックス配列
     * @type {Uint32Array}
     * @readonly
     */

  }, {
    key: "indices",
    get: function get() {
      return this._indices;
    }
  }]);

  return Layout;
}();
/**
 * @summary レイアウト対象
 * @memberof mapray.PinEntity
 * @private
 */


var LItem$1 =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.PinEntity.Layout} layout   所有者
   * @param {mapray.PinEntity.Entry}  entry    PinEntityのエントリ
   */
  function LItem(layout) {
    _classCallCheck(this, LItem);

    this.entries = []; // テキストの基点

    this._pos_x = 0; // 左端

    this._pos_y = 0; // ベースライン位置

    this._height = this._width = null;
    this._is_canceled = false;
  }

  _createClass(LItem, [{
    key: "add",
    value: function add(index, entry) {
      var size = entry.size;
      if (this._width === null || this._width < size[0]) this._width = size[0];
      if (this._height === null || this._height < size[1]) this._height = size[1];
      this.entries.push({
        index: index,
        entry: entry
      });
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "cancel",

    /**
     * @summary 取り消し状態に移行
     */
    value: function cancel() {
      this._is_canceled = true;
    }
    /**
     * @summary 配置を決定
     * @param {number} x  テキスト矩形左辺の X 座標 (キャンバス座標系)
     * @param {number} y  テキスト矩形上辺の Y 座標 (キャンバス座標系)
     */

  }, {
    key: "locate",
    value: function locate(x, y) {
      this._pos_x = x;
      this._pos_y = y;
    }
  }, {
    key: "draw",
    value: function draw(context) {
      this.entries[0].entry.draw(context, this._pos_x, this.pos_y, this.width, this.height);
    }
  }, {
    key: "pos_x",
    get: function get() {
      return this._pos_x;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "pos_y",
    get: function get() {
      return this._pos_y;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "width",
    get: function get() {
      return this._width;
    }
  }, {
    key: "height",
    get: function get() {
      return this._height;
    }
    /**
     * キャンバス上でのテキストの横画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "width_pixel",
    get: function get() {
      return Math.ceil(this._width);
    }
    /**
     * キャンバス上でのテキストの縦画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_pixel",
    get: function get() {
      return Math.ceil(this._height);
    }
    /**
     * 取り消し状態か?
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "is_canceled",
    get: function get() {
      return this._is_canceled;
    }
  }]);

  return LItem;
}();
/**
 * @summary 水平レイアウト
 * @memberof mapray.PinEntity
 * @private
 */


var RowLayout$1 =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>レイアウトされた、またはレイアウトに失敗したアイテムは src_items から削除される。</p>
   * <p>レイアウトに失敗したアイテムは取り消し (is_canceled) になる。</p>
   * @param {array.<mapray.PinEntity.LItem>} src_items  アイテムリスト
   */
  function RowLayout(src_items) {
    _classCallCheck(this, RowLayout);

    var width_assumed_total = 0;
    var height_pixel_max = 0;
    var row_items = [];
    width_assumed_total += PinEntity.SAFETY_PIXEL_MARGIN; // 左マージン

    while (src_items.length > 0) {
      var item = src_items.shift();
      var width_assumed = item.width_pixel + PinEntity.SAFETY_PIXEL_MARGIN; // テキスト幅 + 右マージン

      if (width_assumed_total + width_assumed <= PinEntity.MAX_IMAGE_WIDTH) {
        // 行にアイテムを追加
        row_items.push(item);
        width_assumed_total += width_assumed;
        height_pixel_max = Math.max(item.height_pixel, height_pixel_max);
      } else {
        if (row_items.length == 0) {
          // テキストが長すぎて表示できない
          item.cancel();
        } else {
          // 次の行になるため差し戻して終了
          src_items.unshift(item);
          break;
        }
      }
    }

    this._items = row_items;
    this._width_assumed = width_assumed_total;
    this._height_pixel = height_pixel_max;
  }
  /**
   * @summary 有効なオブジェクトか?
   * @desc
   * <p>無効のとき、他のメソッドは呼び出せない。</p>
   * @return {boolean}  有効のとき true, 無効のとき false
   */


  _createClass(RowLayout, [{
    key: "isValid",
    value: function isValid() {
      return this._items.length > 0;
    }
    /**
     *
     * @type {array.<mapray.PinEntity.LItem>}
     * @readonly
     */

  }, {
    key: "locate",

    /**
     * @summary レイアウトの配置を決定
     * @param {number} y  テキスト矩形上辺の Y 座標 (キャンバス座標系)
     */
    value: function locate(y) {
      var items = this._items;
      var x = 0;
      x += PinEntity.SAFETY_PIXEL_MARGIN; // 左マージン

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        item.locate(x, y);
        x += item.width_pixel + PinEntity.SAFETY_PIXEL_MARGIN; // テキスト幅 + 右マージン
      }
    }
  }, {
    key: "items",
    get: function get() {
      return this._items;
    }
    /**
     * キャンバス上での行の横占有画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "width_assumed",
    get: function get() {
      return this._width_assumed;
    }
    /**
     * キャンバス上での行の縦画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_pixel",
    get: function get() {
      return this._height_pixel;
    }
  }]);

  return RowLayout;
}();

var image_icon_vs_code = "/**\n * テキスト (頂点シェーダ)\n */\n\nattribute vec4 a_position;     // 頂点位置 (モデル座標系)\nattribute vec2 a_offset;       // 頂点変位 (スクリーン座標系)\nattribute vec2 a_texcoord;     // テクスチャ座標\n\nuniform mat4 u_obj_to_clip;    // モデル座標系からクリップ座標系への変換\nuniform vec2 u_sparam;         // 画面パラメータ: {2/w, 2/h}\n\nvarying vec2 v_texcoord;       // テクスチャ座標\n\nvoid\nmain()\n{\n    gl_Position = u_obj_to_clip * a_position;\n    gl_Position.xy += a_offset * u_sparam * gl_Position.w;\n    v_texcoord = a_texcoord;\n}\n";

var image_icon_fs_code = "/**\n * テキスト (フラグメントシェーダ)\n */\n\nprecision mediump float;\n\nvarying vec2 v_texcoord;        // テクスチャ座標\nuniform sampler2D u_image;      // 画像\n\n\nvoid\nmain()\n{\n    gl_FragColor = texture2D( u_image, v_texcoord );\n}\n";

/**
 * @summary イメージアイコンマテリアル
 * @memberof mapray
 * @extends mapray.EntityMaterial
 * @private
 * @see mapray.ImageIconEntity
 */

var ImageIconMaterial =
/*#__PURE__*/
function (_EntityMaterial) {
  _inherits(ImageIconMaterial, _EntityMaterial);

  /**
   * @param {mapray.GLEnv} glenv
   */
  function ImageIconMaterial(glenv) {
    var _this;

    _classCallCheck(this, ImageIconMaterial);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(ImageIconMaterial).call(this, glenv, image_icon_vs_code, image_icon_fs_code)); // 不変パラメータを事前設定

    _this.bindProgram();

    _this.setInteger("u_image", ImageIconMaterial.TEXUNIT_IMAGE); // this.setInteger( "u_image_mask", ImageIconMaterial.TEXUNIT_IMAGE_MASK );


    return _this;
  }
  /**
   * @override
   */


  _createClass(ImageIconMaterial, [{
    key: "isTranslucent",
    value: function isTranslucent(stage, primitive) {
      // 半透明画像は非対応
      return false;
    }
    /**
     * @override
     */

  }, {
    key: "setParameters",
    value: function setParameters(stage, primitive) {
      var props = primitive.properties; // mat4 u_obj_to_clip

      this.setObjToClip(stage, primitive); // 画面パラメータ: {2/w, 2/h}
      // vec2 u_sparam

      var sparam = ImageIconMaterial._sparam;
      sparam[0] = 2 / stage._width;
      sparam[1] = 2 / stage._height;
      this.setVector2("u_sparam", sparam); // テクスチャのバインド
      // sampler2D u_image

      var image = props["image"];
      this.bindTexture2D(ImageIconMaterial.TEXUNIT_IMAGE, image.handle); // テクスチャマスクのバインド
      // sampler2D u_image_mask
      // var image_mask = props["image_mask"];
      // this.bindTexture2D( ImageIconMaterial.TEXUNIT_IMAGE_MASK, image_mask.handle );
    }
  }]);

  return ImageIconMaterial;
}(EntityMaterial); // クラス定数の定義


{
  ImageIconMaterial.TEXUNIT_IMAGE = 0; // 画像のテクスチャユニット
  // ImageIconMaterial.TEXUNIT_IMAGE_MASK = 1;  // 画像マスクのテクスチャユニット
  // 計算用一時領域

  ImageIconMaterial._sparam = GeoMath.createVector2f();
  ImageIconMaterial._bg_color = GeoMath.createVector3f();
  ImageIconMaterial._fg_color = GeoMath.createVector3f();
}

/**
 * @summary 画像アイコンエンティティ
 * @memberof mapray
 * @extends mapray.Entity
 */

var ImageIconEntity =
/*#__PURE__*/
function (_Entity) {
  _inherits(ImageIconEntity, _Entity);

  /**
   * @param {mapray.Scene} scene        所属可能シーン
   * @param {object}       [opts]       オプション集合
   * @param {object}       [opts.json]  生成情報
   * @param {object}       [opts.refs]  参照辞書
   */
  function ImageIconEntity(scene, opts) {
    var _this;

    _classCallCheck(this, ImageIconEntity);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(ImageIconEntity).call(this, scene, opts)); // 要素管理

    _this._entries = []; // 親プロパティ

    _this._parent_props = {
      size: null,
      origin: null
    }; // Entity.PrimitiveProducer インスタンス

    _this._primitive_producer = new PrimitiveProducer$6(_assertThisInitialized(_this)); // 生成情報から設定

    if (opts && opts.json) {
      _this._setupByJson(opts.json);
    }

    return _this;
  }
  /**
   * @override
   */


  _createClass(ImageIconEntity, [{
    key: "getPrimitiveProducer",
    value: function getPrimitiveProducer() {
      return this._primitive_producer;
    }
    /**
     * @summary アイコンのサイズを指定
     * @param {mapray.Vector2} size  アイコンのピクセルサイズ
     */

  }, {
    key: "setSize",
    value: function setSize(size) {
      this._setVector2Property("size", size);
    }
    /**
     * @summary アイコンの原点位置を指定
     * @param {mapray.Vector2} origin  アイコンの原点位置
     */

  }, {
    key: "setOrigin",
    value: function setOrigin(origin) {
      this._setVector2Property("origin", origin);
    }
    /**
     * @summary Add Image Icon
     * @param {URL|HTMLImageElement|HTMLCanvasElement} image_src      画像
     * @param {mapray.GeoPoint} position  位置
     * @param {object}          [props]   プロパティ
     * @param {mapray.Vector2} [props.size]              アイコンサイズ
     */

  }, {
    key: "addImageIcon",
    value: function addImageIcon(image_src, position, props) {
      this._entries.push(new ImageEntry$1(this, image_src, position, props));

      this._primitive_producer.onAddEntry();
    }
    /**
     * @summary 専用マテリアルを取得
     * @private
     */

  }, {
    key: "_getMaterial",
    value: function _getMaterial() {
      var scene = this.scene;

      if (!scene._ImageEntity_image_material) {
        // scene にマテリアルをキャッシュ
        scene._ImageEntity_image_material = new ImageIconMaterial(scene.glenv);
      }

      return scene._ImageEntity_image_material;
    }
    /**
     * @private
     */

  }, {
    key: "_setValueProperty",
    value: function _setValueProperty(name, value) {
      var props = this._text_parent_props;

      if (props[name] != value) {
        props[name] = value;

        this._primitive_producer.onChangeParentProperty();
      }
    }
    /**
     * @private
     */

  }, {
    key: "_setVector2Property",
    value: function _setVector2Property(name, value) {
      var dst = this._parent_props[name];

      if (!dst) {
        this._parent_props[name] = GeoMath.createVector2f(value);

        this._primitive_producer.onChangeParentProperty();
      } else if (dst[0] !== value[0] || dst[1] !== value[1]) {
        GeoMath.copyVector2(value, dst);

        this._primitive_producer.onChangeParentProperty();
      }
    }
    /**
     * @private
     */

  }, {
    key: "_setupByJson",
    value: function _setupByJson(json) {
      var position = new GeoPoint();
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = json.entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var entry = _step.value;
          position.setFromArray(entry.position);
          this.addImageIcon(position, entry);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator["return"] != null) {
            _iterator["return"]();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      if (json.size) this.setSize(json.size);
      if (json.origin) this.setOrigin(json.origin);
    }
  }]);

  return ImageIconEntity;
}(Entity); // クラス定数の定義


{
  ImageIconEntity.DEFAULT_COLOR = GeoMath.createVector3f([1, 1, 1]);
  ImageIconEntity.SAFETY_PIXEL_MARGIN = 1;
  ImageIconEntity.MAX_IMAGE_WIDTH = 4096;
  ImageIconEntity.CIRCLE_SEP_LENGTH = 32;
  ImageIconEntity.DEFAULT_ICON_SIZE = GeoMath.createVector2f([30, 30]);
  ImageIconEntity.DEFAULT_ORIGIN = GeoMath.createVector2f([0.5, 0.5]);
  ImageIconEntity.SAFETY_PIXEL_MARGIN = 1;
  ImageIconEntity.MAX_IMAGE_WIDTH = 4096;
}
/**
 * @summary PrimitiveProducer
 *
 * TODO: relative で標高の変化のたびにテクスチャを生成する必要はないので
 *       Layout でのテクスチャの生成とメッシュの生成を分離する
 *
 * @private
 */

var PrimitiveProducer$6 =
/*#__PURE__*/
function (_Entity$PrimitiveProd) {
  _inherits(PrimitiveProducer, _Entity$PrimitiveProd);

  /**
   * @param {mapray.ImageIconEntity} entity
   */
  function PrimitiveProducer(entity) {
    var _this2;

    _classCallCheck(this, PrimitiveProducer);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(PrimitiveProducer).call(this, entity));
    _this2._glenv = entity.scene.glenv;
    _this2._dirty = true; // プリミティブの要素

    _this2._transform = GeoMath.setIdentity(GeoMath.createMatrix());
    _this2._properties = {
      image: null // アイコン画像

    }; // プリミティブ

    var primitive = new Primitive(_this2._glenv, null, entity._getMaterial(), _this2._transform);
    primitive.properties = _this2._properties;
    _this2._primitive = primitive; // プリミティブ配列

    _this2._primitives = [];
    return _this2;
  }
  /**
   * @override
   */


  _createClass(PrimitiveProducer, [{
    key: "createRegions",
    value: function createRegions() {
      var region = new EntityRegion();
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = this.entity._entries[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var position = _step2.value.position;
          region.addPoint(position);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
            _iterator2["return"]();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      return [region];
    }
    /**
     * @override
     */

  }, {
    key: "onChangeElevation",
    value: function onChangeElevation(regions) {
      this._dirty = true;
    }
    /**
     * @override
     */

  }, {
    key: "getPrimitives",
    value: function getPrimitives(stage) {
      return this._updatePrimitive();
    }
    /**
     * @summary 親プロパティが変更されたことを通知
     */

  }, {
    key: "onChangeParentProperty",
    value: function onChangeParentProperty() {
      this._dirty = true;
    }
    /**
     * @summary 高度モードが変更されたことを通知
     */

  }, {
    key: "onChangeAltitudeMode",
    value: function onChangeAltitudeMode() {
      this._dirty = true;
    }
    /**
     * @summary エントリが追加されたことを通知
     */

  }, {
    key: "onAddEntry",
    value: function onAddEntry() {
      // 変化した可能性がある
      this.needToCreateRegions();
      this._dirty = true;
    }
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * 入力:
     *   this.entity._entries
     *   this._dirty
     * 出力:
     *   this._transform
     *   this._properties.image
     *   this._primitive.mesh
     *   this._primitives
     *   this._dirty
     *
     * @return {array.<mapray.Prmitive>}  this._primitives
     *
     * @private
     */

  }, {
    key: "_updatePrimitive",
    value: function _updatePrimitive() {
      if (!this._dirty) {
        // 更新する必要はない
        return this._primitives;
      }

      if (this.entity._entries.length == 0) {
        this._primitives = [];
        this._dirty = false;
        return this._primitives;
      } // 各エントリーの GOCS 位置を生成 (平坦化配列)


      var gocs_array = this._createFlatGocsArray(); // プリミティブの更新
      //   primitive.transform


      this._updateTransform(gocs_array);

      var layout = new Layout$2(this, gocs_array);

      if (!layout.isValid()) {
        // 更新に失敗
        this._primitives = [];
        this._dirty = false;
        return this._primitives;
      } // テクスチャ設定


      var properties = this._properties;

      if (properties.image) {
        properties.image.dispose();
      }

      properties.image = layout.texture; // メッシュ生成

      var mesh_data = {
        vtype: [{
          name: "a_position",
          size: 3
        }, {
          name: "a_offset",
          size: 2
        }, {
          name: "a_texcoord",
          size: 2
        }],
        vertices: layout.vertices,
        indices: layout.indices
      };
      var mesh = new Mesh(this._glenv, mesh_data); // メッシュ設定
      //   primitive.mesh

      var primitive = this._primitive;

      if (primitive.mesh) {
        primitive.mesh.dispose();
      }

      primitive.mesh = mesh; // 更新に成功

      this._primitives = [primitive];
      this._dirty = false;
      return this._primitives;
    }
    /**
     * @summary プリミティブの更新
     *
     * @desc
     * 条件:
     *   this.entity._entries.length > 0
     * 入力:
     *   this.entity._entries.length
     * 出力:
     *   this._transform
     *
     * @param {number[]} gocs_array  GOCS 平坦化配列
     *
     * @private
     */

  }, {
    key: "_updateTransform",
    value: function _updateTransform(gocs_array) {
      var num_entries = this.entity._entries.length;
      var xsum = 0;
      var ysum = 0;
      var zsum = 0;

      for (var i = 0; i < num_entries; ++i) {
        var ibase = 3 * i;
        xsum += gocs_array[ibase];
        ysum += gocs_array[ibase + 1];
        zsum += gocs_array[ibase + 2];
      } // 変換行列の更新


      var transform = this._transform;
      transform[12] = xsum / num_entries;
      transform[13] = ysum / num_entries;
      transform[14] = zsum / num_entries;
    }
    /**
     * @summary GOCS 平坦化配列を取得
     *
     * 入力: this.entity._entries
     *
     * @return {number[]}  GOCS 平坦化配列
     * @private
     */

  }, {
    key: "_createFlatGocsArray",
    value: function _createFlatGocsArray() {
      var num_points = this.entity._entries.length;
      return GeoPoint.toGocsArray(this._getFlatGeoPoints_with_Absolute(), num_points, new Float64Array(3 * num_points));
    }
    /**
     * @summary GeoPoint 平坦化配列を取得 (絶対高度)
     *
     * 入力: this.entity._entries
     *
     * @return {number[]}  GeoPoint 平坦化配列
     * @private
     */

  }, {
    key: "_getFlatGeoPoints_with_Absolute",
    value: function _getFlatGeoPoints_with_Absolute() {
      var owner = this.entity;
      var entries = owner._entries;
      var num_points = entries.length;
      var flat_array = new Float64Array(3 * num_points); // flat_array[] に経度要素と緯度要素を設定

      for (var i = 0; i < num_points; ++i) {
        var pos = entries[i].position;
        flat_array[3 * i] = pos.longitude;
        flat_array[3 * i + 1] = pos.latitude;
      }

      switch (owner.altitude_mode) {
        case AltitudeMode.RELATIVE:
        case AltitudeMode.CLAMP:
          // flat_array[] の高度要素に現在の標高を設定
          owner.scene.viewer.getExistingElevations(num_points, flat_array, 0, 3, flat_array, 2, 3);

          if (owner.altitude_mode === AltitudeMode.RELATIVE) {
            // flat_array[] の高度要素に絶対高度を設定
            for (var _i = 0; _i < num_points; ++_i) {
              flat_array[3 * _i + 2] += entries[_i].position.altitude;
            }
          }

          break;

        default:
          // AltitudeMode.ABSOLUTE
          // flat_array[] の高度要素に絶対高度を設定
          for (var _i2 = 0; _i2 < num_points; ++_i2) {
            flat_array[3 * _i2 + 2] = entries[_i2].position.altitude;
          }

          break;
      }

      return flat_array;
    }
  }]);

  return PrimitiveProducer;
}(Entity.PrimitiveProducer);
/**
 * @summary 要素
 * @memberof mapray.ImageIconEntity
 * @private
 */


var ImageEntry$1 =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.ImageIconEntity} owner        所有者
   * @param {string}                 image_src    アイコン画像
   * @param {mapray.GeoPoint}        position     位置
   * @param {object}                 [props]      プロパティ
   * @param {mapray.Vector2}         [props.size] アイコンサイズ
   */
  function ImageEntry(owner, image_src, position, props) {
    var _this3 = this;

    _classCallCheck(this, ImageEntry);

    this._owner = owner;
    this._image_src = image_src;
    this._position = position.clone();
    this._props = Object.assign({}, props); // props の複製

    this._copyPropertyVector2f("size"); // deep copy


    this._copyPropertyVector2f("origin"); // deep copy


    this._icon = ImageEntry.iconLoader.load(image_src);

    this._icon.onEnd(function (item) {
      _this3._owner.getPrimitiveProducer()._dirty = true;
    });
  }
  /**
   * @summary 位置
   * @type {mapray.GeoPoint}
   * @readonly
   */


  _createClass(ImageEntry, [{
    key: "_copyPropertyVector3f",

    /**
     * @private
     */
    value: function _copyPropertyVector3f(name) {
      var props = this._props;

      if (props.hasOwnProperty(name)) {
        props[name] = GeoMath.createVector3f(props[name]);
      }
    }
    /**
     * @private
     */

  }, {
    key: "_copyPropertyVector2f",
    value: function _copyPropertyVector2f(name) {
      var props = this._props;

      if (props.hasOwnProperty(name)) {
        if (typeof props[name] === 'number') {
          props[name] = GeoMath.createVector2f([props[name], props[name]]);
        } else {
          props[name] = GeoMath.createVector2f(props[name]);
        }
      }
    }
  }, {
    key: "isLoaded",
    value: function isLoaded() {
      return this._icon.isLoaded();
    }
  }, {
    key: "draw",
    value: function draw(context, x, y, width, height) {
      this._icon.draw(context, x, y, width, height);
    }
  }, {
    key: "position",
    get: function get() {
      return this._position;
    }
    /**
     * @summary アイコンサイズ (Pixels)
     * @type {mapray.Vector2}
     * @readonly
     */

  }, {
    key: "size",
    get: function get() {
      var props = this._props;
      var parent = this._owner._parent_props;
      return props.size || parent.size || GeoMath.createVector2f([this._icon.width, this._icon.height]);
    }
    /**
     * @summary アイコンオリジン位置 (左上を(0, 0)、右下を(1, 1)としする数字を指定する。)
     * @type {mapray.Vector2}
     * @readonly
     */

  }, {
    key: "origin",
    get: function get() {
      var props = this._props;
      var parent = this._owner._parent_props;
      return props.origin || parent.origin || ImageIconEntity.DEFAULT_ORIGIN;
    }
  }, {
    key: "icon",
    get: function get() {
      return this._icon;
    }
  }]);

  return ImageEntry;
}();

{
  ImageEntry$1.iconLoader = new ImageIconLoader();
}
/**
 * @summary Pin画像を Canvas 上にレイアウト
 * @memberof mapray.ImageIconEntity
 * @private
 */

var Layout$2 =
/*#__PURE__*/
function () {
  /**
   * @desc
   * 入力:
   *   owner._glenv
   *   owner.entity._entries
   *   owner._transform
   *
   * @param {PrimitiveProducer} owner       所有者
   * @param {number[]}          gocs_array  GOCS 平坦化配列
   */
  function Layout(owner, gocs_array) {
    _classCallCheck(this, Layout);

    this._owner = owner;
    this._items = this._createItemList();
    this._is_valid = true;

    var row_layouts = this._createRowLayouts();

    if (row_layouts.length == 0) {
      // 有効なテキストが1つも無い
      this._is_valid = false;
      return;
    } // アイテムの配置の設定とキャンバスサイズの決定


    var size = this._setupLocation(row_layouts);

    this._texture = this._createTexture(size.width, size.height);
    this._vertices = this._createVertices(size.width, size.height, gocs_array);
    this._indices = this._createIndices();
  }
  /**
   * @summary 有効なオブジェクトか?
   * @desc
   * <p>無効のとき、他のメソッドは呼び出せない。</p>
   * @return {boolean}  有効のとき true, 無効のとき false
   */


  _createClass(Layout, [{
    key: "isValid",
    value: function isValid() {
      return this._is_valid;
    }
    /**
     * @summary テクスチャ
     * @type {mapray.Texture}
     * @readonly
     */

  }, {
    key: "_createItemList",

    /**
     * @summary レイアウトアイテムのリストを生成
     * @return {array.<mapray.ImageIconEntity.LItem>}
     * @private
     */
    value: function _createItemList() {
      var map = new Map();
      var items = [];
      var counter = 0;
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = this._owner.entity._entries[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var entry = _step3.value;

          if (entry.isLoaded()) {
            var item = map.get(entry.icon);

            if (!item) {
              map.set(entry.icon, item = new LItem$2(this));
              items.push(item);
            }

            item.add(counter++, entry);
          }
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) {
            _iterator3["return"]();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }

      return items;
    }
    /**
     * @summary RowLayout のリストを生成
     * @return {array.<mapray.ImageIconEntity.RowLayout>}
     * @private
     */

  }, {
    key: "_createRowLayouts",
    value: function _createRowLayouts() {
      // アイテムリストの複製
      var items = [].concat(this._items); // RowLayout 内であまり高さに差が出ないように、アイテムリストを高さで整列

      items.sort(function (a, b) {
        return a.height_pixel - b.height_pixel;
      }); // リストを生成

      var row_layouts = [];

      while (items.length > 0) {
        var row_layout = new RowLayout$2(items);

        if (row_layout.isValid()) {
          row_layouts.push(row_layout);
        }
      }

      return row_layouts;
    }
    /**
     * @summary テクスチャを生成
     * @param  {number} width    横幅
     * @param  {number} height   高さ
     * @return {mapray.Texture}  テキストテクスチャ
     * @private
     */

  }, {
    key: "_createTexture",
    value: function _createTexture(width, height) {
      var context = Dom.createCanvasContext(width, height);
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;
        item.draw(context);
      }

      var glenv = this._owner._glenv;
      var opts = {
        usage: Texture.Usage.ICON
      };
      return new Texture(glenv, context.canvas, opts);
    }
    /**
     * @summary 頂点配列を生成
     *
     * @param  {number}   width       横幅
     * @param  {number}   height      高さ
     * @param  {number[]} gocs_array  GOCS 平坦化配列
     * @return {array.<number>}  頂点配列 [左下0, 右下0, 左上0, 右上0, ...]
     *
     * @private
     */

  }, {
    key: "_createVertices",
    value: function _createVertices(width, height, gocs_array) {
      var vertices = []; // テキスト集合の原点 (GOCS)

      var transform = this._owner._transform;
      var xo = transform[12];
      var yo = transform[13];
      var zo = transform[14];
      /*
       |<----size[0]px---->|
       0-------------------3 ------------------
      |                   |  ^              ^
      |                   |  | origin[1]    |
      |                   |  |              |
      |                   |  v              | size[1]px
      |           o       | ---             |
      |                   |  ^              |
      |                   |  | 1-origin[1]  |
      |                   |  v              v
      1-------------------2 ------------------

      |           |<----->|    1 - origin[0]
      |<--------->|            origin[0]
      */

      var xn = 1 / width;
      var yn = 1 / height;
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;

        for (var ie = 0; ie < item.entries.length; ie++) {
          var eitem = item.entries[ie];
          var entry = eitem.entry;
          var size = entry.size;
          var origin = entry.origin; // Relativize based on (xo, yo, zo)

          var ibase = eitem.index * 3;
          var xm = gocs_array[ibase] - xo;
          var ym = gocs_array[ibase + 1] - yo;
          var zm = gocs_array[ibase + 2] - zo; // Image dimensions (Image Coordinate)

          var xc = item.pos_x;
          var yc = item.pos_y;
          var xsize = item.width;
          var ysize = item.height; // p0

          vertices.push(xm, ym, zm); // a_position

          vertices.push(-origin[0] * size[0], origin[1] * size[1]); // a_offset

          vertices.push(xc * xn, 1.0 - yc * yn); // a_texcoord
          // p1

          vertices.push(xm, ym, zm); // a_position

          vertices.push(-origin[0] * size[0], -(1 - origin[1]) * size[1]); // a_offset

          vertices.push(xc * xn, 1 - (yc + ysize) * yn); // a_texcoord
          // p2

          vertices.push(xm, ym, zm); // a_position

          vertices.push((1 - origin[0]) * size[0], -(1 - origin[1]) * size[1]); // a_offset

          vertices.push((xc + xsize) * xn, 1 - (yc + ysize) * yn); // a_texcoord
          // p3

          vertices.push(xm, ym, zm); // a_position

          vertices.push((1 - origin[0]) * size[0], origin[1] * size[1]); // a_offset

          vertices.push((xc + xsize) * xn, 1 - yc * yn); // a_texcoord
        }
      }

      return vertices;
    }
    /**
     * @summary インデックス配列を生成
     * @return {array.<number>}  インデックス配列 []
     * @private
     */

  }, {
    key: "_createIndices",
    value: function _createIndices() {
      var indices = [];
      var items = this._items;

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        if (item.is_canceled) continue;

        for (var ie = 0; ie < item.entries.length; ie++) {
          var eitem = item.entries[ie];
          var base = 4 * eitem.index;
          var p = base;
          indices.push(p, p + 1, p + 2);
          indices.push(p, p + 2, p + 3);
        }
      }

      return indices;
    }
    /**
     * @summary アイテムの配置を設定
     * @param  {array.<mapray.ImageIconEntity.RowLayout>} row_layouts
     * @return {object}                              キャンバスサイズ
     * @private
     */

  }, {
    key: "_setupLocation",
    value: function _setupLocation(row_layouts) {
      var width = 0;
      var height = 0;
      height += ImageIconEntity.SAFETY_PIXEL_MARGIN;

      for (var i = 0; i < row_layouts.length; ++i) {
        var row_layout = row_layouts[i];
        row_layout.locate(height);
        width = Math.max(row_layout.width_assumed, width);
        height += row_layout.height_pixel + ImageIconEntity.SAFETY_PIXEL_MARGIN;
      }

      return {
        width: width,
        height: height
      };
    }
  }, {
    key: "texture",
    get: function get() {
      return this._texture;
    }
    /**
     * @summary 頂点配列
     * @desc
     * 条件:
     *   this._entries.length > 0
     * 入力:
     *   this._entries
     *   this._transform
     * @type {Float32Array}
     * @readonly
     */

  }, {
    key: "vertices",
    get: function get() {
      return this._vertices;
    }
    /**
     * @summary インデックス配列
     * @type {Uint32Array}
     * @readonly
     */

  }, {
    key: "indices",
    get: function get() {
      return this._indices;
    }
  }]);

  return Layout;
}();
/**
 * @summary レイアウト対象
 * @memberof mapray.ImageIconEntity
 * @private
 */


var LItem$2 =
/*#__PURE__*/
function () {
  /**
   * @param {mapray.ImageIconEntity.Layout} layout   所有者
   * @param {mapray.ImageIconEntity.Entry}  entry    ImageIconEntityのエントリ
   */
  function LItem(layout) {
    _classCallCheck(this, LItem);

    this.entries = []; // テキストの基点

    this._pos_x = 0; // 左端

    this._pos_y = 0; // ベースライン位置

    this._height = this._width = null;
    this._is_canceled = false;
  }

  _createClass(LItem, [{
    key: "add",
    value: function add(index, entry) {
      var size = entry.size;
      if (this._width === null || this._width < size[0]) this._width = size[0];
      if (this._height === null || this._height < size[1]) this._height = size[1];
      this.entries.push({
        index: index,
        entry: entry
      });
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "cancel",

    /**
     * @summary 取り消し状態に移行
     */
    value: function cancel() {
      this._is_canceled = true;
    }
    /**
     * @summary 配置を決定
     * @param {number} x  テキスト矩形左辺の X 座標 (キャンバス座標系)
     * @param {number} y  テキスト矩形上辺の Y 座標 (キャンバス座標系)
     */

  }, {
    key: "locate",
    value: function locate(x, y) {
      this._pos_x = x;
      this._pos_y = y;
    }
  }, {
    key: "draw",
    value: function draw(context) {
      this.entries[0].entry.draw(context, this._pos_x, this.pos_y, this.width, this.height); // @Todo: fix this
    }
  }, {
    key: "pos_x",
    get: function get() {
      return this._pos_x;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "pos_y",
    get: function get() {
      return this._pos_y;
    }
    /**
     * @type {number}
     * @readonly
     */

  }, {
    key: "width",
    get: function get() {
      return this._width;
    }
  }, {
    key: "height",
    get: function get() {
      return this._height;
    }
    /**
     * キャンバス上でのテキストの横画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "width_pixel",
    get: function get() {
      return Math.ceil(this._width);
    }
    /**
     * キャンバス上でのテキストの縦画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_pixel",
    get: function get() {
      return Math.ceil(this._height);
    }
    /**
     * 取り消し状態か?
     * @type {boolean}
     * @readonly
     */

  }, {
    key: "is_canceled",
    get: function get() {
      return this._is_canceled;
    }
  }]);

  return LItem;
}();
/**
 * @summary 水平レイアウト
 * @memberof mapray.ImageIconEntity
 * @private
 */


var RowLayout$2 =
/*#__PURE__*/
function () {
  /**
   * @desc
   * <p>レイアウトされた、またはレイアウトに失敗したアイテムは src_items から削除される。</p>
   * <p>レイアウトに失敗したアイテムは取り消し (is_canceled) になる。</p>
   * @param {array.<mapray.ImageIconEntity.LItem>} src_items  アイテムリスト
   */
  function RowLayout(src_items) {
    _classCallCheck(this, RowLayout);

    var width_assumed_total = 0;
    var height_pixel_max = 0;
    var row_items = [];
    width_assumed_total += ImageIconEntity.SAFETY_PIXEL_MARGIN; // 左マージン

    while (src_items.length > 0) {
      var item = src_items.shift();
      var width_assumed = item.width_pixel + ImageIconEntity.SAFETY_PIXEL_MARGIN; // テキスト幅 + 右マージン

      if (width_assumed_total + width_assumed <= ImageIconEntity.MAX_IMAGE_WIDTH) {
        // 行にアイテムを追加
        row_items.push(item);
        width_assumed_total += width_assumed;
        height_pixel_max = Math.max(item.height_pixel, height_pixel_max);
      } else {
        if (row_items.length == 0) {
          // テキストが長すぎて表示できない
          item.cancel();
        } else {
          // 次の行になるため差し戻して終了
          src_items.unshift(item);
          break;
        }
      }
    }

    this._items = row_items;
    this._width_assumed = width_assumed_total;
    this._height_pixel = height_pixel_max;
  }
  /**
   * @summary 有効なオブジェクトか?
   * @desc
   * <p>無効のとき、他のメソッドは呼び出せない。</p>
   * @return {boolean}  有効のとき true, 無効のとき false
   */


  _createClass(RowLayout, [{
    key: "isValid",
    value: function isValid() {
      return this._items.length > 0;
    }
    /**
     *
     * @type {array.<mapray.ImageIconEntity.LItem>}
     * @readonly
     */

  }, {
    key: "locate",

    /**
     * @summary レイアウトの配置を決定
     * @param {number} y  テキスト矩形上辺の Y 座標 (キャンバス座標系)
     */
    value: function locate(y) {
      var items = this._items;
      var x = 0;
      x += ImageIconEntity.SAFETY_PIXEL_MARGIN; // 左マージン

      for (var i = 0; i < items.length; ++i) {
        var item = items[i];
        item.locate(x, y);
        x += item.width_pixel + ImageIconEntity.SAFETY_PIXEL_MARGIN; // テキスト幅 + 右マージン
      }
    }
  }, {
    key: "items",
    get: function get() {
      return this._items;
    }
    /**
     * キャンバス上での行の横占有画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "width_assumed",
    get: function get() {
      return this._width_assumed;
    }
    /**
     * キャンバス上での行の縦画素数
     * @type {number}
     * @readonly
     */

  }, {
    key: "height_pixel",
    get: function get() {
      return this._height_pixel;
    }
  }]);

  return RowLayout;
}();

var $reduce$1 = arrayReduce.left;
var STRICT_METHOD$5 = arrayMethodIsStrict('reduce');
var USES_TO_LENGTH$8 = arrayMethodUsesToLength('reduce', {
  1: 0
}); // `Array.prototype.reduce` method
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce

_export({
  target: 'Array',
  proto: true,
  forced: !STRICT_METHOD$5 || !USES_TO_LENGTH$8
}, {
  reduce: function reduce(callbackfn
  /* , initialValue */
  ) {
    return $reduce$1(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
  }
});

var propertyIsEnumerable = objectPropertyIsEnumerable.f; // `Object.{ entries, values }` methods implementation

var createMethod$5 = function (TO_ENTRIES) {
  return function (it) {
    var O = toIndexedObject(it);
    var keys = objectKeys(O);
    var length = keys.length;
    var i = 0;
    var result = [];
    var key;

    while (length > i) {
      key = keys[i++];

      if (!descriptors || propertyIsEnumerable.call(O, key)) {
        result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
      }
    }

    return result;
  };
};

var objectToArray = {
  // `Object.entries` method
  // https://tc39.github.io/ecma262/#sec-object.entries
  entries: createMethod$5(true),
  // `Object.values` method
  // https://tc39.github.io/ecma262/#sec-object.values
  values: createMethod$5(false)
};

var $values = objectToArray.values; // `Object.values` method
// https://tc39.github.io/ecma262/#sec-object.values

_export({
  target: 'Object',
  stat: true
}, {
  values: function values(O) {
    return $values(O);
  }
});

/**
 * GeoJSON形式(<a href="https://tools.ietf.org/html/rfc7946">rfc7946</a>)のデータをシーンに読み込みます。
 * @memberof mapray
 */

var GeoJSONLoader =
/*#__PURE__*/
function (_Loader) {
  _inherits(GeoJSONLoader, _Loader);

  /**
   * @desc
   * <p>url で指定したシーンデータの読み込みを開始し、scene にエンティティを構築する。</p>
   * <p>読み込みが終了したとき options.callback を呼び出す。</p>
   * @param {mapray.Scene} scene      読み込み先のシーン
   * @param {string}       resource        シーンファイルの URL
   * @param {object}       [options]  オプション集合
   * @param {mapray.GeoJSONLoader.TransformCallback} [options.transform]  リソース要求変換関数
   * @param {mapray.GeoJSONLoader.FinishCallback}    [options.callback]   終了コールバック関数
   */
  function GeoJSONLoader(scene, resource) {
    var _this;

    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

    _classCallCheck(this, GeoJSONLoader);

    if (resource instanceof Resource) ; else if (typeof resource === "string") {
      resource = new URLResource(resource, {
        type: "json",
        transform: options.transform
      });
    } else {
      throw new Error("Unsupported Resource: " + resource);
    }

    _this = _possibleConstructorReturn(this, _getPrototypeOf(GeoJSONLoader).call(this, scene, resource, {
      onLoad: options.onLoad
    })); // PinEntity

    _this._getPointFGColor = options.getPointFGColor || defaultGetPointFGColorCallback;
    _this._getPointBGColor = options.getPointBGColor || defaultGetPointBGColorCallback;
    _this._getPointSize = options.getPointSize || defaultGetPointSizeCallback;
    _this._getPointIconId = options.getPointIconId || defaultGetPointIconIdCallback; // MarkerLineEntity

    _this._getLineColor = options.getLineColor || defaultGetLineColorCallback;
    _this._getLineWidth = options.getLineWidth || defaultGetLineWidthCallback; // PolygonEntity

    _this._getFillColor = options.getFillColor || defaultGetFillColorCallback;
    _this._getExtrudedHeight = options.getExtrudedHeight || defaultGetExtrudedHeightCallback; // Common

    _this._getAltitudeMode = options.getAltitudeMode || defaultGetAltitudeModeCallback;
    _this._getAltitude = options.getAltitude || defaultGetAltitudeCallback;
    _this._transform = options.transform || defaultTransformCallback$2;
    _this._glenv = scene.glenv;
    _this._references = {};
    _this._cancelled = false;
    _this._finished = false;
    return _this;
  }

  _createClass(GeoJSONLoader, [{
    key: "_load",
    value: function _load() {
      var _this2 = this;

      return this._resource.load().then(function (geoJson) {
        // JSON データの取得に成功
        _this2._check_cancel();

        _this2._load_geojson_object(geoJson);
      });
    }
    /**
     * Load GeoJSON Object
     * @private
     */

  }, {
    key: "_load_geojson_object",
    value: function _load_geojson_object(geojson) {
      var success;

      if (geojson.type === TYPES.FEATURE_COLLECTION) {
        var features = geojson.features;
        success = false;

        for (var i = 0, len = features.length; i < len; i++) {
          var feature = features[i];

          var s = this._load_geojson_object(feature.featureId ? feature.feature : feature); // @ToDo: Unknown
          // var s = this._load_geojson_object( feature );


          if (s && !success) success = s;
        }
      } else if (geojson.type === TYPES.FEATURE) {
        var geometry = geojson.geometry;
        success = this._load_geometry_object(geometry, geojson);
      } else if (SUPPORTED_GEOMETRY_TYPES.indexOf(geojson.type) !== -1) {
        success = this._load_geometry_object(geojson, null);
      } else {
        throw new Error("Unnsupported Type: " + geojson.type);
      }

      if (this._cancelled) return false;
      return success;
    }
    /**
     * Load Geometry Object
     * @private
     */

  }, {
    key: "_load_geometry_object",
    value: function _load_geometry_object(geometry) {
      var geojson = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      var coords = geometry.coordinates;

      if (!coords && !geometry) {
        return false;
      }

      switch (geometry.type) {
        case GEOMETRY_TYPES.POINT:
        case GEOMETRY_TYPES.MULTI_POINT:
          return this._loadPoint(geometry, geojson);

        case GEOMETRY_TYPES.LINE_STRING:
        case GEOMETRY_TYPES.MULTI_LINE_STRING:
          return this._loadLines(geometry, geojson);

        case GEOMETRY_TYPES.POLYGON:
        case GEOMETRY_TYPES.MULTI_POLYGON:
          return this._loadPolygons(geometry, geojson);

        case GEOMETRY_TYPES.GEOMETRY_COLLECTION:
          return true;

        default:
          throw new Error("Invalid GeoJSON type: " + geometry.type);
      }
    }
    /**
     * fetch() の init 引数に与えるオブジェクトを生成
     * @private
     */

  }, {
    key: "_make_fetch_params",
    value: function _make_fetch_params(tr) {
      var init = {
        signal: this._abort_ctrl.signal,
        credentials: (tr.credentials || CredentialMode.OMIT).credentials
      };

      if (tr.headers) {
        init.headers = tr.headers || GeoJSONLoader._defaultHeaders;
      }

      return init;
    }
  }, {
    key: "_loadLines",
    value: function _loadLines(geometry, geojson) {
      var _this3 = this;

      var color4 = this._getLineColor(geojson);

      var width = this._getLineWidth(geojson);

      var altitude = this._getAltitude(geojson);

      var altitude_mode = this._getAltitudeMode(geojson);

      if (!geometry || color4.length !== 4) {
        return false;
      }

      var type = geometry.type;
      var coords = geometry.coordinates;
      var rgb = color4.slice(0, 3);
      var alpha = color4[3]; // If multiline, split entity

      if (type === GEOMETRY_TYPES.MULTI_LINE_STRING) {
        coords.forEach(function (points) {
          if (!_this3._generateLine(points, width, rgb, alpha, altitude_mode, altitude)) {
            return false;
          }
        });
        return true;
      } else {
        // type === GEOMETRY_TYPES.LINE_STRING
        return this._generateLine(coords, width, rgb, alpha, altitude_mode, altitude);
      }
    }
  }, {
    key: "_generateLine",
    value: function _generateLine(points, width, color, opaticy, altitude_mode, altitude) {
      if (!points) {
        return false;
      }

      var entity = new MarkerLineEntity(this._scene);
      entity.altitude_mode = altitude_mode;

      var fp = this._flatten(points, altitude);

      entity.addPoints(fp);
      entity.setLineWidth(width);
      entity.setColor(color);
      entity.setOpacity(opaticy);

      this._scene.addEntity(entity);

      return true;
    }
  }, {
    key: "_loadPoint",
    value: function _loadPoint(geometry, geojson) {
      var fgColor = this._getPointFGColor(geojson);

      var bgColor = this._getPointBGColor(geojson);

      var iconId = this._getPointIconId(geojson);

      var size = this._getPointSize(geojson);

      var altitude_mode = this._getAltitudeMode(geojson);

      var altitude = this._getAltitude(geojson);

      if (!geometry) {
        return false;
      }

      var type = geometry.type;
      var props = {
        "fg_color": fgColor.slice(0, 3),
        "bg_color": bgColor.slice(0, 3),
        size: size
      }; // If multiline, split entity

      if (type === GEOMETRY_TYPES.POINT) {
        var entity = new PinEntity(this._scene);
        entity.altitude_mode = altitude_mode;

        var alt = this._getActualValue(altitude, geometry.coordinates[2], GeoJSONLoader.defaultAltitude);

        var coords = new GeoPoint(geometry.coordinates[0], geometry.coordinates[1], alt);

        if (iconId !== null) {
          entity.addMakiIconPin(iconId, coords, props);
        } else {
          entity.addPin(coords, props);
        }

        this._scene.addEntity(entity);
      } else {
        // type === GEOMETRY_TYPES.MULTI_POINT
        var entity = new PinEntity(this._scene);
        entity.altitude_mode = altitude_mode;

        for (var i = 0; i < geometry.coordinates.length; i++) {
          var targetCoordinates = geometry.coordinates[i];

          var alt = this._getActualValue(altitude, geometry.coordinates[2], GeoJSONLoader.defaultAltitude);

          var coords = new GeoPoint(targetCoordinates[0], targetCoordinates[1], alt);

          if (iconId !== null) {
            entity.addMakiIconPin(iconId, coords, props); // entity.addPin( coords, props );
          } else {
            entity.addPin(coords, props);
          }
        }

        this._scene.addEntity(entity);
      }

      return true;
    }
  }, {
    key: "_loadPolygons",
    value: function _loadPolygons(geometry, geojson) {
      var _this4 = this;

      var color4 = this._getFillColor(geojson);

      var altitude_mode = this._getAltitudeMode(geojson);

      var altitude = this._getAltitude(geojson);

      var extruded_height = this._getExtrudedHeight(geojson);

      if (!geometry || color4.length !== 4) {
        return false;
      }

      var type = geometry.type;
      var coords = geometry.coordinates;
      var rgb = color4.slice(0, 3);
      var alpha = color4[3]; // If multiline, split entity

      if (type === GEOMETRY_TYPES.MULTI_POLYGON) {
        coords.forEach(function (points) {
          if (!_this4._generatePolygon(points, rgb, alpha, altitude_mode, altitude, extruded_height)) {
            return false;
          }
        });
        return true;
      } else {
        // type === GEOMETRY_TYPES.POLYGON
        return this._generatePolygon(coords, rgb, alpha, altitude_mode, altitude, extruded_height);
      }
    }
  }, {
    key: "_generatePolygon",
    value: function _generatePolygon(pointsList, color, opaticy, altitude_mode, altitude, extruded_height) {
      if (!pointsList) {
        return false;
      }

      var entity = new PolygonEntity(this._scene);
      entity.altitude_mode = altitude_mode;
      entity.extruded_height = extruded_height;
      entity.setColor(color);
      entity.setOpacity(opaticy);

      for (var i = 0; i < pointsList.length; i++) {
        var fp = this._flatten(pointsList[i], altitude, pointsList[i].length - 1);

        if (!fp) return false;
        if (i === 0) entity.addOuterBoundary(fp);else entity.addInnerBoundary(fp);
      }

      this._scene.addEntity(entity);

      return true;
    }
  }, {
    key: "_getActualValue",
    value: function _getActualValue(valueFromCallback, valueInGeoJSON, defaultValue) {
      return valueFromCallback != null ? valueFromCallback : // value from callback is the most prioritized
      valueInGeoJSON != null ? valueInGeoJSON : // value in GeoJSON will be used if defined
      defaultValue // default value
      ;
    }
  }, {
    key: "_flatten",
    value: function _flatten(ary, altitude) {
      var _this5 = this;

      var len = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ary.length;
      return ary.reduce(function (p, c, i) {
        return i >= len ? p : p.concat(c.slice(0, 2), _this5._getActualValue(altitude, c[2], GeoJSONLoader.defaultAltitude));
      }, []);
    }
  }]);

  return GeoJSONLoader;
}(Loader);
/**
 * @summary リソース要求変換関数
 * @callback TransformCallback
 * @desc
 * <p>リソースのリクエスト時に URL などを変換する関数の型である。</p>
 *
 * @param  {string}                          url   変換前のリソース URL
 * @param  {mapray.GeoJSONLoader.ResourceType} type  リソースの種類
 * @return {mapray.GeoJSONLoader.TransformResult}    変換結果を表すオブジェクト
 *
 * @example
 * function( url, type ) {
 *     return {
 *         url:         url,
 *         credentials: mapray.CredentialMode.SAME_ORIGIN,
 *         headers: {
 *             'Header-Name': 'Header-Value'
 *         }
 *     };
 * }
 *
 * @memberof mapray.GeoJSONLoader
 */

/**
 * @summary リソース要求変換関数の変換結果
 * @typedef {object} TransformResult
 * @desc
 * <p>関数型 {@link mapray.GeoJSONLoader.TransformCallback} の戻り値のオブジェクト構造である。</p>
 * <p>注意: 現在のところ、リソースの種類が {@link mapray.GeoJSONLoader.ResourceType|ResourceType}.IMAGE のとき、headers プロパティの値は無視される。</p>
 * @property {string}                url                 変換後のリソース URL
 * @property {mapray.CredentialMode} [credentials=OMIT]  クレデンシャルモード
 * @property {object}                [headers={}]        リクエストに追加するヘッダーの辞書 (キーがヘッダー名、値がヘッダー値)
 * @memberof mapray.GeoJSONLoader
 */


{
  GeoJSONLoader._defaultHeaders = {};
  GeoJSONLoader.defaultLineColor = [0, 0, 0, 1];
  GeoJSONLoader.defaultFillColor = [0, 0, 0, 1];
  GeoJSONLoader.defaultLineWidth = 1;
  GeoJSONLoader.defaultPointFGColor = [1.0, 1.0, 1.0];
  GeoJSONLoader.defaultPointBGColor = [0.35, 0.61, 0.81];
  GeoJSONLoader.defaultPointSize = 30;
  GeoJSONLoader.defaultPointIconId = null;
  GeoJSONLoader.defaultAltitude = 0.0;
  GeoJSONLoader.defaultExtrudedHeight = 0.0;
}

function defaultGetLineColorCallback(geojson) {
  return GeoJSONLoader.defaultLineColor;
}

function defaultGetLineWidthCallback(geojson) {
  return GeoJSONLoader.defaultLineWidth;
}

function defaultGetFillColorCallback(geojson) {
  return GeoJSONLoader.defaultFillColor;
}

function defaultGetPointFGColorCallback(geojson) {
  return GeoJSONLoader.defaultPointFGColor;
}

function defaultGetPointBGColorCallback(geojson) {
  return GeoJSONLoader.defaultPointBGColor;
}

function defaultGetPointSizeCallback(geojson) {
  return GeoJSONLoader.defaultPointSize;
}

function defaultGetPointIconIdCallback(geojson) {
  return GeoJSONLoader.defaultPointIconId;
}

function defaultGetAltitudeModeCallback(geojson) {
  return AltitudeMode.ABSOLUTE;
}

function defaultGetAltitudeCallback(geojson) {
  return null;
}

function defaultGetExtrudedHeightCallback(geojson) {
  return GeoJSONLoader.defaultExtrudedHeight;
}

function defaultTransformCallback$2(url) {
  return {
    url: url
  };
}

var TYPES = {
  FEATURE: "Feature",
  FEATURE_COLLECTION: "FeatureCollection"
};
var GEOMETRY_TYPES = {
  POINT: "Point",
  MULTI_POINT: "MultiPoint",
  LINE_STRING: "LineString",
  MULTI_LINE_STRING: "MultiLineString",
  POLYGON: "Polygon",
  MULTI_POLYGON: "MultiPolygon",
  GEOMETRY_COLLECTION: "GeometryCollection",
  FEATURE: "Feature"
};
var SUPPORTED_GEOMETRY_TYPES = Object.values(GEOMETRY_TYPES);

/**
 * @summary デバッグ統計
 * @classdesc
 * <p>エンジン開発用の統計オブジェクトである。<p>
 * <p>NOTE: オブジェクトの振舞いはエンジンの実装に依存するため、一般アプリの開発では使用できない。<p>
 * @memberof mapray
 */
var DebugStats =
/*#__PURE__*/
function () {
  /**
   */
  function DebugStats() {
    _classCallCheck(this, DebugStats);

    /**
     *  @summary リクエスト待ちの DEM 数
     *  @member mapray.DebugStats#num_wait_reqs_dem
     *  @type {number}
     */

    /**
     *  @summary リクエスト待ちの画像数
     *  @member mapray.DebugStats#num_wait_reqs_img
     *  @type {number}
     */

    /**
     *  @summary 描画地表断片数
     *  @member mapray.DebugStats#num_drawing_flakes
     *  @type {number}
     */

    /**
     *  @summary 描画地表断頂点数
     *  @member mapray.DebugStats#num_drawing_flake_vertices
     *  @type {number}
     */

    /**
     *  @summary 地表断片処理 A の数
     *  @member mapray.DebugStats#num_procA_flakes
     *  @type {number}
     */

    /**
     *  @summary 地表断片処理 B の数
     *  @member mapray.DebugStats#num_procB_flakes
     *  @type {number}
     */
    this.clearStats();
  }
  /**
   * 統計値をクリア
   * @package
   */


  _createClass(DebugStats, [{
    key: "clearStats",
    value: function clearStats() {
      this.num_wait_reqs_dem = 0;
      this.num_wait_reqs_img = 0;
      this.num_drawing_flakes = 0;
      this.num_drawing_flake_vertices = 0;
      this.num_procA_flakes = 0;
      this.num_procB_flakes = 0;
    }
    /**
     * @summary 更新が完了したときに呼び出される
     * @abstract
     */

  }, {
    key: "onUpdate",
    value: function onUpdate() {}
  }]);

  return DebugStats;
}();

var trim$1 = stringTrim.trim;
var $parseInt = global_1.parseInt;
var hex = /^[+-]?0[Xx]/;
var FORCED$8 = $parseInt(whitespaces + '08') !== 8 || $parseInt(whitespaces + '0x16') !== 22; // `parseInt` method
// https://tc39.github.io/ecma262/#sec-parseint-string-radix

var numberParseInt = FORCED$8 ? function parseInt(string, radix) {
  var S = trim$1(String(string));
  return $parseInt(S, radix >>> 0 || (hex.test(S) ? 16 : 10));
} : $parseInt;

// https://tc39.github.io/ecma262/#sec-parseint-string-radix

_export({
  global: true,
  forced: parseInt != numberParseInt
}, {
  parseInt: numberParseInt
});

var getOwnPropertyDescriptor$5 = objectGetOwnPropertyDescriptor.f;
var nativeEndsWith = ''.endsWith;
var min$6 = Math.min;
var CORRECT_IS_REGEXP_LOGIC$1 = correctIsRegexpLogic('endsWith'); // https://github.com/zloirock/core-js/pull/702

var MDN_POLYFILL_BUG$1 =  !CORRECT_IS_REGEXP_LOGIC$1 && !!function () {
  var descriptor = getOwnPropertyDescriptor$5(String.prototype, 'endsWith');
  return descriptor && !descriptor.writable;
}(); // `String.prototype.endsWith` method
// https://tc39.github.io/ecma262/#sec-string.prototype.endswith

_export({
  target: 'String',
  proto: true,
  forced: !MDN_POLYFILL_BUG$1 && !CORRECT_IS_REGEXP_LOGIC$1
}, {
  endsWith: function endsWith(searchString
  /* , endPosition = @length */
  ) {
    var that = String(requireObjectCoercible(this));
    notARegexp(searchString);
    var endPosition = arguments.length > 1 ? arguments[1] : undefined;
    var len = toLength(that.length);
    var end = endPosition === undefined ? len : min$6(toLength(endPosition), len);
    var search = String(searchString);
    return nativeEndsWith ? nativeEndsWith.call(that, search, end) : that.slice(end - search.length, end) === search;
  }
});

var MaprayApiError =
/*#__PURE__*/
function (_FetchError) {
  _inherits(MaprayApiError, _FetchError);

  function MaprayApiError(code, message, url, response, cause) {
    var _this;

    _classCallCheck(this, MaprayApiError);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(MaprayApiError).call(this, message + " [" + code + "]", url));

    if (Error.captureStackTrace) {
      Error.captureStackTrace(_assertThisInitialized(_this), MaprayApiError);
    }

    _this.name = "MaprayApiError";
    _this.code = code;
    _this.resonse = response;
    _this.cause = cause;

    if (cause) {
      _this.stack += "\nCaused-By: " + cause.stack;
    }

    return _this;
  }

  return MaprayApiError;
}(FetchError);

var MaprayResource =
/*#__PURE__*/
function (_Resource) {
  _inherits(MaprayResource, _Resource);

  function MaprayResource(api) {
    var _this2;

    _classCallCheck(this, MaprayResource);

    _this2 = _possibleConstructorReturn(this, _getPrototypeOf(MaprayResource).call(this));
    _this2._api = api;
    return _this2;
  }

  _createClass(MaprayResource, [{
    key: "type",
    get: function get() {
      throw new Error("Not Implemented");
    }
  }]);

  return MaprayResource;
}(Resource);
var DatasetResource =
/*#__PURE__*/
function (_MaprayResource) {
  _inherits(DatasetResource, _MaprayResource);

  function DatasetResource(api, datasetId) {
    var _this3;

    _classCallCheck(this, DatasetResource);

    _this3 = _possibleConstructorReturn(this, _getPrototypeOf(DatasetResource).call(this, api));
    _this3._datasetId = datasetId;
    return _this3;
  }

  _createClass(DatasetResource, [{
    key: "load",
    value: function load() {
      return this._api.listFeatures(this._datasetId);
    }
  }, {
    key: "type",
    get: function get() {
      return "Dataset";
    }
  }]);

  return DatasetResource;
}(MaprayResource);
var Dataset3DSceneResource =
/*#__PURE__*/
function (_MaprayResource2) {
  _inherits(Dataset3DSceneResource, _MaprayResource2);

  function Dataset3DSceneResource(api, datasetIds) {
    var _this4;

    _classCallCheck(this, Dataset3DSceneResource);

    _this4 = _possibleConstructorReturn(this, _getPrototypeOf(Dataset3DSceneResource).call(this, api));

    if (!Array.isArray(datasetIds)) {
      datasetIds = [datasetIds];
    }

    _this4._datasetIds = datasetIds;
    return _this4;
  }

  _createClass(Dataset3DSceneResource, [{
    key: "load",
    value: function load() {
      return this._api.get3DDatasetScene(this._datasetIds).then(function (response) {
        return response;
      });
    }
  }, {
    key: "loadSubResourceSupported",
    value: function loadSubResourceSupported() {
      return true;
    }
  }, {
    key: "loadSubResource",
    value: function loadSubResource(subUrl, resourceType) {
      var url = Dom.resolveUrl(this._base_url, subUrl);
      return this._api.fetch(HTTP.METHOD.GET, url);
    }
  }, {
    key: "resolveResourceSupported",
    value: function resolveResourceSupported() {
      return true;
    }
  }, {
    key: "resolveResource",
    value: function resolveResource(subUrl) {
      return new Dataset3DSceneBlobResource(this._api, subUrl, {
        transform: this._transform
      });
    }
  }, {
    key: "type",
    get: function get() {
      return "3DDatasetScene";
    }
  }]);

  return Dataset3DSceneResource;
}(MaprayResource);
var Dataset3DSceneBlobResource =
/*#__PURE__*/
function (_MaprayResource3) {
  _inherits(Dataset3DSceneBlobResource, _MaprayResource3);

  function Dataset3DSceneBlobResource(api, url) {
    var _this5;

    _classCallCheck(this, Dataset3DSceneBlobResource);

    _this5 = _possibleConstructorReturn(this, _getPrototypeOf(Dataset3DSceneBlobResource).call(this, api));
    _this5._url = url;
    var index = url.lastIndexOf("/");
    if (index === -1) throw new Error("invalid url");
    _this5._base_url = _this5._url.substr(0, index + 1);
    return _this5;
  }

  _createClass(Dataset3DSceneBlobResource, [{
    key: "load",
    value: function load() {
      return this._api.fetch(HTTP.METHOD.GET, this._url);
    }
  }, {
    key: "loadSubResourceSupported",
    value: function loadSubResourceSupported() {
      return true;
    }
  }, {
    key: "loadSubResource",
    value: function loadSubResource(subUrl, resourceType) {
      var url = Dom.resolveUrl(this._base_url, subUrl);

      if (resourceType === SceneLoader.ResourceType.BINARY) {
        return this._api.fetch(HTTP.METHOD.GET, url).then(function (response) {
          if (!response.ok) throw new Error(response.statusText);
          return response.arrayBuffer();
        });
      } else if (resourceType === SceneLoader.ResourceType.IMAGE) {
        return this._api.fetch(HTTP.METHOD.GET, url).then(function (response) {
          if (!response.ok) throw new Error(response.statusText);
          return response.blob();
        }).then(Dom.loadImage);
      }

      return this._api.fetch(HTTP.METHOD.GET, subUrl);
    }
  }, {
    key: "type",
    get: function get() {
      return "3DDatasetSceneBlob";
    }
  }]);

  return Dataset3DSceneBlobResource;
}(MaprayResource);
/**
 * MaprayApi
 *
 * @classdesc
 * <p>MaprayApiへアクセスする手段を提供します。</p>
 *
 * @memberof mapray
 * @example
 * const maprayApi = new mapray.MaprayApi({
 *         basePath: "https://api.mapray.com",
 *         version: "v1",
 *         userId: "...",
 *         token: "..."
 * });
 * maprayApi.getDatasets();
 */

var MaprayApi =
/*#__PURE__*/
function (_HTTP) {
  _inherits(MaprayApi, _HTTP);

  /**
   * @param {object} option Option
   * @param {object} option.basePath
   * @param {object} option.version
   * @param {object} option.userId
   * @param {object} option.token
   */
  function MaprayApi() {
    var _this6;

    var option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    _classCallCheck(this, MaprayApi);

    _this6 = _possibleConstructorReturn(this, _getPrototypeOf(MaprayApi).call(this));
    var basePath = option.basePath.endsWith("/") ? option.basePath.slice(0, -1) : option.basePath;
    _this6._option = {
      token: option.token,
      version: option.version,
      basePath: basePath,
      userId: option.userId
    };
    return _this6;
  }

  _createClass(MaprayApi, [{
    key: "getDatasetAsResource",
    value: function getDatasetAsResource(datasetId) {
      return new DatasetResource(this, datasetId);
    }
  }, {
    key: "get3DDatasetAsResource",
    value: function get3DDatasetAsResource(datasetIds) {
      return new Dataset3DSceneResource(this, datasetIds);
    }
    /**
     * List datasets
     */

  }, {
    key: "getDatasets",
    value: function getDatasets() {
      var opt = this._option;
      return this.get("datasets", [opt.userId], null);
    }
    /**
     * Get dataset
     */

  }, {
    key: "getDataset",
    value: function getDataset(datasetId) {
      var opt = this._option;
      return this.get("datasets", [opt.userId, datasetId], null);
    }
    /**
     * create a dataset
     * @param {string} name
     * @param {string} description
     */

  }, {
    key: "createDataset",
    value: function createDataset(name, description) {
      var opt = this._option;
      var body = {
        name: name,
        description: description
      };
      return this.post("datasets", [opt.userId], null, body);
    }
    /**
     * Delete a dataset
     */

  }, {
    key: "deleteDataset",
    value: function deleteDataset(datasetId
    /*, option={ wait: true }*/
    ) {
      var opt = this._option;
      return this["delete"]("datasets", [opt.userId, datasetId]);
    }
    /**
     * List Features
     */

  }, {
    key: "listFeatures",
    value: function listFeatures(datasetId) {
      var opt = this._option;
      return this.get("datasets", [opt.userId, datasetId, "features"]);
    }
  }, {
    key: "insertFeature",
    value: function insertFeature(datasetId, feature) {
      var opt = this._option;
      return this.post("datasets", [opt.userId, datasetId, "features"], null, feature);
    }
  }, {
    key: "updateFeature",
    value: function updateFeature(datasetId, featureId, feature) {
      var opt = this._option;
      return this.put("datasets", [opt.userId, "features", featureId], null, feature);
    }
  }, {
    key: "list3DDatasets",
    value: function list3DDatasets() {
      var opt = this._option;
      return this.get("3ddatasets", [opt.userId]);
    }
  }, {
    key: "create3DDataset",
    value: function create3DDataset(name, description, coordinateSystem) {
      var opt = this._option;
      var body = {
        name: name,
        description: description,
        path: coordinateSystem.path,
        format: coordinateSystem.format,
        srid: coordinateSystem.srid,
        x: coordinateSystem.x,
        y: coordinateSystem.y,
        z: coordinateSystem.z
      };
      return this.post("3ddatasets", [opt.userId], null, body);
    }
  }, {
    key: "update3DDataset",
    value: function update3DDataset(datasetId, name, description, coordinateSystem) {
      var opt = this._option;
      var body = {
        name: name,
        description: description,
        path: coordinateSystem.path,
        format: coordinateSystem.format,
        srid: coordinateSystem.srid,
        x: coordinateSystem.x,
        y: coordinateSystem.y,
        z: coordinateSystem.z
      };
      return this.patch("3ddatasets", [opt.userId, datasetId], null, body);
    }
  }, {
    key: "create3DDatasetUploadUrl",
    value: function create3DDatasetUploadUrl(datasetId) {
      var opt = this._option;
      return this.post("3ddatasets", ["uploads", opt.userId, datasetId], null, {});
    }
  }, {
    key: "get3DDataset",
    value: function get3DDataset(datasetId) {
      var opt = this._option;
      return this.get("3ddatasets", [opt.userId, datasetId], null);
    }
  }, {
    key: "delete3DDataset",
    value: function delete3DDataset(datasetId) {
      var opt = this._option;
      return this["delete"]("3ddatasets", [opt.userId, datasetId]);
    }
  }, {
    key: "get3DDatasetScene",
    value: function get3DDatasetScene(datasetIds) {
      var opt = this._option;
      return this.get("3ddatasets", ["scene", opt.userId], {
        "3ddatasets_ids": Array.isArray(datasetIds) ? datasetIds.join(",") : datasetIds
      }).then(function (response) {
        response.entity_list.forEach(function (entity) {
          var indexStr = entity.index;
          var index = parseInt(indexStr);

          if (index.toString() !== indexStr) {
            throw new Error("Internal Error: ID couldn't be convert to 'number'");
          }

          entity.index = index;
        });
        return response;
      });
    }
    /**
     * @protected
     */

  }, {
    key: "get",
    value: function get(api, args, query) {
      var option = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
      return this.fetchAPI(HTTP.METHOD.GET, api, args, query, null, option);
    }
    /**
     * @protected
     */

  }, {
    key: "post",
    value: function post(api, args, query, body) {
      var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};

      if (typeof body !== "string") {
        body = JSON.stringify(body);
      }

      return this.fetchAPI(HTTP.METHOD.POST, api, args, query, body, option);
    }
    /**
     * @protected
     */

  }, {
    key: "patch",
    value: function patch(api, args, query, body) {
      var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};

      if (typeof body !== "string") {
        body = JSON.stringify(body);
      }

      return this.fetchAPI(HTTP.METHOD.PATCH, api, args, query, body, option);
    }
    /**
     * @protected
     */

  }, {
    key: "put",
    value: function put(api, args, query, body) {
      var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};

      if (typeof body !== "string") {
        body = JSON.stringify(body);
      }

      return this.fetchAPI(HTTP.METHOD.PUT, api, args, query, body, option);
    }
    /**
     * @protected
     */

  }, {
    key: "delete",
    value: function _delete(api, args, query) {
      var option = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
      return this.fetchAPI(HTTP.METHOD.DELETE, api, args, query, null, option);
    }
    /**
     * @protected
     */

  }, {
    key: "fetchAPI",
    value: function fetchAPI(method, api, args, query, body) {
      var option = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
      var opt = this._option;
      var url = opt.basePath + "/" + api + "/" + opt.version + (args.length > 0 ? "/" + args.join("/") : ""); // console.log( "MaprayAPI: " + method + " " + api + " (" + args.join("/") + ")" );

      console.log("MaprayAPI: " + method + " " + url + (query ? "?" + JSON.stringify(query) : ""));
      return this.fetch(method, url, query, body, option);
    }
    /**
     * @protected
     */

  }, {
    key: "fetch",
    value: function fetch(method, url, query, body) {
      var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
      var opt = this._option;
      var headers = option.headers || (option.headers = {});
      headers["x-api-key"] = opt.token;
      return HTTP.fetch(method, url, query, body, option).then(function (response) {
        if (response.status === HTTP.RESPONSE_STATUS.NO_CONTENT) {
          return;
        }

        var mimeType = response.headers.get(HTTP.CONTENT_TYPE);

        if (HTTP.isJson(mimeType)) {
          return response.json();
        } else {
          console.log("Unsupported Mime Type: " + mimeType);
          return response;
        }
      })["catch"](function (error) {
        if (error.name === "FetchError" && error.response) {
          return error.response.json()["catch"](function (additionalError) {
            // Couldn't get additional info of the error.
            // throw original error.
            throw new MaprayApiError(-1, "Failed to fetch", url, null, error);
          }).then(function (errorObject) {
            throw new MaprayApiError(errorObject.code, errorObject.error, url, error.response, error);
          });
        } else {
          throw new MaprayApiError(-1, "Failed to fetch", url, null, error);
        }
      });
    }
  }]);

  return MaprayApi;
}(HTTP); // MaprayApi.BASE_PATH = "https://api.mapray.com";
// MaprayApi.BASE_PATH = "https://cloud.mapray.com";


MaprayApi.CLOUD_BASE_PATH = "http://localhost:8080"; // @ToDo remove this

/**
 * Mapray 関連の機能全体が含まれる名前空間
 * @namespace mapray
 */

var mapray = {
  animation: animation,
  Viewer: Viewer,
  Camera: Camera,
  GeoMath: GeoMath,
  GeoPoint: GeoPoint,
  Orientation: Orientation,
  Ray: Ray,
  AltitudeMode: AltitudeMode,
  CredentialMode: CredentialMode,
  Layer: Layer,
  LayerCollection: LayerCollection,
  DemProvider: DemProvider,
  StandardDemProvider: StandardDemProvider,
  CloudDemProvider: CloudDemProvider,
  ImageProvider: ImageProvider,
  RenderCallback: RenderCallback,
  StandardImageProvider: StandardImageProvider,
  Scene: Scene,
  Entity: Entity,
  MarkerLineEntity: MarkerLineEntity,
  TextEntity: TextEntity,
  ModelEntity: ModelEntity,
  PolygonEntity: PolygonEntity,
  PinEntity: PinEntity,
  ImageIconEntity: ImageIconEntity,
  SceneLoader: SceneLoader,
  GeoJSONLoader: GeoJSONLoader,
  URLResource: URLResource,
  MaprayApi: MaprayApi,
  DebugStats: DebugStats,
  LogoController: LogoController,
  // マウス・Attribution開発
  AttributionController: AttributionController // マウス・Attribution開発

}; // 互換関数を登録

{
  /* requestAnimationFrame 互換関数
   * @param {function} callback
   * @return {number} requestID
   * @see https://developer.mozilla.org/ja/docs/Web/API/Window/requestAnimationFrame
   */
  window.maprayRequestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame;
  /* cancelAnimationFrame 互換関数
   * @param {number} requestID
   * @see https://developer.mozilla.org/ja/docs/Web/API/window/cancelAnimationFrame
   */

  window.maprayCancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame;
  /* Performance.now 互換関数
   * @see https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
   * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now
   */

  var perf = window.performance;
  var now = perf && (perf.now || perf.mozNow || perf.msNow || perf.oNow || perf.webkitNow);
  var date = new Date();
  window.maprayNow = now ? function () {
    return now.call(perf);
  } : function () {
    return date.getTime();
  };
  /* Math.log2 互換関数
   * @function Math.maprayLog2
   * @see https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/log2
   */

  Math.maprayLog2 = Math.log2 || function (x) {
    return 1.4426950408889634074 * Math.log(x);
  };
}

export default mapray;
//# sourceMappingURL=mapray.js.map