import {
  Draw_default,
  getCoordinate,
  getTraceTargetUpdate,
  getTraceTargets
} from "./chunk-MEQVYVYE.js";
import {
  Select_default
} from "./chunk-6DXBPPKF.js";
import {
  RBush_default,
  Vector_default as Vector_default2
} from "./chunk-PD2E5XZ4.js";
import {
  VectorEventType_default
} from "./chunk-V7WRBSQ6.js";
import "./chunk-W7BDJOQY.js";
import "./chunk-7JXPN73Q.js";
import {
  Feature_default
} from "./chunk-E53S5GN6.js";
import {
  Vector_default
} from "./chunk-T3TT2KJN.js";
import "./chunk-HM3IY3H4.js";
import "./chunk-JFXZSSOM.js";
import "./chunk-ZUI5NXIU.js";
import {
  DoubleClickZoom_default,
  DragBox_default,
  DragPan_default,
  DragRotate_default,
  DragZoom_default,
  KeyboardPan_default,
  KeyboardZoom_default,
  MouseWheelZoom_default,
  PinchRotate_default,
  PinchZoom_default,
  Pointer_default,
  defaults
} from "./chunk-RTVPCGIJ.js";
import {
  Interaction_default,
  Property_default
} from "./chunk-MSWSBYBR.js";
import {
  MapBrowserEventType_default,
  altKeyOnly,
  always,
  mouseOnly,
  never,
  primaryAction,
  shiftKeyOnly,
  singleClick
} from "./chunk-QCJTGAWF.js";
import {
  CollectionEventType_default,
  Collection_default
} from "./chunk-M5TTSD4C.js";
import "./chunk-ZCRXKB7J.js";
import "./chunk-RW3V7S4F.js";
import {
  createEditingStyle
} from "./chunk-PAB2HIXK.js";
import "./chunk-I6K7MRGV.js";
import "./chunk-PGWX4545.js";
import "./chunk-AYBYZSAV.js";
import "./chunk-YLJGUH5Z.js";
import {
  Point_default,
  fromCircle,
  fromExtent
} from "./chunk-AZGMK675.js";
import {
  MapEventType_default
} from "./chunk-BHVDQB66.js";
import "./chunk-6EWLK2BW.js";
import "./chunk-6Y7C6NBJ.js";
import "./chunk-SHUBVYN4.js";
import "./chunk-FM44FOIC.js";
import "./chunk-LMC3RO5P.js";
import {
  getIntersectionPoint
} from "./chunk-X52LGBOS.js";
import "./chunk-QFCIXVZ3.js";
import {
  closestOnCircle,
  closestOnSegment,
  distance,
  equals as equals2,
  fromUserCoordinate,
  fromUserExtent,
  get,
  getUserProjection,
  squaredDistance,
  squaredDistanceToSegment,
  toUserCoordinate,
  toUserExtent
} from "./chunk-A3RXLHYB.js";
import "./chunk-ZLPTRF2L.js";
import {
  toFixed
} from "./chunk-54BTDBAD.js";
import "./chunk-UPTVWZ45.js";
import "./chunk-5XHD7RSF.js";
import {
  getUid
} from "./chunk-Q5ZULJHM.js";
import {
  Event_default,
  listen,
  unlistenByKey
} from "./chunk-NGFXCWUF.js";
import {
  EventType_default,
  FALSE,
  TRUE,
  equals
} from "./chunk-K25ZO44T.js";
import {
  boundingExtent,
  buffer,
  containsCoordinate,
  createEmpty,
  createOrUpdateFromCoordinate,
  getArea,
  intersects
} from "./chunk-SRXHWJOY.js";
import {
  clear
} from "./chunk-5RHQVMYD.js";
import "./chunk-DC5AMYBS.js";

// node_modules/ol/interaction/DblClickDragZoom.js
var DblClickDragZoom = class extends Interaction_default {
  /**
   * @param {Options} [opt_options] Options.
   */
  constructor(opt_options) {
    const options = opt_options ? opt_options : {};
    super(
      /** @type {import("./Interaction.js").InteractionOptions} */
      options
    );
    if (options.stopDown) {
      this.stopDown = options.stopDown;
    }
    this.scaleDeltaByPixel_ = options.delta ? options.delta : 0.01;
    this.duration_ = options.duration !== void 0 ? options.duration : 250;
    this.handlingDownUpSequence_ = false;
    this.handlingDoubleDownSequence_ = false;
    this.doubleTapTimeoutId_ = void 0;
    this.trackedPointers_ = {};
    this.down_ = null;
    this.targetPointers = [];
  }
  /**
   * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent  map browser event} and may call into
   * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are
   * detected.
   * @param {import("../MapBrowserEvent.js").default<PointerEvent>} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @api
   * @override
   */
  handleEvent(mapBrowserEvent) {
    if (!mapBrowserEvent.originalEvent) {
      return true;
    }
    let stopEvent = false;
    this.updateTrackedPointers_(mapBrowserEvent);
    if (this.handlingDownUpSequence_) {
      if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERDRAG) {
        this.handleDragEvent(mapBrowserEvent);
        mapBrowserEvent.originalEvent.preventDefault();
      } else if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERUP) {
        const handledUp = this.handleUpEvent(mapBrowserEvent);
        this.handlingDownUpSequence_ = handledUp;
      }
    } else {
      if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERDOWN) {
        if (this.handlingDoubleDownSequence_) {
          this.handlingDoubleDownSequence_ = false;
          const handled = this.handleDownEvent(mapBrowserEvent);
          this.handlingDownUpSequence_ = handled;
          stopEvent = this.stopDown(handled);
        } else {
          stopEvent = this.stopDown(false);
          this.waitForDblTap_();
        }
      }
    }
    return !stopEvent;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default<PointerEvent>} mapBrowserEvent Event.
   */
  handleDragEvent(mapBrowserEvent) {
    let scaleDelta = 1;
    const touch0 = this.targetPointers[0];
    const touch1 = this.down_;
    const distance2 = touch0.clientY - touch1.clientY;
    if (this.lastDistance_ !== void 0) {
      scaleDelta = 1 - (this.lastDistance_ - distance2) * this.scaleDeltaByPixel_;
    }
    this.lastDistance_ = distance2;
    if (scaleDelta != 1) {
      this.lastScaleDelta_ = scaleDelta;
    }
    const map = mapBrowserEvent.map;
    const view = map.getView();
    map.render();
    view.adjustResolutionInternal(scaleDelta);
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default<PointerEvent>} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   */
  handleDownEvent(mapBrowserEvent) {
    if (this.targetPointers.length == 1) {
      const map = mapBrowserEvent.map;
      this.anchor_ = null;
      this.lastDistance_ = void 0;
      this.lastScaleDelta_ = 1;
      this.down_ = mapBrowserEvent.originalEvent;
      if (!this.handlingDownUpSequence_) {
        map.getView().beginInteraction();
      }
      return true;
    }
    return false;
  }
  /**
   * Handle pointer up events zooming out.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   */
  handleUpEvent(mapBrowserEvent) {
    if (this.targetPointers.length == 0) {
      const map = mapBrowserEvent.map;
      const view = map.getView();
      const direction = this.lastScaleDelta_ > 1 ? 1 : -1;
      view.endInteraction(this.duration_, direction);
      this.handlingDownUpSequence_ = false;
      this.handlingDoubleDownSequence_ = false;
      return false;
    }
    return true;
  }
  /**
   * This function is used to determine if "down" events should be propagated
   * to other interactions or should be stopped.
   * @param {boolean} handled Was the event handled by the interaction?
   * @return {boolean} Should the `down` event be stopped?
   */
  stopDown(handled) {
    return handled;
  }
  /**
   * @param {import("../MapBrowserEvent.js").default<PointerEvent>} mapBrowserEvent Event.
   * @private
   */
  updateTrackedPointers_(mapBrowserEvent) {
    if (isPointerDraggingEvent(mapBrowserEvent)) {
      const event = mapBrowserEvent.originalEvent;
      const id = event.pointerId.toString();
      if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERUP) {
        delete this.trackedPointers_[id];
      } else if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERDOWN) {
        this.trackedPointers_[id] = event;
      } else if (id in this.trackedPointers_) {
        this.trackedPointers_[id] = event;
      }
      this.targetPointers = Object.values(this.trackedPointers_);
    }
  }
  /**
   * Wait the second double finger tap.
   * @private
   */
  waitForDblTap_() {
    if (this.doubleTapTimeoutId_ !== void 0) {
      clearTimeout(this.doubleTapTimeoutId_);
      this.doubleTapTimeoutId_ = void 0;
    } else {
      this.handlingDoubleDownSequence_ = true;
      this.doubleTapTimeoutId_ = setTimeout(
        this.endInteraction_.bind(this),
        250
      );
    }
  }
  /**
   * @private
   */
  endInteraction_() {
    this.handlingDoubleDownSequence_ = false;
    this.doubleTapTimeoutId_ = void 0;
  }
};
function isPointerDraggingEvent(mapBrowserEvent) {
  const type = mapBrowserEvent.type;
  return type === MapBrowserEventType_default.POINTERDOWN || type === MapBrowserEventType_default.POINTERDRAG || type === MapBrowserEventType_default.POINTERUP;
}
var DblClickDragZoom_default = DblClickDragZoom;

// node_modules/ol/interaction/DragAndDrop.js
var DragAndDropEventType = {
  /**
   * Triggered when features are added
   * @event DragAndDropEvent#addfeatures
   * @api
   */
  ADD_FEATURES: "addfeatures"
};
var DragAndDropEvent = class extends Event_default {
  /**
   * @param {DragAndDropEventType} type Type.
   * @param {File} file File.
   * @param {Array<import("../Feature.js").default>} [features] Features.
   * @param {import("../proj/Projection.js").default} [projection] Projection.
   */
  constructor(type, file, features, projection) {
    super(type);
    this.features = features;
    this.file = file;
    this.projection = projection;
  }
};
var DragAndDrop = class extends Interaction_default {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options) {
    options = options ? options : {};
    super({
      handleEvent: TRUE
    });
    this.on;
    this.once;
    this.un;
    this.readAsBuffer_ = false;
    this.formats_ = [];
    const formatConstructors = options.formatConstructors ? options.formatConstructors : [];
    for (let i = 0, ii = formatConstructors.length; i < ii; ++i) {
      let format = formatConstructors[i];
      if (typeof format === "function") {
        format = new format();
      }
      this.formats_.push(format);
      this.readAsBuffer_ = this.readAsBuffer_ || format.getType() === "arraybuffer";
    }
    this.projection_ = options.projection ? get(options.projection) : null;
    this.dropListenKeys_ = null;
    this.source_ = options.source || null;
    this.target = options.target ? options.target : null;
  }
  /**
   * @param {File} file File.
   * @param {Event} event Load event.
   * @private
   */
  handleResult_(file, event) {
    const result = event.target.result;
    const map = this.getMap();
    let projection = this.projection_;
    if (!projection) {
      projection = getUserProjection();
      if (!projection) {
        const view = map.getView();
        projection = view.getProjection();
      }
    }
    let text;
    const formats = this.formats_;
    for (let i = 0, ii = formats.length; i < ii; ++i) {
      const format = formats[i];
      let input = result;
      if (this.readAsBuffer_ && format.getType() !== "arraybuffer") {
        if (text === void 0) {
          text = new TextDecoder().decode(result);
        }
        input = text;
      }
      const features = this.tryReadFeatures_(format, input, {
        featureProjection: projection
      });
      if (features && features.length > 0) {
        if (this.source_) {
          this.source_.clear();
          this.source_.addFeatures(features);
        }
        this.dispatchEvent(
          new DragAndDropEvent(
            DragAndDropEventType.ADD_FEATURES,
            file,
            features,
            projection
          )
        );
        break;
      }
    }
  }
  /**
   * @private
   */
  registerListeners_() {
    const map = this.getMap();
    if (map) {
      const dropArea = this.target ? this.target : map.getViewport();
      this.dropListenKeys_ = [
        listen(dropArea, EventType_default.DROP, this.handleDrop, this),
        listen(dropArea, EventType_default.DRAGENTER, this.handleStop, this),
        listen(dropArea, EventType_default.DRAGOVER, this.handleStop, this),
        listen(dropArea, EventType_default.DROP, this.handleStop, this)
      ];
    }
  }
  /**
   * Activate or deactivate the interaction.
   * @param {boolean} active Active.
   * @observable
   * @api
   * @override
   */
  setActive(active) {
    if (!this.getActive() && active) {
      this.registerListeners_();
    }
    if (this.getActive() && !active) {
      this.unregisterListeners_();
    }
    super.setActive(active);
  }
  /**
   * Remove the interaction from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../Map.js").default} map Map.
   * @override
   */
  setMap(map) {
    this.unregisterListeners_();
    super.setMap(map);
    if (this.getActive()) {
      this.registerListeners_();
    }
  }
  /**
   * @param {import("../format/Feature.js").default} format Format.
   * @param {string} text Text.
   * @param {import("../format/Feature.js").ReadOptions} options Read options.
   * @private
   * @return {Array<import("../Feature.js").default>} Features.
   */
  tryReadFeatures_(format, text, options) {
    try {
      return (
        /** @type {Array<import("../Feature.js").default>} */
        format.readFeatures(text, options)
      );
    } catch {
      return null;
    }
  }
  /**
   * @private
   */
  unregisterListeners_() {
    if (this.dropListenKeys_) {
      this.dropListenKeys_.forEach(unlistenByKey);
      this.dropListenKeys_ = null;
    }
  }
  /**
   * @param {DragEvent} event Event.
   */
  handleDrop(event) {
    const files = event.dataTransfer.files;
    for (let i = 0, ii = files.length; i < ii; ++i) {
      const file = files.item(i);
      const reader = new FileReader();
      reader.addEventListener(
        EventType_default.LOAD,
        this.handleResult_.bind(this, file)
      );
      if (this.readAsBuffer_) {
        reader.readAsArrayBuffer(file);
      } else {
        reader.readAsText(file);
      }
    }
  }
  /**
   * @param {DragEvent} event Event.
   */
  handleStop(event) {
    event.stopPropagation();
    event.preventDefault();
    event.dataTransfer.dropEffect = "copy";
  }
};
var DragAndDrop_default = DragAndDrop;

// node_modules/ol/interaction/DragRotateAndZoom.js
var DragRotateAndZoom = class extends Pointer_default {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options) {
    options = options ? options : {};
    super(
      /** @type {import("./Pointer.js").Options} */
      options
    );
    this.condition_ = options.condition ? options.condition : shiftKeyOnly;
    this.lastAngle_ = void 0;
    this.lastMagnitude_ = void 0;
    this.lastScaleDelta_ = 0;
    this.duration_ = options.duration !== void 0 ? options.duration : 400;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @override
   */
  handleDragEvent(mapBrowserEvent) {
    if (!mouseOnly(mapBrowserEvent)) {
      return;
    }
    const map = mapBrowserEvent.map;
    const size = map.getSize();
    const offset = mapBrowserEvent.pixel;
    const deltaX = offset[0] - size[0] / 2;
    const deltaY = size[1] / 2 - offset[1];
    const theta = Math.atan2(deltaY, deltaX);
    const magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
    const view = map.getView();
    if (this.lastAngle_ !== void 0) {
      const angleDelta = this.lastAngle_ - theta;
      view.adjustRotationInternal(angleDelta);
    }
    this.lastAngle_ = theta;
    if (this.lastMagnitude_ !== void 0) {
      view.adjustResolutionInternal(this.lastMagnitude_ / magnitude);
    }
    if (this.lastMagnitude_ !== void 0) {
      this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;
    }
    this.lastMagnitude_ = magnitude;
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(mapBrowserEvent) {
    if (!mouseOnly(mapBrowserEvent)) {
      return true;
    }
    const map = mapBrowserEvent.map;
    const view = map.getView();
    const direction = this.lastScaleDelta_ > 1 ? 1 : -1;
    view.endInteraction(this.duration_, direction);
    this.lastScaleDelta_ = 0;
    return false;
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(mapBrowserEvent) {
    if (!mouseOnly(mapBrowserEvent)) {
      return false;
    }
    if (this.condition_(mapBrowserEvent)) {
      mapBrowserEvent.map.getView().beginInteraction();
      this.lastAngle_ = void 0;
      this.lastMagnitude_ = void 0;
      return true;
    }
    return false;
  }
};
var DragRotateAndZoom_default = DragRotateAndZoom;

// node_modules/ol/interaction/Extent.js
var ExtentEventType = {
  /**
   * Triggered after the extent is changed
   * @event ExtentEvent#extentchanged
   * @api
   */
  EXTENTCHANGED: "extentchanged"
};
var ExtentEvent = class extends Event_default {
  /**
   * @param {import("../extent.js").Extent} extent the new extent
   */
  constructor(extent) {
    super(ExtentEventType.EXTENTCHANGED);
    this.extent = extent;
  }
};
var Extent = class extends Pointer_default {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options) {
    options = options || {};
    super(
      /** @type {import("./Pointer.js").Options} */
      options
    );
    this.on;
    this.once;
    this.un;
    this.condition_ = options.condition ? options.condition : always;
    this.createCondition_ = options.createCondition || this.condition_;
    this.drag_ = options.drag || false;
    this.extent_ = null;
    this.pointerHandler_ = null;
    this.pixelTolerance_ = options.pixelTolerance !== void 0 ? options.pixelTolerance : 10;
    this.snappedToVertex_ = false;
    this.extentFeature_ = null;
    this.vertexFeature_ = null;
    if (!options) {
      options = {};
    }
    this.extentOverlay_ = new Vector_default({
      source: new Vector_default2({
        useSpatialIndex: false,
        wrapX: !!options.wrapX
      }),
      style: options.boxStyle ? options.boxStyle : getDefaultExtentStyleFunction(),
      updateWhileAnimating: true,
      updateWhileInteracting: true
    });
    this.vertexOverlay_ = new Vector_default({
      source: new Vector_default2({
        useSpatialIndex: false,
        wrapX: !!options.wrapX
      }),
      style: options.pointerStyle ? options.pointerStyle : getDefaultPointerStyleFunction(),
      updateWhileAnimating: true,
      updateWhileInteracting: true
    });
    if (options.extent) {
      this.setExtent(options.extent);
    }
  }
  /**
   * @param {import("../pixel.js").Pixel} pixel cursor location
   * @param {import("../Map.js").default} map map
   * @return {import("../coordinate.js").Coordinate|null} snapped vertex on extent
   * @private
   */
  snapToVertex_(pixel, map) {
    const pixelCoordinate = map.getCoordinateFromPixelInternal(pixel);
    const sortByDistance = function(a, b) {
      return squaredDistanceToSegment(pixelCoordinate, a) - squaredDistanceToSegment(pixelCoordinate, b);
    };
    const extent = this.getExtentInternal();
    if (extent) {
      const segments = getSegments(extent);
      segments.sort(sortByDistance);
      const closestSegment = segments[0];
      let vertex = closestOnSegment(pixelCoordinate, closestSegment);
      const vertexPixel = map.getPixelFromCoordinateInternal(vertex);
      if (distance(pixel, vertexPixel) <= this.pixelTolerance_) {
        const pixel1 = map.getPixelFromCoordinateInternal(closestSegment[0]);
        const pixel2 = map.getPixelFromCoordinateInternal(closestSegment[1]);
        const squaredDist1 = squaredDistance(vertexPixel, pixel1);
        const squaredDist2 = squaredDistance(vertexPixel, pixel2);
        const dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
        this.snappedToVertex_ = dist <= this.pixelTolerance_;
        if (this.snappedToVertex_) {
          vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
        }
        return vertex;
      }
    }
    return null;
  }
  /**
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent pointer move event
   * @return {boolean} The event was handled.
   * @private
   */
  handlePointerMove_(mapBrowserEvent) {
    const pixel = mapBrowserEvent.pixel;
    const map = mapBrowserEvent.map;
    const draggable = this.drag_ && containsCoordinate(this.extent_, mapBrowserEvent.coordinate);
    let vertex = this.snapToVertex_(pixel, map);
    if (!vertex && this.createCondition_(mapBrowserEvent) && !draggable) {
      vertex = map.getCoordinateFromPixelInternal(pixel);
    }
    if (draggable && !vertex) {
      this.getMap().getViewport().classList.add("ol-grab");
    } else {
      this.getMap().getViewport().classList.remove("ol-grab");
    }
    if (vertex) {
      this.updatePointerFeature_(vertex);
      return true;
    }
    this.noVertexFeature_();
    return false;
  }
  /**
   * @param {import("../extent.js").Extent} extent extent
   * @return {Feature} extent as featrue
   * @private
   */
  createOrUpdateExtentFeature_(extent) {
    let extentFeature = this.extentFeature_;
    if (!extentFeature) {
      if (!extent) {
        extentFeature = new Feature_default({});
      } else {
        extentFeature = new Feature_default(fromExtent(extent));
      }
      this.extentFeature_ = extentFeature;
      this.extentOverlay_.getSource().addFeature(extentFeature);
    } else {
      if (!extent) {
        extentFeature.setGeometry(void 0);
      } else {
        extentFeature.setGeometry(fromExtent(extent));
      }
    }
    return extentFeature;
  }
  /**
   * @param {import("../coordinate.js").Coordinate} vertex location of feature
   * @param {boolean} [createIfNotExists] create the feature if it does not exist
   * @return {Feature} vertex as feature
   * @private
   */
  updatePointerFeature_(vertex, createIfNotExists = true) {
    let vertexFeature = this.vertexFeature_;
    if (createIfNotExists && !vertexFeature) {
      vertexFeature = new Feature_default(new Point_default(vertex));
      this.vertexFeature_ = vertexFeature;
      this.vertexOverlay_.getSource().addFeature(vertexFeature);
    }
    if (vertexFeature) {
      const geometry = vertexFeature.getGeometry();
      geometry.setCoordinates(vertex);
    }
    return vertexFeature;
  }
  /**
   * Remove the vertex feature if it exists.
   * @private
   */
  noVertexFeature_() {
    if (this.vertexFeature_) {
      this.vertexOverlay_.getSource().removeFeature(this.vertexFeature_);
      this.vertexFeature_ = null;
    }
  }
  /**
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @override
   */
  handleEvent(mapBrowserEvent) {
    if (!mapBrowserEvent.originalEvent || !this.condition_(mapBrowserEvent)) {
      this.noVertexFeature_();
      return true;
    }
    let handled = this.handlingDownUpSequence;
    if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERMOVE && !this.handlingDownUpSequence) {
      handled = this.handlePointerMove_(mapBrowserEvent);
    }
    super.handleEvent(mapBrowserEvent);
    return !handled;
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(mapBrowserEvent) {
    const pixel = mapBrowserEvent.pixel;
    const map = mapBrowserEvent.map;
    const extent = this.getExtentInternal();
    let vertex = this.snapToVertex_(pixel, map);
    const getOpposingPoint = function(point) {
      let x_ = null;
      let y_ = null;
      if (point[0] == extent[0]) {
        x_ = extent[2];
      } else if (point[0] == extent[2]) {
        x_ = extent[0];
      }
      if (point[1] == extent[1]) {
        y_ = extent[3];
      } else if (point[1] == extent[3]) {
        y_ = extent[1];
      }
      if (x_ !== null && y_ !== null) {
        return [x_, y_];
      }
      return null;
    };
    if (vertex && extent) {
      const x = vertex[0] == extent[0] || vertex[0] == extent[2] ? vertex[0] : null;
      const y = vertex[1] == extent[1] || vertex[1] == extent[3] ? vertex[1] : null;
      if (x !== null && y !== null) {
        this.pointerHandler_ = getPointHandler(getOpposingPoint(vertex));
      } else if (x !== null) {
        this.pointerHandler_ = getEdgeHandler(
          getOpposingPoint([x, extent[1]]),
          getOpposingPoint([x, extent[3]])
        );
      } else if (y !== null) {
        this.pointerHandler_ = getEdgeHandler(
          getOpposingPoint([extent[0], y]),
          getOpposingPoint([extent[2], y])
        );
      }
    } else {
      vertex = map.getCoordinateFromPixelInternal(pixel);
      let drag = false;
      if (this.drag_) {
        if (containsCoordinate(extent, vertex)) {
          this.pointerHandler_ = getDragHandler(extent, vertex);
          drag = true;
        }
      }
      if (!drag && this.createCondition_(mapBrowserEvent)) {
        this.setExtent([vertex[0], vertex[1], vertex[0], vertex[1]]);
        this.pointerHandler_ = getPointHandler(vertex);
      }
    }
    return !!this.pointerHandler_;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @override
   */
  handleDragEvent(mapBrowserEvent) {
    if (this.pointerHandler_) {
      const pixelCoordinate = mapBrowserEvent.coordinate;
      this.setExtent(this.pointerHandler_(pixelCoordinate));
      this.updatePointerFeature_(pixelCoordinate, false);
    }
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(mapBrowserEvent) {
    this.pointerHandler_ = null;
    const extent = this.getExtentInternal();
    if (!extent || getArea(extent) === 0) {
      this.setExtent(null);
    }
    return false;
  }
  /**
   * Remove the interaction from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../Map.js").default} map Map.
   * @override
   */
  setMap(map) {
    this.extentOverlay_.setMap(map);
    this.vertexOverlay_.setMap(map);
    super.setMap(map);
  }
  /**
   * Returns the current drawn extent in the view projection (or user projection if set)
   *
   * @return {import("../extent.js").Extent} Drawn extent in the view projection.
   * @api
   */
  getExtent() {
    return toUserExtent(
      this.getExtentInternal(),
      this.getMap().getView().getProjection()
    );
  }
  /**
   * Returns the current drawn extent in the view projection
   *
   * @return {import("../extent.js").Extent} Drawn extent in the view projection.
   * @api
   * @deprecated Use {@link module:ol/interaction/Extent~Extent#getExtent} instead.
   */
  getExtentInternal() {
    return this.extent_;
  }
  /**
   * Manually sets the drawn extent, using the view projection.
   *
   * @param {import("../extent.js").Extent} extent Extent
   * @api
   */
  setExtent(extent) {
    this.extent_ = extent ? extent : null;
    this.createOrUpdateExtentFeature_(extent);
    this.dispatchEvent(new ExtentEvent(this.extent_));
  }
};
function getDefaultExtentStyleFunction() {
  const style = createEditingStyle();
  return function(feature, resolution) {
    return style["Polygon"];
  };
}
function getDefaultPointerStyleFunction() {
  const style = createEditingStyle();
  return function(feature, resolution) {
    return style["Point"];
  };
}
function getPointHandler(fixedPoint) {
  return function(point) {
    return boundingExtent([fixedPoint, point]);
  };
}
function getEdgeHandler(fixedP1, fixedP2) {
  if (fixedP1[0] == fixedP2[0]) {
    return function(point) {
      return boundingExtent([fixedP1, [point[0], fixedP2[1]]]);
    };
  }
  if (fixedP1[1] == fixedP2[1]) {
    return function(point) {
      return boundingExtent([fixedP1, [fixedP2[0], point[1]]]);
    };
  }
  return null;
}
function getDragHandler(extent, vertex) {
  return function(point) {
    const deltaX = point[0] - vertex[0];
    const deltaY = point[1] - vertex[1];
    return [
      extent[0] + deltaX,
      extent[1] + deltaY,
      extent[2] + deltaX,
      extent[3] + deltaY
    ];
  };
}
function getSegments(extent) {
  return [
    [
      [extent[0], extent[1]],
      [extent[0], extent[3]]
    ],
    [
      [extent[0], extent[3]],
      [extent[2], extent[3]]
    ],
    [
      [extent[2], extent[3]],
      [extent[2], extent[1]]
    ],
    [
      [extent[2], extent[1]],
      [extent[0], extent[1]]
    ]
  ];
}
var Extent_default = Extent;

// node_modules/ol/interaction/Link.js
function to5(number) {
  return toFixed(number, 5);
}
function readNumber(string) {
  return parseFloat(string);
}
function writeNumber(number) {
  return to5(number).toString();
}
function differentNumber(a, b) {
  if (isNaN(a)) {
    return false;
  }
  return a !== readNumber(writeNumber(b));
}
function differentArray(a, b) {
  return differentNumber(a[0], b[0]) || differentNumber(a[1], b[1]);
}
var Link = class extends Interaction_default {
  /**
   * @param {Options} [options] Link options.
   */
  constructor(options) {
    super();
    options = Object.assign(
      {
        animate: true,
        params: ["x", "y", "z", "r", "l"],
        replace: false,
        prefix: ""
      },
      options || {}
    );
    let animationOptions;
    if (options.animate === true) {
      animationOptions = { duration: 250 };
    } else if (!options.animate) {
      animationOptions = null;
    } else {
      animationOptions = options.animate;
    }
    this.animationOptions_ = animationOptions;
    this.params_ = options.params.reduce((acc, value) => {
      acc[value] = true;
      return acc;
    }, {});
    this.replace_ = options.replace;
    this.prefix_ = options.prefix;
    this.listenerKeys_ = [];
    this.initial_ = true;
    this.updateState_ = this.updateState_.bind(this);
    this.trackedCallbacks_ = {};
    this.trackedValues_ = {};
  }
  /**
   * @private
   * @param {string} name A parameter name.
   * @return {string} A name with the prefix applied.
   */
  getParamName_(name) {
    if (!this.prefix_) {
      return name;
    }
    return this.prefix_ + name;
  }
  /**
   * @private
   * @param {URLSearchParams} params The search params.
   * @param {string} name The unprefixed parameter name.
   * @return {string|null} The parameter value.
   */
  get_(params, name) {
    return params.get(this.getParamName_(name));
  }
  /**
   * @private
   * @param {URLSearchParams} params The search params.
   * @param {string} name The unprefixed parameter name.
   * @param {string} value The param value.
   */
  set_(params, name, value) {
    if (!(name in this.params_)) {
      return;
    }
    params.set(this.getParamName_(name), value);
  }
  /**
   * @private
   * @param {URLSearchParams} params The search params.
   * @param {string} name The unprefixed parameter name.
   */
  delete_(params, name) {
    if (!(name in this.params_)) {
      return;
    }
    params.delete(this.getParamName_(name));
  }
  /**
   * @param {import("../Map.js").default|null} map Map.
   * @override
   */
  setMap(map) {
    const oldMap = this.getMap();
    super.setMap(map);
    if (map === oldMap) {
      return;
    }
    if (oldMap) {
      this.unregisterListeners_(oldMap);
    }
    if (map) {
      this.initial_ = true;
      this.updateState_();
      this.registerListeners_(map);
    }
  }
  /**
   * @param {import("../Map.js").default} map Map.
   * @private
   */
  registerListeners_(map) {
    this.listenerKeys_.push(
      listen(map, MapEventType_default.MOVEEND, this.updateUrl_, this),
      listen(map.getLayerGroup(), EventType_default.CHANGE, this.updateUrl_, this),
      listen(map, "change:layergroup", this.handleChangeLayerGroup_, this)
    );
    if (!this.replace_) {
      addEventListener("popstate", this.updateState_);
    }
  }
  /**
   * @param {import("../Map.js").default} map Map.
   * @private
   */
  unregisterListeners_(map) {
    for (let i = 0, ii = this.listenerKeys_.length; i < ii; ++i) {
      unlistenByKey(this.listenerKeys_[i]);
    }
    this.listenerKeys_.length = 0;
    if (!this.replace_) {
      removeEventListener("popstate", this.updateState_);
    }
    const url = new URL(window.location.href);
    const params = url.searchParams;
    this.delete_(params, "x");
    this.delete_(params, "y");
    this.delete_(params, "z");
    this.delete_(params, "r");
    this.delete_(params, "l");
    window.history.replaceState(null, "", url);
  }
  /**
   * @private
   */
  handleChangeLayerGroup_() {
    const map = this.getMap();
    if (!map) {
      return;
    }
    this.unregisterListeners_(map);
    this.registerListeners_(map);
    this.initial_ = true;
    this.updateUrl_();
  }
  /**
   * @private
   */
  updateState_() {
    const url = new URL(window.location.href);
    const params = url.searchParams;
    for (const key in this.trackedCallbacks_) {
      const value = params.get(key);
      if (key in this.trackedCallbacks_ && value !== this.trackedValues_[key]) {
        this.trackedValues_[key] = value;
        this.trackedCallbacks_[key](value);
      }
    }
    const map = this.getMap();
    if (!map) {
      return;
    }
    const view = map.getView();
    if (!view) {
      return;
    }
    let updateView = false;
    const viewProperties = {};
    const zoom = readNumber(this.get_(params, "z"));
    if ("z" in this.params_ && differentNumber(zoom, view.getZoom())) {
      updateView = true;
      viewProperties.zoom = zoom;
    }
    const rotation = readNumber(this.get_(params, "r"));
    if ("r" in this.params_ && differentNumber(rotation, view.getRotation())) {
      updateView = true;
      viewProperties.rotation = rotation;
    }
    const center = [
      readNumber(this.get_(params, "x")),
      readNumber(this.get_(params, "y"))
    ];
    if (("x" in this.params_ || "y" in this.params_) && differentArray(center, view.getCenter())) {
      updateView = true;
      viewProperties.center = center;
    }
    if (updateView) {
      if (!this.initial_ && this.animationOptions_) {
        view.animate(Object.assign(viewProperties, this.animationOptions_));
      } else {
        if (viewProperties.center) {
          view.setCenter(viewProperties.center);
        }
        if ("zoom" in viewProperties) {
          view.setZoom(viewProperties.zoom);
        }
        if ("rotation" in viewProperties) {
          view.setRotation(viewProperties.rotation);
        }
      }
    }
    const layers = map.getAllLayers();
    const layersParam = this.get_(params, "l");
    if ("l" in this.params_ && layersParam && layersParam.length === layers.length) {
      for (let i = 0, ii = layers.length; i < ii; ++i) {
        const value = parseInt(layersParam[i]);
        if (!isNaN(value)) {
          const visible = Boolean(value);
          const layer = layers[i];
          if (layer.getVisible() !== visible) {
            layer.setVisible(visible);
          }
        }
      }
    }
  }
  /**
   * Register a listener for a URL search parameter.  The callback will be called with a new value
   * when the corresponding search parameter changes due to history events (e.g. browser navigation).
   *
   * @param {string} key The URL search parameter.
   * @param {Callback} callback The function to call when the search parameter changes.
   * @return {string|null} The initial value of the search parameter (or null if absent from the URL).
   * @api
   */
  track(key, callback) {
    this.trackedCallbacks_[key] = callback;
    const url = new URL(window.location.href);
    const params = url.searchParams;
    const value = params.get(key);
    this.trackedValues_[key] = value;
    return value;
  }
  /**
   * Update the URL with a new search parameter value.  If the value is null, it will be
   * deleted from the search parameters.
   *
   * @param {string} key The URL search parameter.
   * @param {string|null} value The updated value (or null to remove it from the URL).
   * @api
   */
  update(key, value) {
    const url = new URL(window.location.href);
    const params = url.searchParams;
    if (value === null) {
      params.delete(key);
    } else {
      params.set(key, value);
    }
    if (key in this.trackedValues_) {
      this.trackedValues_[key] = value;
    }
    this.updateHistory_(url);
  }
  /**
   * @private
   */
  updateUrl_() {
    const map = this.getMap();
    if (!map) {
      return;
    }
    const view = map.getView();
    if (!view) {
      return;
    }
    const center = view.getCenter();
    const zoom = view.getZoom();
    const rotation = view.getRotation();
    const layers = map.getAllLayers();
    const visibilities = new Array(layers.length);
    for (let i = 0, ii = layers.length; i < ii; ++i) {
      visibilities[i] = layers[i].getVisible() ? "1" : "0";
    }
    const url = new URL(window.location.href);
    const params = url.searchParams;
    this.set_(params, "x", writeNumber(center[0]));
    this.set_(params, "y", writeNumber(center[1]));
    this.set_(params, "z", writeNumber(zoom));
    this.set_(params, "r", writeNumber(rotation));
    this.set_(params, "l", visibilities.join(""));
    this.updateHistory_(url);
    this.initial_ = false;
  }
  /**
   * @private
   * @param {URL} url The URL.
   */
  updateHistory_(url) {
    if (url.href !== window.location.href) {
      if (this.initial_ || this.replace_) {
        window.history.replaceState(history.state, "", url);
      } else {
        window.history.pushState(null, "", url);
      }
    }
  }
};
var Link_default = Link;

// node_modules/ol/interaction/Modify.js
var CIRCLE_CENTER_INDEX = 0;
var CIRCLE_CIRCUMFERENCE_INDEX = 1;
var tempExtent = [0, 0, 0, 0];
var tempSegment = [];
var ModifyEventType = {
  /**
   * Triggered upon feature modification start
   * @event ModifyEvent#modifystart
   * @api
   */
  MODIFYSTART: "modifystart",
  /**
   * Triggered upon feature modification end
   * @event ModifyEvent#modifyend
   * @api
   */
  MODIFYEND: "modifyend"
};
function getCoordinatesArray(coordinates, geometryType, depth) {
  let coordinatesArray;
  switch (geometryType) {
    case "LineString":
      coordinatesArray = coordinates;
      break;
    case "MultiLineString":
    case "Polygon":
      coordinatesArray = coordinates[depth[0]];
      break;
    case "MultiPolygon":
      coordinatesArray = coordinates[depth[1]][depth[0]];
      break;
    default:
  }
  return coordinatesArray;
}
var ModifyEvent = class extends Event_default {
  /**
   * @param {ModifyEventType} type Type.
   * @param {Collection<Feature>} features
   * The features modified.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent
   * Associated {@link module:ol/MapBrowserEvent~MapBrowserEvent}.
   */
  constructor(type, features, mapBrowserEvent) {
    super(type);
    this.features = features;
    this.mapBrowserEvent = mapBrowserEvent;
  }
};
var Modify = class extends Pointer_default {
  /**
   * @param {Options} options Options.
   */
  constructor(options) {
    super(
      /** @type {import("./Pointer.js").Options} */
      options
    );
    this.on;
    this.once;
    this.un;
    this.boundHandleFeatureChange_ = this.handleFeatureChange_.bind(this);
    this.condition_ = options.condition ? options.condition : primaryAction;
    this.defaultDeleteCondition_ = function(mapBrowserEvent) {
      return altKeyOnly(mapBrowserEvent) && singleClick(mapBrowserEvent);
    };
    this.deleteCondition_ = options.deleteCondition ? options.deleteCondition : this.defaultDeleteCondition_;
    this.insertVertexCondition_ = options.insertVertexCondition ? options.insertVertexCondition : always;
    this.vertexFeature_ = null;
    this.vertexSegments_ = null;
    this.lastCoordinate_ = [0, 0];
    this.ignoreNextSingleClick_ = false;
    this.featuresBeingModified_ = null;
    this.rBush_ = new RBush_default();
    this.pixelTolerance_ = options.pixelTolerance !== void 0 ? options.pixelTolerance : 10;
    this.snappedToVertex_ = false;
    this.changingFeature_ = false;
    this.dragSegments_ = [];
    this.overlay_ = new Vector_default({
      source: new Vector_default2({
        useSpatialIndex: false,
        wrapX: !!options.wrapX
      }),
      style: options.style ? options.style : getDefaultStyleFunction(),
      updateWhileAnimating: true,
      updateWhileInteracting: true
    });
    this.SEGMENT_WRITERS_ = {
      Point: this.writePointGeometry_.bind(this),
      LineString: this.writeLineStringGeometry_.bind(this),
      LinearRing: this.writeLineStringGeometry_.bind(this),
      Polygon: this.writePolygonGeometry_.bind(this),
      MultiPoint: this.writeMultiPointGeometry_.bind(this),
      MultiLineString: this.writeMultiLineStringGeometry_.bind(this),
      MultiPolygon: this.writeMultiPolygonGeometry_.bind(this),
      Circle: this.writeCircleGeometry_.bind(this),
      GeometryCollection: this.writeGeometryCollectionGeometry_.bind(this)
    };
    this.source_ = null;
    this.traceSource_ = options.traceSource || options.source || null;
    this.traceCondition_;
    this.setTrace(options.trace || false);
    this.traceState_ = { active: false };
    this.traceSegments_ = null;
    this.hitDetection_ = null;
    let features;
    if (options.features) {
      features = options.features;
    } else if (options.source) {
      this.source_ = options.source;
      features = new Collection_default(this.source_.getFeatures());
      this.source_.addEventListener(
        VectorEventType_default.ADDFEATURE,
        this.handleSourceAdd_.bind(this)
      );
      this.source_.addEventListener(
        VectorEventType_default.REMOVEFEATURE,
        this.handleSourceRemove_.bind(this)
      );
    }
    if (!features) {
      throw new Error(
        "The modify interaction requires features, a source or a layer"
      );
    }
    if (options.hitDetection) {
      this.hitDetection_ = options.hitDetection;
    }
    this.features_ = features;
    this.features_.forEach(this.addFeature_.bind(this));
    this.features_.addEventListener(
      CollectionEventType_default.ADD,
      this.handleFeatureAdd_.bind(this)
    );
    this.features_.addEventListener(
      CollectionEventType_default.REMOVE,
      this.handleFeatureRemove_.bind(this)
    );
    this.lastPointerEvent_ = null;
    this.delta_ = [0, 0];
    this.snapToPointer_ = options.snapToPointer === void 0 ? !this.hitDetection_ : options.snapToPointer;
  }
  /**
   * Toggle tracing mode or set a tracing condition.
   *
   * @param {boolean|import("../events/condition.js").Condition} trace A boolean to toggle tracing mode or an event
   *     condition that will be checked when a feature is clicked to determine if tracing should be active.
   */
  setTrace(trace) {
    let condition;
    if (!trace) {
      condition = never;
    } else if (trace === true) {
      condition = always;
    } else {
      condition = trace;
    }
    this.traceCondition_ = condition;
  }
  /**
   * @param {Feature} feature Feature.
   * @private
   */
  addFeature_(feature) {
    const geometry = feature.getGeometry();
    if (geometry) {
      const writer = this.SEGMENT_WRITERS_[geometry.getType()];
      if (writer) {
        writer(feature, geometry);
      }
    }
    const map = this.getMap();
    if (map && map.isRendered() && this.getActive()) {
      this.handlePointerAtPixel_(this.lastCoordinate_);
    }
    feature.addEventListener(EventType_default.CHANGE, this.boundHandleFeatureChange_);
  }
  /**
   * @param {import("../MapBrowserEvent.js").default} evt Map browser event.
   * @param {Array<SegmentData>} segments The segments subject to modification.
   * @private
   */
  willModifyFeatures_(evt, segments) {
    if (!this.featuresBeingModified_) {
      this.featuresBeingModified_ = new Collection_default();
      const features = this.featuresBeingModified_.getArray();
      for (let i = 0, ii = segments.length; i < ii; ++i) {
        const feature = segments[i].feature;
        if (feature && !features.includes(feature)) {
          this.featuresBeingModified_.push(feature);
        }
      }
      if (this.featuresBeingModified_.getLength() === 0) {
        this.featuresBeingModified_ = null;
      } else {
        this.dispatchEvent(
          new ModifyEvent(
            ModifyEventType.MODIFYSTART,
            this.featuresBeingModified_,
            evt
          )
        );
      }
    }
  }
  /**
   * @param {Feature} feature Feature.
   * @private
   */
  removeFeature_(feature) {
    this.removeFeatureSegmentData_(feature);
    if (this.vertexFeature_ && this.features_.getLength() === 0) {
      this.overlay_.getSource().removeFeature(this.vertexFeature_);
      this.vertexFeature_ = null;
    }
    feature.removeEventListener(
      EventType_default.CHANGE,
      this.boundHandleFeatureChange_
    );
  }
  /**
   * @param {Feature} feature Feature.
   * @private
   */
  removeFeatureSegmentData_(feature) {
    const rBush = this.rBush_;
    const nodesToRemove = [];
    rBush.forEach(
      /**
       * @param {SegmentData} node RTree node.
       */
      function(node) {
        if (feature === node.feature) {
          nodesToRemove.push(node);
        }
      }
    );
    for (let i = nodesToRemove.length - 1; i >= 0; --i) {
      const nodeToRemove = nodesToRemove[i];
      for (let j = this.dragSegments_.length - 1; j >= 0; --j) {
        if (this.dragSegments_[j][0] === nodeToRemove) {
          this.dragSegments_.splice(j, 1);
        }
      }
      rBush.remove(nodeToRemove);
    }
  }
  /**
   * Activate or deactivate the interaction.
   * @param {boolean} active Active.
   * @observable
   * @api
   * @override
   */
  setActive(active) {
    if (this.vertexFeature_ && !active) {
      this.overlay_.getSource().removeFeature(this.vertexFeature_);
      this.vertexFeature_ = null;
    }
    super.setActive(active);
  }
  /**
   * Remove the interaction from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../Map.js").default} map Map.
   * @override
   */
  setMap(map) {
    this.overlay_.setMap(map);
    super.setMap(map);
  }
  /**
   * Get the overlay layer that this interaction renders the modification point or vertex to.
   * @return {VectorLayer} Overlay layer.
   * @api
   */
  getOverlay() {
    return this.overlay_;
  }
  /**
   * @param {import("../source/Vector.js").VectorSourceEvent} event Event.
   * @private
   */
  handleSourceAdd_(event) {
    if (event.feature) {
      this.features_.push(event.feature);
    }
  }
  /**
   * @param {import("../source/Vector.js").VectorSourceEvent} event Event.
   * @private
   */
  handleSourceRemove_(event) {
    if (event.feature) {
      this.features_.remove(event.feature);
    }
  }
  /**
   * @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
   * @private
   */
  handleFeatureAdd_(evt) {
    this.addFeature_(evt.element);
  }
  /**
   * @param {import("../events/Event.js").default} evt Event.
   * @private
   */
  handleFeatureChange_(evt) {
    if (!this.changingFeature_) {
      const feature = (
        /** @type {Feature} */
        evt.target
      );
      this.removeFeature_(feature);
      this.addFeature_(feature);
    }
  }
  /**
   * @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
   * @private
   */
  handleFeatureRemove_(evt) {
    this.removeFeature_(evt.element);
  }
  /**
   * @param {Feature} feature Feature
   * @param {Point} geometry Geometry.
   * @private
   */
  writePointGeometry_(feature, geometry) {
    const coordinates = geometry.getCoordinates();
    const segmentData = {
      feature,
      geometry,
      segment: [coordinates, coordinates]
    };
    this.rBush_.insert(geometry.getExtent(), segmentData);
  }
  /**
   * @param {Feature} feature Feature
   * @param {import("../geom/MultiPoint.js").default} geometry Geometry.
   * @private
   */
  writeMultiPointGeometry_(feature, geometry) {
    const points = geometry.getCoordinates();
    for (let i = 0, ii = points.length; i < ii; ++i) {
      const coordinates = points[i];
      const segmentData = {
        feature,
        geometry,
        depth: [i],
        index: i,
        segment: [coordinates, coordinates]
      };
      this.rBush_.insert(geometry.getExtent(), segmentData);
    }
  }
  /**
   * @param {Feature} feature Feature
   * @param {import("../geom/LineString.js").default} geometry Geometry.
   * @private
   */
  writeLineStringGeometry_(feature, geometry) {
    const coordinates = geometry.getCoordinates();
    for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
      const segment = coordinates.slice(i, i + 2);
      const segmentData = {
        feature,
        geometry,
        index: i,
        segment
      };
      this.rBush_.insert(boundingExtent(segment), segmentData);
    }
  }
  /**
   * @param {Feature} feature Feature
   * @param {import("../geom/MultiLineString.js").default} geometry Geometry.
   * @private
   */
  writeMultiLineStringGeometry_(feature, geometry) {
    const lines = geometry.getCoordinates();
    for (let j = 0, jj = lines.length; j < jj; ++j) {
      const coordinates = lines[j];
      for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
        const segment = coordinates.slice(i, i + 2);
        const segmentData = {
          feature,
          geometry,
          depth: [j],
          index: i,
          segment
        };
        this.rBush_.insert(boundingExtent(segment), segmentData);
      }
    }
  }
  /**
   * @param {Feature} feature Feature
   * @param {import("../geom/Polygon.js").default} geometry Geometry.
   * @private
   */
  writePolygonGeometry_(feature, geometry) {
    const rings = geometry.getCoordinates();
    for (let j = 0, jj = rings.length; j < jj; ++j) {
      const coordinates = rings[j];
      for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
        const segment = coordinates.slice(i, i + 2);
        const segmentData = {
          feature,
          geometry,
          depth: [j],
          index: i,
          segment
        };
        this.rBush_.insert(boundingExtent(segment), segmentData);
      }
    }
  }
  /**
   * @param {Feature} feature Feature
   * @param {import("../geom/MultiPolygon.js").default} geometry Geometry.
   * @private
   */
  writeMultiPolygonGeometry_(feature, geometry) {
    const polygons = geometry.getCoordinates();
    for (let k = 0, kk = polygons.length; k < kk; ++k) {
      const rings = polygons[k];
      for (let j = 0, jj = rings.length; j < jj; ++j) {
        const coordinates = rings[j];
        for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
          const segment = coordinates.slice(i, i + 2);
          const segmentData = {
            feature,
            geometry,
            depth: [j, k],
            index: i,
            segment
          };
          this.rBush_.insert(boundingExtent(segment), segmentData);
        }
      }
    }
  }
  /**
   * We convert a circle into two segments.  The segment at index
   * {@link CIRCLE_CENTER_INDEX} is the
   * circle's center (a point).  The segment at index
   * {@link CIRCLE_CIRCUMFERENCE_INDEX} is
   * the circumference, and is not a line segment.
   *
   * @param {Feature} feature Feature.
   * @param {import("../geom/Circle.js").default} geometry Geometry.
   * @private
   */
  writeCircleGeometry_(feature, geometry) {
    const coordinates = geometry.getCenter();
    const centerSegmentData = {
      feature,
      geometry,
      index: CIRCLE_CENTER_INDEX,
      segment: [coordinates, coordinates]
    };
    const circumferenceSegmentData = {
      feature,
      geometry,
      index: CIRCLE_CIRCUMFERENCE_INDEX,
      segment: [coordinates, coordinates]
    };
    const featureSegments = [centerSegmentData, circumferenceSegmentData];
    centerSegmentData.featureSegments = featureSegments;
    circumferenceSegmentData.featureSegments = featureSegments;
    this.rBush_.insert(createOrUpdateFromCoordinate(coordinates), centerSegmentData);
    let circleGeometry = (
      /** @type {import("../geom/Geometry.js").default} */
      geometry
    );
    const userProjection = getUserProjection();
    if (userProjection && this.getMap()) {
      const projection = this.getMap().getView().getProjection();
      circleGeometry = circleGeometry.clone().transform(userProjection, projection);
      circleGeometry = fromCircle(
        /** @type {import("../geom/Circle.js").default} */
        circleGeometry
      ).transform(projection, userProjection);
    }
    this.rBush_.insert(circleGeometry.getExtent(), circumferenceSegmentData);
  }
  /**
   * @param {Feature} feature Feature
   * @param {import("../geom/GeometryCollection.js").default} geometry Geometry.
   * @private
   */
  writeGeometryCollectionGeometry_(feature, geometry) {
    const geometries = geometry.getGeometriesArray();
    for (let i = 0; i < geometries.length; ++i) {
      const geometry2 = geometries[i];
      const writer = this.SEGMENT_WRITERS_[geometry2.getType()];
      writer(feature, geometry2);
    }
  }
  /**
   * @param {import("../coordinate.js").Coordinate} coordinates Coordinates.
   * @param {Array<Feature>} features The features being modified.
   * @param {Array<import("../geom/SimpleGeometry.js").default>} geometries The geometries being modified.
   * @param {boolean} existing The vertex represents an existing vertex.
   * @return {Feature} Vertex feature.
   * @private
   */
  createOrUpdateVertexFeature_(coordinates, features, geometries, existing) {
    let vertexFeature = this.vertexFeature_;
    if (!vertexFeature) {
      vertexFeature = new Feature_default(new Point_default(coordinates));
      this.vertexFeature_ = vertexFeature;
      this.overlay_.getSource().addFeature(vertexFeature);
    } else {
      const geometry = vertexFeature.getGeometry();
      geometry.setCoordinates(coordinates);
    }
    vertexFeature.set("features", features);
    vertexFeature.set("geometries", geometries);
    vertexFeature.set("existing", existing);
    return vertexFeature;
  }
  /**
   * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} and may modify the geometry.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @override
   */
  handleEvent(mapBrowserEvent) {
    if (!mapBrowserEvent.originalEvent) {
      return true;
    }
    this.lastPointerEvent_ = mapBrowserEvent;
    let handled;
    if (!mapBrowserEvent.map.getView().getInteracting() && mapBrowserEvent.type == MapBrowserEventType_default.POINTERMOVE && !this.handlingDownUpSequence) {
      this.handlePointerMove_(mapBrowserEvent);
    }
    if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) {
      if (mapBrowserEvent.type != MapBrowserEventType_default.SINGLECLICK || !this.ignoreNextSingleClick_) {
        handled = this.removePoint();
      } else {
        handled = true;
      }
    }
    if (mapBrowserEvent.type == MapBrowserEventType_default.SINGLECLICK) {
      this.ignoreNextSingleClick_ = false;
    }
    return super.handleEvent(mapBrowserEvent) && !handled;
  }
  /**
   * @param {import("../coordinate.js").Coordinate} pixelCoordinate Pixel coordinate.
   * @return {Array<SegmentData>|undefined} Insert vertices and update drag segments.
   * @private
   */
  findInsertVerticesAndUpdateDragSegments_(pixelCoordinate) {
    this.handlePointerAtPixel_(pixelCoordinate);
    this.dragSegments_.length = 0;
    this.featuresBeingModified_ = null;
    const vertexFeature = this.vertexFeature_;
    if (!vertexFeature) {
      return;
    }
    const projection = this.getMap().getView().getProjection();
    const insertVertices = [];
    const vertex = this.vertexFeature_.getGeometry().getCoordinates();
    const vertexExtent = boundingExtent([vertex]);
    const segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
    const componentSegments = {};
    segmentDataMatches.sort(compareIndexes);
    for (let i = 0, ii = segmentDataMatches.length; i < ii; ++i) {
      const segmentDataMatch = segmentDataMatches[i];
      const segment = segmentDataMatch.segment;
      let uid = getUid(segmentDataMatch.geometry);
      const depth = segmentDataMatch.depth;
      if (depth) {
        uid += "-" + depth.join("-");
      }
      if (!componentSegments[uid]) {
        componentSegments[uid] = new Array(2);
      }
      if (segmentDataMatch.geometry.getType() === "Circle" && segmentDataMatch.index === CIRCLE_CIRCUMFERENCE_INDEX) {
        const closestVertex = closestOnSegmentData(
          pixelCoordinate,
          segmentDataMatch,
          projection
        );
        if (equals2(closestVertex, vertex) && !componentSegments[uid][0]) {
          this.dragSegments_.push([segmentDataMatch, 0]);
          componentSegments[uid][0] = segmentDataMatch;
        }
        continue;
      }
      if (equals2(segment[0], vertex) && !componentSegments[uid][0]) {
        this.dragSegments_.push([segmentDataMatch, 0]);
        componentSegments[uid][0] = segmentDataMatch;
        continue;
      }
      if (equals2(segment[1], vertex) && !componentSegments[uid][1]) {
        if (componentSegments[uid][0] && componentSegments[uid][0].index === 0) {
          let coordinates = segmentDataMatch.geometry.getCoordinates();
          switch (segmentDataMatch.geometry.getType()) {
            // prevent dragging closed linestrings by the connecting node
            case "LineString":
            case "MultiLineString":
              continue;
            // if dragging the first vertex of a polygon, ensure the other segment
            // belongs to the closing vertex of the linear ring
            case "MultiPolygon":
              coordinates = coordinates[depth[1]];
            /* falls through */
            case "Polygon":
              if (segmentDataMatch.index !== coordinates[depth[0]].length - 2) {
                continue;
              }
              break;
            default:
          }
        }
        this.dragSegments_.push([segmentDataMatch, 1]);
        componentSegments[uid][1] = segmentDataMatch;
        continue;
      }
      if (getUid(segment) in this.vertexSegments_ && !componentSegments[uid][0] && !componentSegments[uid][1]) {
        insertVertices.push(segmentDataMatch);
      }
    }
    return insertVertices;
  }
  /**
   * @private
   */
  deactivateTrace_() {
    this.traceState_ = { active: false };
  }
  /**
   * Update the trace.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @private
   */
  updateTrace_(event) {
    const traceState = this.traceState_;
    if (!traceState.active) {
      return;
    }
    if (traceState.targetIndex === -1) {
      const startPx = event.map.getPixelFromCoordinate(traceState.startCoord);
      if (distance(startPx, event.pixel) < this.pixelTolerance_) {
        return;
      }
    }
    const updatedTraceTarget = getTraceTargetUpdate(
      event.coordinate,
      traceState,
      event.map,
      this.pixelTolerance_
    );
    if (traceState.targetIndex === -1 && Math.sqrt(updatedTraceTarget.closestTargetDistance) / event.map.getView().getResolution() > this.pixelTolerance_) {
      return;
    }
    if (traceState.targetIndex !== updatedTraceTarget.index) {
      if (traceState.targetIndex !== -1) {
        const oldTarget = traceState.targets[traceState.targetIndex];
        this.removeTracedCoordinates_(oldTarget.startIndex, oldTarget.endIndex);
      } else {
        for (const traceSegment of this.traceSegments_) {
          const segmentData = traceSegment[0];
          const geometry = segmentData.geometry;
          const index = traceSegment[1];
          const coordinates = geometry.getCoordinates();
          const coordinatesArray = getCoordinatesArray(
            coordinates,
            geometry.getType(),
            segmentData.depth
          );
          coordinatesArray.splice(segmentData.index + index, 1);
          geometry.setCoordinates(coordinates);
          if (index === 0) {
            segmentData.index -= 1;
          }
        }
      }
      const newTarget = traceState.targets[updatedTraceTarget.index];
      this.addTracedCoordinates_(
        newTarget,
        newTarget.startIndex,
        updatedTraceTarget.endIndex
      );
    } else {
      const target2 = traceState.targets[traceState.targetIndex];
      this.addOrRemoveTracedCoordinates_(target2, updatedTraceTarget.endIndex);
    }
    traceState.targetIndex = updatedTraceTarget.index;
    const target = traceState.targets[traceState.targetIndex];
    target.endIndex = updatedTraceTarget.endIndex;
  }
  getTraceCandidates_(event) {
    const map = this.getMap();
    const tolerance = this.pixelTolerance_;
    const lowerLeft = map.getCoordinateFromPixel([
      event.pixel[0] - tolerance,
      event.pixel[1] + tolerance
    ]);
    const upperRight = map.getCoordinateFromPixel([
      event.pixel[0] + tolerance,
      event.pixel[1] - tolerance
    ]);
    const extent = boundingExtent([lowerLeft, upperRight]);
    const features = this.traceSource_.getFeaturesInExtent(extent);
    return features;
  }
  /**
   * Activate or deactivate trace state based on a browser event.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @private
   */
  toggleTraceState_(event) {
    if (!this.traceSource_ || !this.traceCondition_(event)) {
      return;
    }
    if (this.traceState_.active) {
      this.deactivateTrace_();
      this.traceSegments_ = null;
      return;
    }
    const features = this.getTraceCandidates_(event);
    if (features.length === 0) {
      return;
    }
    const targets = getTraceTargets(event.coordinate, features);
    if (targets.length) {
      this.traceState_ = {
        active: true,
        startCoord: event.coordinate.slice(),
        targets,
        targetIndex: -1
      };
    }
  }
  /**
   * @param {import('./tracing.js').TraceTarget} target The trace target.
   * @param {number} endIndex The new end index of the trace.
   * @private
   */
  addOrRemoveTracedCoordinates_(target, endIndex) {
    const previouslyForward = target.startIndex <= target.endIndex;
    const currentlyForward = target.startIndex <= endIndex;
    if (previouslyForward === currentlyForward) {
      if (previouslyForward && endIndex > target.endIndex || !previouslyForward && endIndex < target.endIndex) {
        this.addTracedCoordinates_(target, target.endIndex, endIndex);
      } else if (previouslyForward && endIndex < target.endIndex || !previouslyForward && endIndex > target.endIndex) {
        this.removeTracedCoordinates_(endIndex, target.endIndex);
      }
    } else {
      this.removeTracedCoordinates_(target.startIndex, target.endIndex);
      this.addTracedCoordinates_(target, target.startIndex, endIndex);
    }
  }
  /**
   * @param {number} fromIndex The start index.
   * @param {number} toIndex The end index.
   * @private
   */
  removeTracedCoordinates_(fromIndex, toIndex) {
    if (fromIndex === toIndex) {
      return;
    }
    let remove = 0;
    if (fromIndex < toIndex) {
      const start = Math.ceil(fromIndex);
      let end = Math.floor(toIndex);
      if (end === toIndex) {
        end -= 1;
      }
      remove = end - start + 1;
    } else {
      const start = Math.floor(fromIndex);
      let end = Math.ceil(toIndex);
      if (end === toIndex) {
        end += 1;
      }
      remove = start - end + 1;
    }
    if (remove > 0) {
      for (const traceSegment of this.traceSegments_) {
        const segmentData = traceSegment[0];
        const geometry = segmentData.geometry;
        const index = traceSegment[1];
        let removeIndex = traceSegment[0].index + 1;
        if (index === 1) {
          removeIndex -= remove;
        }
        const coordinates = geometry.getCoordinates();
        const coordinatesArray = getCoordinatesArray(
          coordinates,
          geometry.getType(),
          segmentData.depth
        );
        coordinatesArray.splice(removeIndex, remove);
        geometry.setCoordinates(coordinates);
        if (index === 1) {
          segmentData.index -= remove;
        }
      }
    }
  }
  /**
   * @param {import('./tracing.js').TraceTarget} target The trace target.
   * @param {number} fromIndex The start index.
   * @param {number} toIndex The end index.
   * @private
   */
  addTracedCoordinates_(target, fromIndex, toIndex) {
    if (fromIndex === toIndex) {
      return;
    }
    const newCoordinates = [];
    if (fromIndex < toIndex) {
      const start = Math.ceil(fromIndex);
      let end = Math.floor(toIndex);
      if (end === toIndex) {
        end -= 1;
      }
      for (let i = start; i <= end; ++i) {
        newCoordinates.push(getCoordinate(target.coordinates, i));
      }
    } else {
      const start = Math.floor(fromIndex);
      let end = Math.ceil(toIndex);
      if (end === toIndex) {
        end += 1;
      }
      for (let i = start; i >= end; --i) {
        newCoordinates.push(getCoordinate(target.coordinates, i));
      }
    }
    if (newCoordinates.length) {
      for (const traceSegment of this.traceSegments_) {
        const segmentData = traceSegment[0];
        const geometry = segmentData.geometry;
        const index = traceSegment[1];
        const insertIndex = segmentData.index + 1;
        if (index === 0) {
          newCoordinates.reverse();
        }
        const coordinates = geometry.getCoordinates();
        const coordinatesArray = getCoordinatesArray(
          coordinates,
          geometry.getType(),
          segmentData.depth
        );
        coordinatesArray.splice(insertIndex, 0, ...newCoordinates);
        geometry.setCoordinates(coordinates);
        if (index === 1) {
          segmentData.index += newCoordinates.length;
        }
      }
    }
  }
  /**
   * @param {import('../coordinate.js').Coordinate} vertex Vertex.
   * @param {DragSegment} dragSegment Drag segment.
   */
  updateGeometry_(vertex, dragSegment) {
    const segmentData = dragSegment[0];
    const depth = segmentData.depth;
    let coordinates;
    const segment = segmentData.segment;
    const geometry = segmentData.geometry;
    const index = dragSegment[1];
    while (vertex.length < geometry.getStride()) {
      vertex.push(segment[index][vertex.length]);
    }
    switch (geometry.getType()) {
      case "Point":
        coordinates = vertex;
        segment[0] = vertex;
        segment[1] = vertex;
        break;
      case "MultiPoint":
        coordinates = geometry.getCoordinates();
        coordinates[segmentData.index] = vertex;
        segment[0] = vertex;
        segment[1] = vertex;
        break;
      case "LineString":
        coordinates = geometry.getCoordinates();
        coordinates[segmentData.index + index] = vertex;
        segment[index] = vertex;
        break;
      case "MultiLineString":
        coordinates = geometry.getCoordinates();
        coordinates[depth[0]][segmentData.index + index] = vertex;
        segment[index] = vertex;
        break;
      case "Polygon":
        coordinates = geometry.getCoordinates();
        coordinates[depth[0]][segmentData.index + index] = vertex;
        segment[index] = vertex;
        break;
      case "MultiPolygon":
        coordinates = geometry.getCoordinates();
        coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex;
        segment[index] = vertex;
        break;
      case "Circle":
        const circle = (
          /** @type {import("../geom/Circle.js").default} */
          geometry
        );
        segment[0] = vertex;
        segment[1] = vertex;
        if (segmentData.index === CIRCLE_CENTER_INDEX) {
          this.changingFeature_ = true;
          circle.setCenter(vertex);
          this.changingFeature_ = false;
        } else {
          this.changingFeature_ = true;
          const projection = this.getMap().getView().getProjection();
          let radius = distance(
            fromUserCoordinate(circle.getCenter(), projection),
            fromUserCoordinate(vertex, projection)
          );
          const userProjection = getUserProjection();
          if (userProjection) {
            const circleGeometry = circle.clone().transform(userProjection, projection);
            circleGeometry.setRadius(radius);
            radius = circleGeometry.transform(projection, userProjection).getRadius();
          }
          circle.setRadius(radius);
          this.changingFeature_ = false;
        }
        break;
      default:
    }
    if (coordinates) {
      this.setGeometryCoordinates_(geometry, coordinates);
    }
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} evt Event.
   * @override
   */
  handleDragEvent(evt) {
    this.ignoreNextSingleClick_ = false;
    this.willModifyFeatures_(
      evt,
      this.dragSegments_.map(([segment]) => segment)
    );
    const vertex = [
      evt.coordinate[0] + this.delta_[0],
      evt.coordinate[1] + this.delta_[1]
    ];
    const features = [];
    const geometries = [];
    const startTraceCoord = this.traceState_.active && !this.traceSegments_ ? this.traceState_.startCoord : null;
    if (startTraceCoord) {
      this.traceSegments_ = [];
      for (const dragSegment of this.dragSegments_) {
        const segmentData = dragSegment[0];
        const eligibleForTracing = distance(
          closestOnSegment(startTraceCoord, segmentData.segment),
          startTraceCoord
        ) / evt.map.getView().getResolution() < 1;
        if (eligibleForTracing) {
          this.traceSegments_.push(dragSegment);
        }
      }
    }
    for (let i = 0, ii = this.dragSegments_.length; i < ii; ++i) {
      const dragSegment = this.dragSegments_[i];
      const segmentData = dragSegment[0];
      const feature = segmentData.feature;
      if (!features.includes(feature)) {
        features.push(feature);
      }
      const geometry = segmentData.geometry;
      if (!geometries.includes(geometry)) {
        geometries.push(geometry);
      }
      this.updateGeometry_(vertex, dragSegment);
    }
    this.updateTrace_(evt);
    this.createOrUpdateVertexFeature_(vertex, features, geometries, true);
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} evt Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(evt) {
    if (!this.condition_(evt)) {
      return false;
    }
    const pixelCoordinate = evt.coordinate;
    const insertVertices = this.findInsertVerticesAndUpdateDragSegments_(pixelCoordinate);
    if ((insertVertices == null ? void 0 : insertVertices.length) && this.insertVertexCondition_(evt)) {
      this.willModifyFeatures_(evt, insertVertices);
      if (this.vertexFeature_) {
        const vertex = this.vertexFeature_.getGeometry().getCoordinates();
        for (let j = insertVertices.length - 1; j >= 0; --j) {
          this.insertVertex_(insertVertices[j], vertex);
        }
        this.ignoreNextSingleClick_ = true;
      }
    }
    return !!this.vertexFeature_;
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} evt Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(evt) {
    for (let i = this.dragSegments_.length - 1; i >= 0; --i) {
      const segmentData = this.dragSegments_[i][0];
      const geometry = segmentData.geometry;
      if (geometry.getType() === "Circle") {
        const circle = (
          /** @type {import("../geom/Circle.js").default} */
          geometry
        );
        const coordinates = circle.getCenter();
        const centerSegmentData = segmentData.featureSegments[0];
        const circumferenceSegmentData = segmentData.featureSegments[1];
        centerSegmentData.segment[0] = coordinates;
        centerSegmentData.segment[1] = coordinates;
        circumferenceSegmentData.segment[0] = coordinates;
        circumferenceSegmentData.segment[1] = coordinates;
        this.rBush_.update(createOrUpdateFromCoordinate(coordinates), centerSegmentData);
        let circleGeometry = circle;
        const userProjection = getUserProjection();
        if (userProjection) {
          const projection = evt.map.getView().getProjection();
          circleGeometry = circleGeometry.clone().transform(userProjection, projection);
          circleGeometry = fromCircle(circleGeometry).transform(
            projection,
            userProjection
          );
        }
        this.rBush_.update(
          circleGeometry.getExtent(),
          circumferenceSegmentData
        );
      } else {
        this.rBush_.update(boundingExtent(segmentData.segment), segmentData);
      }
    }
    if (this.featuresBeingModified_) {
      this.toggleTraceState_(evt);
      this.dispatchEvent(
        new ModifyEvent(
          ModifyEventType.MODIFYEND,
          this.featuresBeingModified_,
          evt
        )
      );
      this.featuresBeingModified_ = null;
    }
    return false;
  }
  /**
   * @param {import("../MapBrowserEvent.js").default} evt Event.
   * @private
   */
  handlePointerMove_(evt) {
    this.lastCoordinate_ = evt.coordinate;
    this.handlePointerAtPixel_(this.lastCoordinate_);
  }
  /**
   * @param {import("../coordinate.js").Coordinate} pixelCoordinate The pixel Coordinate.
   * @private
   */
  handlePointerAtPixel_(pixelCoordinate) {
    const map = this.getMap();
    const pixel = map.getPixelFromCoordinate(pixelCoordinate);
    const projection = map.getView().getProjection();
    const sortByDistance = function(a, b) {
      return projectedDistanceToSegmentDataSquared(pixelCoordinate, a, projection) - projectedDistanceToSegmentDataSquared(pixelCoordinate, b, projection);
    };
    let nodes;
    let hitPointGeometry;
    if (this.hitDetection_) {
      const layerFilter = typeof this.hitDetection_ === "object" ? (layer) => layer === this.hitDetection_ : void 0;
      map.forEachFeatureAtPixel(
        pixel,
        (feature, layer, geometry) => {
          if (geometry && geometry.getType() === "Point") {
            geometry = new Point_default(
              toUserCoordinate(geometry.getCoordinates(), projection)
            );
          }
          const geom = geometry || feature.getGeometry();
          if (geom && geom.getType() === "Point" && feature instanceof Feature_default && this.features_.getArray().includes(feature)) {
            hitPointGeometry = /** @type {Point} */
            geom;
            const coordinate = (
              /** @type {Point} */
              feature.getGeometry().getFlatCoordinates().slice(0, 2)
            );
            nodes = [
              {
                feature,
                geometry: hitPointGeometry,
                segment: [coordinate, coordinate]
              }
            ];
          }
          return true;
        },
        { layerFilter }
      );
    }
    if (!nodes) {
      const viewExtent = fromUserExtent(
        createOrUpdateFromCoordinate(pixelCoordinate, tempExtent),
        projection
      );
      const buffer2 = map.getView().getResolution() * this.pixelTolerance_;
      const box = toUserExtent(
        buffer(viewExtent, buffer2, tempExtent),
        projection
      );
      nodes = this.rBush_.getInExtent(box);
    }
    if (nodes && nodes.length > 0) {
      const node = nodes.sort(sortByDistance)[0];
      const closestSegment = node.segment;
      let vertex = closestOnSegmentData(pixelCoordinate, node, projection);
      const vertexPixel = map.getPixelFromCoordinate(vertex);
      let dist = distance(pixel, vertexPixel);
      if (hitPointGeometry || dist <= this.pixelTolerance_) {
        const vertexSegments = {};
        vertexSegments[getUid(closestSegment)] = true;
        if (!this.snapToPointer_) {
          this.delta_[0] = vertex[0] - pixelCoordinate[0];
          this.delta_[1] = vertex[1] - pixelCoordinate[1];
        }
        if (node.geometry.getType() === "Circle" && node.index === CIRCLE_CIRCUMFERENCE_INDEX) {
          this.snappedToVertex_ = true;
          this.createOrUpdateVertexFeature_(
            vertex,
            [node.feature],
            [node.geometry],
            this.snappedToVertex_
          );
        } else {
          const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
          const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
          const squaredDist1 = squaredDistance(vertexPixel, pixel1);
          const squaredDist2 = squaredDistance(vertexPixel, pixel2);
          dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
          this.snappedToVertex_ = dist <= this.pixelTolerance_;
          if (!this.snappedToVertex_ && !this.insertVertexCondition_(this.lastPointerEvent_)) {
            if (this.vertexFeature_) {
              this.overlay_.getSource().removeFeature(this.vertexFeature_);
              this.vertexFeature_ = null;
            }
            return;
          }
          if (this.snappedToVertex_) {
            vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
          }
          this.createOrUpdateVertexFeature_(
            vertex,
            [node.feature],
            [node.geometry],
            this.snappedToVertex_
          );
          const geometries = {};
          geometries[getUid(node.geometry)] = true;
          for (let i = 1, ii = nodes.length; i < ii; ++i) {
            const segment = nodes[i].segment;
            if (equals2(closestSegment[0], segment[0]) && equals2(closestSegment[1], segment[1]) || equals2(closestSegment[0], segment[1]) && equals2(closestSegment[1], segment[0])) {
              const geometryUid = getUid(nodes[i].geometry);
              if (!(geometryUid in geometries)) {
                geometries[geometryUid] = true;
                vertexSegments[getUid(segment)] = true;
              }
            } else {
              break;
            }
          }
        }
        this.vertexSegments_ = vertexSegments;
        return;
      }
    }
    if (this.vertexFeature_) {
      this.overlay_.getSource().removeFeature(this.vertexFeature_);
      this.vertexFeature_ = null;
    }
  }
  /**
   * @param {SegmentData} segmentData Segment data.
   * @param {import("../coordinate.js").Coordinate} vertex Vertex.
   * @return {boolean} A vertex was inserted.
   * @private
   */
  insertVertex_(segmentData, vertex) {
    const segment = segmentData.segment;
    const feature = segmentData.feature;
    const geometry = segmentData.geometry;
    const depth = segmentData.depth;
    const index = segmentData.index;
    let coordinates;
    while (vertex.length < geometry.getStride()) {
      vertex.push(0);
    }
    switch (geometry.getType()) {
      case "MultiLineString":
        coordinates = geometry.getCoordinates();
        coordinates[depth[0]].splice(index + 1, 0, vertex);
        break;
      case "Polygon":
        coordinates = geometry.getCoordinates();
        coordinates[depth[0]].splice(index + 1, 0, vertex);
        break;
      case "MultiPolygon":
        coordinates = geometry.getCoordinates();
        coordinates[depth[1]][depth[0]].splice(index + 1, 0, vertex);
        break;
      case "LineString":
        coordinates = geometry.getCoordinates();
        coordinates.splice(index + 1, 0, vertex);
        break;
      default:
        return false;
    }
    this.setGeometryCoordinates_(geometry, coordinates);
    const rTree = this.rBush_;
    rTree.remove(segmentData);
    this.updateSegmentIndices_(geometry, index, depth, 1);
    const newSegmentData = {
      segment: [segment[0], vertex],
      feature,
      geometry,
      depth,
      index
    };
    rTree.insert(boundingExtent(newSegmentData.segment), newSegmentData);
    this.dragSegments_.push([newSegmentData, 1]);
    const newSegmentData2 = {
      segment: [vertex, segment[1]],
      feature,
      geometry,
      depth,
      index: index + 1
    };
    rTree.insert(boundingExtent(newSegmentData2.segment), newSegmentData2);
    this.dragSegments_.push([newSegmentData2, 0]);
    return true;
  }
  /**
   * @param {import("../coordinate.js").Coordinate} coordinate The coordinate.
   * @return {import("../coordinate.js").Coordinate} The updated pointer coordinate.
   * @private
   */
  updatePointer_(coordinate) {
    var _a;
    if (coordinate) {
      this.findInsertVerticesAndUpdateDragSegments_(coordinate);
    }
    return (_a = this.vertexFeature_) == null ? void 0 : _a.getGeometry().getCoordinates();
  }
  /**
   * Get the current pointer position.
   * @return {import("../coordinate.js").Coordinate | null} The current pointer coordinate.
   */
  getPoint() {
    var _a;
    const coordinate = (_a = this.vertexFeature_) == null ? void 0 : _a.getGeometry().getCoordinates();
    if (!coordinate) {
      return null;
    }
    return toUserCoordinate(
      coordinate,
      this.getMap().getView().getProjection()
    );
  }
  /**
   * Check if a point can be removed from the current linestring or polygon at the current
   * pointer position.
   * @return {boolean} A point can be deleted at the current pointer position.
   * @api
   */
  canRemovePoint() {
    if (!this.vertexFeature_) {
      return false;
    }
    if (this.vertexFeature_.get("geometries").every(
      (geometry) => geometry.getType() === "Circle" || geometry.getType().endsWith("Point")
    )) {
      return false;
    }
    const coordinate = this.vertexFeature_.getGeometry().getCoordinates();
    const segments = this.rBush_.getInExtent(boundingExtent([coordinate]));
    return segments.some(
      ({ segment }) => equals2(segment[0], coordinate) || equals2(segment[1], coordinate)
    );
  }
  /**
   * Removes the vertex currently being pointed from the current linestring or polygon.
   * @param {import('../coordinate.js').Coordinate} [coordinate] If provided, the pointer
   * will be set to the provided coordinate. If not, the current pointer coordinate will be used.
   * @return {boolean} True when a vertex was removed.
   * @api
   */
  removePoint(coordinate) {
    if (coordinate) {
      coordinate = fromUserCoordinate(
        coordinate,
        this.getMap().getView().getProjection()
      );
      this.updatePointer_(coordinate);
    }
    if (!this.lastPointerEvent_ || this.lastPointerEvent_ && this.lastPointerEvent_.type != MapBrowserEventType_default.POINTERDRAG) {
      const evt = this.lastPointerEvent_;
      this.willModifyFeatures_(
        evt,
        this.dragSegments_.map(([segment]) => segment)
      );
      const removed = this.removeVertex_();
      if (this.featuresBeingModified_) {
        this.dispatchEvent(
          new ModifyEvent(
            ModifyEventType.MODIFYEND,
            this.featuresBeingModified_,
            evt
          )
        );
      }
      this.featuresBeingModified_ = null;
      return removed;
    }
    return false;
  }
  /**
   * Removes a vertex from all matching features.
   * @return {boolean} True when a vertex was removed.
   * @private
   */
  removeVertex_() {
    const dragSegments = this.dragSegments_;
    const segmentsByFeature = {};
    let deleted = false;
    let component, coordinates, dragSegment, geometry, i, index, left;
    let newIndex, right, segmentData, uid;
    for (i = dragSegments.length - 1; i >= 0; --i) {
      dragSegment = dragSegments[i];
      segmentData = dragSegment[0];
      uid = getUid(segmentData.feature);
      if (segmentData.depth) {
        uid += "-" + segmentData.depth.join("-");
      }
      if (!(uid in segmentsByFeature)) {
        segmentsByFeature[uid] = {};
      }
      if (dragSegment[1] === 0) {
        segmentsByFeature[uid].right = segmentData;
        segmentsByFeature[uid].index = segmentData.index;
      } else if (dragSegment[1] == 1) {
        segmentsByFeature[uid].left = segmentData;
        segmentsByFeature[uid].index = segmentData.index + 1;
      }
    }
    for (uid in segmentsByFeature) {
      right = segmentsByFeature[uid].right;
      left = segmentsByFeature[uid].left;
      index = segmentsByFeature[uid].index;
      newIndex = index - 1;
      if (left !== void 0) {
        segmentData = left;
      } else {
        segmentData = right;
      }
      if (newIndex < 0) {
        newIndex = 0;
      }
      geometry = segmentData.geometry;
      coordinates = geometry.getCoordinates();
      component = coordinates;
      deleted = false;
      switch (geometry.getType()) {
        case "MultiLineString":
          if (coordinates[segmentData.depth[0]].length > 2) {
            coordinates[segmentData.depth[0]].splice(index, 1);
            deleted = true;
          }
          break;
        case "LineString":
          if (coordinates.length > 2) {
            coordinates.splice(index, 1);
            deleted = true;
          }
          break;
        case "MultiPolygon":
          component = component[segmentData.depth[1]];
        /* falls through */
        case "Polygon":
          component = component[segmentData.depth[0]];
          if (component.length > 4) {
            if (index == component.length - 1) {
              index = 0;
            }
            component.splice(index, 1);
            deleted = true;
            if (index === 0) {
              component.pop();
              component.push(component[0]);
              newIndex = component.length - 1;
            }
          }
          break;
        default:
      }
      if (deleted) {
        this.setGeometryCoordinates_(geometry, coordinates);
        const segments = [];
        if (left !== void 0) {
          this.rBush_.remove(left);
          segments.push(left.segment[0]);
        }
        if (right !== void 0) {
          this.rBush_.remove(right);
          segments.push(right.segment[1]);
        }
        if (left !== void 0 && right !== void 0) {
          const newSegmentData = {
            depth: segmentData.depth,
            feature: segmentData.feature,
            geometry: segmentData.geometry,
            index: newIndex,
            segment: segments
          };
          this.rBush_.insert(
            boundingExtent(newSegmentData.segment),
            newSegmentData
          );
        }
        this.updateSegmentIndices_(geometry, index, segmentData.depth, -1);
        if (this.vertexFeature_) {
          this.overlay_.getSource().removeFeature(this.vertexFeature_);
          this.vertexFeature_ = null;
        }
        dragSegments.length = 0;
      }
    }
    return deleted;
  }
  /**
   * Check if a point can be inserted to the current linestring or polygon at the current
   * pointer position.
   * @return {boolean} A point can be inserted at the current pointer position.
   * @api
   */
  canInsertPoint() {
    if (!this.vertexFeature_) {
      return false;
    }
    if (this.vertexFeature_.get("geometries").every(
      (geometry) => geometry.getType() === "Circle" || geometry.getType().endsWith("Point")
    )) {
      return false;
    }
    const coordinate = this.vertexFeature_.getGeometry().getCoordinates();
    const segments = this.rBush_.getInExtent(boundingExtent([coordinate]));
    return segments.some(
      ({ segment }) => !(equals2(segment[0], coordinate) || equals2(segment[1], coordinate))
    );
  }
  /**
   * Inserts the vertex currently being pointed to the current linestring or polygon.
   * @param {import('../coordinate.js').Coordinate} [coordinate] If provided, the pointer
   * will be set to the provided coordinate. If not, the current pointer coordinate will be used.
   * @return {boolean} A vertex was inserted.
   * @api
   */
  insertPoint(coordinate) {
    var _a;
    const pixelCoordinate = coordinate ? fromUserCoordinate(coordinate, this.getMap().getView().getProjection()) : (_a = this.vertexFeature_) == null ? void 0 : _a.getGeometry().getCoordinates();
    if (!pixelCoordinate) {
      return false;
    }
    const insertVertices = this.findInsertVerticesAndUpdateDragSegments_(pixelCoordinate);
    return insertVertices.reduce(
      (prev, segmentData) => prev || this.insertVertex_(segmentData, pixelCoordinate),
      false
    );
  }
  /**
   * @param {import("../geom/SimpleGeometry.js").default} geometry Geometry.
   * @param {Array} coordinates Coordinates.
   * @private
   */
  setGeometryCoordinates_(geometry, coordinates) {
    this.changingFeature_ = true;
    geometry.setCoordinates(coordinates);
    this.changingFeature_ = false;
  }
  /**
   * @param {import("../geom/SimpleGeometry.js").default} geometry Geometry.
   * @param {number} index Index.
   * @param {Array<number>|undefined} depth Depth.
   * @param {number} delta Delta (1 or -1).
   * @private
   */
  updateSegmentIndices_(geometry, index, depth, delta) {
    this.rBush_.forEachInExtent(
      geometry.getExtent(),
      function(segmentDataMatch) {
        if (segmentDataMatch.geometry === geometry && (depth === void 0 || segmentDataMatch.depth === void 0 || equals(segmentDataMatch.depth, depth)) && segmentDataMatch.index > index) {
          segmentDataMatch.index += delta;
        }
      }
    );
  }
};
function compareIndexes(a, b) {
  return a.index - b.index;
}
function projectedDistanceToSegmentDataSquared(pointCoordinates, segmentData, projection) {
  const geometry = segmentData.geometry;
  if (geometry.getType() === "Circle") {
    let circleGeometry = (
      /** @type {import("../geom/Circle.js").default} */
      geometry
    );
    if (segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) {
      const userProjection = getUserProjection();
      if (userProjection) {
        circleGeometry = circleGeometry.clone().transform(userProjection, projection);
      }
      const distanceToCenterSquared = squaredDistance(
        circleGeometry.getCenter(),
        fromUserCoordinate(pointCoordinates, projection)
      );
      const distanceToCircumference = Math.sqrt(distanceToCenterSquared) - circleGeometry.getRadius();
      return distanceToCircumference * distanceToCircumference;
    }
  }
  const coordinate = fromUserCoordinate(pointCoordinates, projection);
  tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);
  tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection);
  return squaredDistanceToSegment(coordinate, tempSegment);
}
function closestOnSegmentData(pointCoordinates, segmentData, projection) {
  const geometry = segmentData.geometry;
  if (geometry.getType() === "Circle" && segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) {
    let circleGeometry = (
      /** @type {import("../geom/Circle.js").default} */
      geometry
    );
    const userProjection = getUserProjection();
    if (userProjection) {
      circleGeometry = circleGeometry.clone().transform(userProjection, projection);
    }
    return toUserCoordinate(
      circleGeometry.getClosestPoint(
        fromUserCoordinate(pointCoordinates, projection)
      ),
      projection
    );
  }
  const coordinate = fromUserCoordinate(pointCoordinates, projection);
  tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);
  tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection);
  return toUserCoordinate(
    closestOnSegment(coordinate, tempSegment),
    projection
  );
}
function getDefaultStyleFunction() {
  const style = createEditingStyle();
  return function(feature, resolution) {
    return style["Point"];
  };
}
var Modify_default = Modify;

// node_modules/ol/events/SnapEvent.js
var SnapEventType = {
  /**
   * Triggered upon snapping to vertex or edge
   * @event SnapEvent#snap
   * @api
   */
  SNAP: "snap",
  /**
   * Triggered if no longer snapped
   * @event SnapEvent#unsnap
   * @api
   */
  UNSNAP: "unsnap"
};
var SnapEvent = class extends Event_default {
  /**
   * @param {SnapEventType} type Type.
   * @param {Object} options Options.
   * @param {import("../coordinate.js").Coordinate} options.vertex The snapped vertex.
   * @param {import("../coordinate.js").Coordinate} options.vertexPixel The pixel of the snapped vertex.
   * @param {import("../Feature.js").default} options.feature The feature being snapped.
   * @param {Array<import("../coordinate.js").Coordinate>|null} options.segment Segment, or `null` if snapped to a vertex.
   */
  constructor(type, options) {
    super(type);
    this.vertex = options.vertex;
    this.vertexPixel = options.vertexPixel;
    this.feature = options.feature;
    this.segment = options.segment;
  }
};

// node_modules/ol/interaction/Snap.js
var GEOMETRY_SEGMENTERS = {
  /**
   * @param {import("../geom/Circle.js").default} geometry Geometry.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {Array<Segment>} Segments
   */
  Circle(geometry, projection) {
    let circleGeometry = geometry;
    const userProjection = getUserProjection();
    if (userProjection) {
      circleGeometry = circleGeometry.clone().transform(userProjection, projection);
    }
    const polygon = fromCircle(circleGeometry);
    if (userProjection) {
      polygon.transform(projection, userProjection);
    }
    return GEOMETRY_SEGMENTERS.Polygon(polygon);
  },
  /**
   * @param {import("../geom/GeometryCollection.js").default} geometry Geometry.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {Array<Segment>} Segments
   */
  GeometryCollection(geometry, projection) {
    const segments = [];
    const geometries = geometry.getGeometriesArray();
    for (let i = 0; i < geometries.length; ++i) {
      const segmenter = this[geometries[i].getType()];
      if (segmenter) {
        segments.push(segmenter(geometries[i], projection));
      }
    }
    return segments.flat();
  },
  /**
   * @param {import("../geom/LineString.js").default} geometry Geometry.
   * @return {Array<Segment>} Segments
   */
  LineString(geometry) {
    const segments = [];
    const coordinates = geometry.getFlatCoordinates();
    const stride = geometry.getStride();
    for (let i = 0, ii = coordinates.length - stride; i < ii; i += stride) {
      segments.push([
        coordinates.slice(i, i + 2),
        coordinates.slice(i + stride, i + stride + 2)
      ]);
    }
    return segments;
  },
  /**
   * @param {import("../geom/MultiLineString.js").default} geometry Geometry.
   * @return {Array<Segment>} Segments
   */
  MultiLineString(geometry) {
    const segments = [];
    const coordinates = geometry.getFlatCoordinates();
    const stride = geometry.getStride();
    const ends = geometry.getEnds();
    let offset = 0;
    for (let i = 0, ii = ends.length; i < ii; ++i) {
      const end = ends[i];
      for (let j = offset, jj = end - stride; j < jj; j += stride) {
        segments.push([
          coordinates.slice(j, j + 2),
          coordinates.slice(j + stride, j + stride + 2)
        ]);
      }
      offset = end;
    }
    return segments;
  },
  /**
   * @param {import("../geom/MultiPoint.js").default} geometry Geometry.
   * @return {Array<Segment>} Segments
   */
  MultiPoint(geometry) {
    const segments = [];
    const coordinates = geometry.getFlatCoordinates();
    const stride = geometry.getStride();
    for (let i = 0, ii = coordinates.length; i < ii; i += stride) {
      segments.push([coordinates.slice(i, i + 2)]);
    }
    return segments;
  },
  /**
   * @param {import("../geom/MultiPolygon.js").default} geometry Geometry.
   * @return {Array<Segment>} Segments
   */
  MultiPolygon(geometry) {
    const segments = [];
    const coordinates = geometry.getFlatCoordinates();
    const stride = geometry.getStride();
    const endss = geometry.getEndss();
    let offset = 0;
    for (let i = 0, ii = endss.length; i < ii; ++i) {
      const ends = endss[i];
      for (let j = 0, jj = ends.length; j < jj; ++j) {
        const end = ends[j];
        for (let k = offset, kk = end - stride; k < kk; k += stride) {
          segments.push([
            coordinates.slice(k, k + 2),
            coordinates.slice(k + stride, k + stride + 2)
          ]);
        }
        offset = end;
      }
    }
    return segments;
  },
  /**
   * @param {import("../geom/Point.js").default} geometry Geometry.
   * @return {Array<Segment>} Segments
   */
  Point(geometry) {
    return [[geometry.getFlatCoordinates().slice(0, 2)]];
  },
  /**
   * @param {import("../geom/Polygon.js").default} geometry Geometry.
   * @return {Array<Segment>} Segments
   */
  Polygon(geometry) {
    const segments = [];
    const coordinates = geometry.getFlatCoordinates();
    const stride = geometry.getStride();
    const ends = geometry.getEnds();
    let offset = 0;
    for (let i = 0, ii = ends.length; i < ii; ++i) {
      const end = ends[i];
      for (let j = offset, jj = end - stride; j < jj; j += stride) {
        segments.push([
          coordinates.slice(j, j + 2),
          coordinates.slice(j + stride, j + stride + 2)
        ]);
      }
      offset = end;
    }
    return segments;
  }
};
function getFeatureFromEvent(evt) {
  if (
    /** @type {import("../source/Vector.js").VectorSourceEvent} */
    evt.feature
  ) {
    return (
      /** @type {import("../source/Vector.js").VectorSourceEvent} */
      evt.feature
    );
  }
  if (
    /** @type {import("../Collection.js").CollectionEvent<import("../Feature.js").default>} */
    evt.element
  ) {
    return (
      /** @type {import("../Collection.js").CollectionEvent<import("../Feature.js").default>} */
      evt.element
    );
  }
  return null;
}
var tempSegment2 = [];
var tempExtents = [];
var tempSegmentData = [];
var Snap = class extends Pointer_default {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options) {
    options = options ? options : {};
    super({
      handleDownEvent: TRUE,
      stopDown: FALSE
    });
    this.on;
    this.once;
    this.un;
    this.source_ = options.source ? options.source : null;
    this.vertex_ = options.vertex !== void 0 ? options.vertex : true;
    this.edge_ = options.edge !== void 0 ? options.edge : true;
    this.intersection_ = options.intersection !== void 0 ? options.intersection : false;
    this.features_ = options.features ? options.features : null;
    this.featuresListenerKeys_ = [];
    this.featureChangeListenerKeys_ = {};
    this.indexedFeaturesExtents_ = {};
    this.pendingFeatures_ = {};
    this.pixelTolerance_ = options.pixelTolerance !== void 0 ? options.pixelTolerance : 10;
    this.rBush_ = new RBush_default();
    this.snapped_ = null;
    this.segmenters_ = Object.assign(
      {},
      GEOMETRY_SEGMENTERS,
      options.segmenters
    );
  }
  /**
   * Add a feature to the collection of features that we may snap to.
   * @param {import("../Feature.js").default} feature Feature.
   * @param {boolean} [register] Whether to listen to the feature change or not
   *     Defaults to `true`.
   * @api
   */
  addFeature(feature, register) {
    register = register !== void 0 ? register : true;
    const feature_uid = getUid(feature);
    const geometry = feature.getGeometry();
    if (geometry) {
      const segmenter = this.segmenters_[geometry.getType()];
      if (segmenter) {
        this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent(createEmpty());
        const segments = segmenter.call(
          this.segmenters_,
          geometry,
          this.getMap().getView().getProjection()
        );
        let segmentCount = segments.length;
        for (let i = 0; i < segmentCount; ++i) {
          const segment = segments[i];
          tempExtents[i] = boundingExtent(segment);
          tempSegmentData[i] = {
            feature,
            segment
          };
        }
        if (this.intersection_) {
          for (let j = 0, jj = segments.length; j < jj; ++j) {
            const segment = segments[j];
            if (segment.length === 1) {
              continue;
            }
            const extent = tempExtents[j];
            for (let k = 0, kk = j - 1; k < kk; ++k) {
              const otherSegment = segments[k];
              if (!intersects(extent, tempExtents[k])) {
                continue;
              }
              const intersection = getIntersectionPoint(segment, otherSegment);
              if (!intersection) {
                continue;
              }
              const intersectionSegment = [intersection];
              tempExtents[segmentCount] = boundingExtent(intersectionSegment);
              tempSegmentData[segmentCount++] = {
                feature,
                intersectionFeature: feature,
                segment: intersectionSegment
              };
            }
            const otherSegments = this.rBush_.getInExtent(tempExtents[j]);
            for (let k = 0, kk = otherSegments.length; k < kk; ++k) {
              const otherSegment = otherSegments[k].segment;
              if (otherSegment.length === 1) {
                continue;
              }
              const intersection = getIntersectionPoint(segment, otherSegment);
              if (!intersection) {
                continue;
              }
              const intersectionSegment = [intersection];
              tempExtents[segmentCount] = boundingExtent(intersectionSegment);
              tempSegmentData[segmentCount++] = {
                feature,
                intersectionFeature: otherSegments[k].feature,
                segment: intersectionSegment
              };
            }
          }
        }
        if (segmentCount === 1) {
          this.rBush_.insert(tempExtents[0], tempSegmentData[0]);
        } else {
          tempExtents.length = segmentCount;
          tempSegmentData.length = segmentCount;
          this.rBush_.load(tempExtents, tempSegmentData);
        }
      }
    }
    if (register) {
      if (this.featureChangeListenerKeys_[feature_uid]) {
        unlistenByKey(this.featureChangeListenerKeys_[feature_uid]);
      }
      this.featureChangeListenerKeys_[feature_uid] = listen(
        feature,
        EventType_default.CHANGE,
        this.handleFeatureChange_,
        this
      );
    }
  }
  /**
   * @return {import("../Collection.js").default<import("../Feature.js").default>|Array<import("../Feature.js").default>} Features.
   * @private
   */
  getFeatures_() {
    let features;
    if (this.features_) {
      features = this.features_;
    } else if (this.source_) {
      features = this.source_.getFeatures();
    }
    return features;
  }
  /**
   * Checks if two snap data sets are equal.
   * Compares the segment and the feature.
   *
   * @param {SnappedInfo} data1 The first snap data set.
   * @param {SnappedInfo} data2 The second snap data set.
   * @return {boolean} `true` if the data sets are equal, otherwise `false`.
   * @private
   */
  areSnapDataEqual_(data1, data2) {
    return data1.segment === data2.segment && data1.feature === data2.feature;
  }
  /**
   * @param {import("../MapBrowserEvent.js").default} evt Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @api
   * @override
   */
  handleEvent(evt) {
    const result = this.snapTo(evt.pixel, evt.coordinate, evt.map);
    if (result) {
      evt.coordinate = result.vertex.slice(0, 2);
      evt.pixel = result.vertexPixel;
      if (this.snapped_ && !this.areSnapDataEqual_(this.snapped_, result)) {
        this.dispatchEvent(new SnapEvent(SnapEventType.UNSNAP, this.snapped_));
      }
      this.snapped_ = {
        vertex: evt.coordinate,
        vertexPixel: evt.pixel,
        feature: result.feature,
        segment: result.segment
      };
      this.dispatchEvent(new SnapEvent(SnapEventType.SNAP, this.snapped_));
    } else if (this.snapped_) {
      this.dispatchEvent(new SnapEvent(SnapEventType.UNSNAP, this.snapped_));
      this.snapped_ = null;
    }
    return super.handleEvent(evt);
  }
  /**
   * @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent<import("../Feature.js").default>} evt Event.
   * @private
   */
  handleFeatureAdd_(evt) {
    const feature = getFeatureFromEvent(evt);
    if (feature) {
      this.addFeature(feature);
    }
  }
  /**
   * @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent<import("../Feature.js").default>} evt Event.
   * @private
   */
  handleFeatureRemove_(evt) {
    const feature = getFeatureFromEvent(evt);
    if (feature) {
      this.removeFeature(feature);
      delete this.pendingFeatures_[getUid(feature)];
    }
  }
  /**
   * @param {import("../events/Event.js").default} evt Event.
   * @private
   */
  handleFeatureChange_(evt) {
    const feature = (
      /** @type {import("../Feature.js").default} */
      evt.target
    );
    if (this.handlingDownUpSequence) {
      this.pendingFeatures_[getUid(feature)] = feature;
    } else {
      this.updateFeature_(feature);
    }
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} evt Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(evt) {
    const featuresToUpdate = Object.values(this.pendingFeatures_);
    if (featuresToUpdate.length) {
      for (const feature of featuresToUpdate) {
        this.updateFeature_(feature);
      }
      clear(this.pendingFeatures_);
    }
    return false;
  }
  /**
   * Remove a feature from the collection of features that we may snap to.
   * @param {import("../Feature.js").default} feature Feature
   * @param {boolean} [unlisten] Whether to unlisten to the feature change
   *     or not. Defaults to `true`.
   * @api
   */
  removeFeature(feature, unlisten) {
    const unregister = unlisten !== void 0 ? unlisten : true;
    const feature_uid = getUid(feature);
    const extent = this.indexedFeaturesExtents_[feature_uid];
    if (extent) {
      const rBush = this.rBush_;
      rBush.getInExtent(extent).forEach((node) => {
        if (feature === node.feature || feature === node.intersectionFeature) {
          rBush.remove(node);
        }
      });
    }
    if (unregister) {
      unlistenByKey(this.featureChangeListenerKeys_[feature_uid]);
      delete this.featureChangeListenerKeys_[feature_uid];
    }
  }
  /**
   * Remove the interaction from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../Map.js").default} map Map.
   * @override
   */
  setMap(map) {
    const currentMap = this.getMap();
    const keys = this.featuresListenerKeys_;
    let features = this.getFeatures_();
    if (!Array.isArray(features)) {
      features = features.getArray();
    }
    if (currentMap) {
      keys.forEach(unlistenByKey);
      keys.length = 0;
      this.rBush_.clear();
      Object.values(this.featureChangeListenerKeys_).forEach(unlistenByKey);
      this.featureChangeListenerKeys_ = {};
    }
    super.setMap(map);
    if (map) {
      if (this.features_) {
        keys.push(
          listen(
            this.features_,
            CollectionEventType_default.ADD,
            this.handleFeatureAdd_,
            this
          ),
          listen(
            this.features_,
            CollectionEventType_default.REMOVE,
            this.handleFeatureRemove_,
            this
          )
        );
      } else if (this.source_) {
        keys.push(
          listen(
            this.source_,
            VectorEventType_default.ADDFEATURE,
            this.handleFeatureAdd_,
            this
          ),
          listen(
            this.source_,
            VectorEventType_default.REMOVEFEATURE,
            this.handleFeatureRemove_,
            this
          )
        );
      }
      for (const feature of features) {
        this.addFeature(feature);
      }
    }
  }
  /**
   * @param {import("../pixel.js").Pixel} pixel Pixel
   * @param {import("../coordinate.js").Coordinate} pixelCoordinate Coordinate
   * @param {import("../Map.js").default} map Map.
   * @return {SnappedInfo|null} Snap result
   */
  snapTo(pixel, pixelCoordinate, map) {
    const projection = map.getView().getProjection();
    const projectedCoordinate = fromUserCoordinate(pixelCoordinate, projection);
    const box = toUserExtent(
      buffer(
        boundingExtent([projectedCoordinate]),
        map.getView().getResolution() * this.pixelTolerance_
      ),
      projection
    );
    const segments = this.rBush_.getInExtent(box);
    const segmentsLength = segments.length;
    if (segmentsLength === 0) {
      return null;
    }
    let closestVertex;
    let minSquaredDistance = Infinity;
    let closestFeature;
    let closestSegment = null;
    const squaredPixelTolerance = this.pixelTolerance_ * this.pixelTolerance_;
    const getResult = () => {
      if (!closestVertex) {
        return null;
      }
      const vertexPixel = map.getPixelFromCoordinate(closestVertex);
      const squaredPixelDistance = squaredDistance(pixel, vertexPixel);
      if (squaredPixelDistance > squaredPixelTolerance) {
        return null;
      }
      return {
        vertex: closestVertex,
        vertexPixel: [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])],
        feature: closestFeature,
        segment: closestSegment
      };
    };
    if (this.vertex_ || this.intersection_) {
      for (let i = 0; i < segmentsLength; ++i) {
        const segmentData = segments[i];
        if (segmentData.feature.getGeometry().getType() !== "Circle") {
          for (const vertex of segmentData.segment) {
            const tempVertexCoord = fromUserCoordinate(vertex, projection);
            const delta = squaredDistance(projectedCoordinate, tempVertexCoord);
            if (delta < minSquaredDistance && (this.intersection_ && segmentData.intersectionFeature || this.vertex_ && !segmentData.intersectionFeature)) {
              closestVertex = vertex;
              minSquaredDistance = delta;
              closestFeature = segmentData.feature;
            }
          }
        }
      }
      const result = getResult();
      if (result) {
        return result;
      }
    }
    if (this.edge_) {
      for (let i = 0; i < segmentsLength; ++i) {
        let vertex = null;
        const segmentData = segments[i];
        if (segmentData.feature.getGeometry().getType() === "Circle") {
          let circleGeometry = segmentData.feature.getGeometry();
          const userProjection = getUserProjection();
          if (userProjection) {
            circleGeometry = circleGeometry.clone().transform(userProjection, projection);
          }
          vertex = closestOnCircle(
            projectedCoordinate,
            /** @type {import("../geom/Circle.js").default} */
            circleGeometry
          );
        } else {
          const [segmentStart, segmentEnd] = segmentData.segment;
          if (segmentEnd) {
            tempSegment2[0] = fromUserCoordinate(segmentStart, projection);
            tempSegment2[1] = fromUserCoordinate(segmentEnd, projection);
            vertex = closestOnSegment(projectedCoordinate, tempSegment2);
          }
        }
        if (vertex) {
          const delta = squaredDistance(projectedCoordinate, vertex);
          if (delta < minSquaredDistance) {
            closestVertex = toUserCoordinate(vertex, projection);
            closestSegment = segmentData.feature.getGeometry().getType() === "Circle" ? null : segmentData.segment;
            minSquaredDistance = delta;
            closestFeature = segmentData.feature;
          }
        }
      }
      const result = getResult();
      if (result) {
        return result;
      }
    }
    return null;
  }
  /**
   * @param {import("../Feature.js").default} feature Feature
   * @private
   */
  updateFeature_(feature) {
    this.removeFeature(feature, false);
    this.addFeature(feature, false);
  }
};
var Snap_default = Snap;

// node_modules/ol/interaction/Translate.js
var TranslateEventType = {
  /**
   * Triggered upon feature translation start.
   * @event TranslateEvent#translatestart
   * @api
   */
  TRANSLATESTART: "translatestart",
  /**
   * Triggered upon feature translation.
   * @event TranslateEvent#translating
   * @api
   */
  TRANSLATING: "translating",
  /**
   * Triggered upon feature translation end.
   * @event TranslateEvent#translateend
   * @api
   */
  TRANSLATEEND: "translateend"
};
var TranslateEvent = class extends Event_default {
  /**
   * @param {TranslateEventType} type Type.
   * @param {Collection<Feature>} features The features translated.
   * @param {import("../coordinate.js").Coordinate} coordinate The event coordinate.
   * @param {import("../coordinate.js").Coordinate} startCoordinate The original coordinates before.translation started
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   */
  constructor(type, features, coordinate, startCoordinate, mapBrowserEvent) {
    super(type);
    this.features = features;
    this.coordinate = coordinate;
    this.startCoordinate = startCoordinate;
    this.mapBrowserEvent = mapBrowserEvent;
  }
};
var Translate = class extends Pointer_default {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options) {
    options = options ? options : {};
    super(
      /** @type {import("./Pointer.js").Options} */
      options
    );
    this.on;
    this.once;
    this.un;
    this.lastCoordinate_ = null;
    this.startCoordinate_ = null;
    this.features_ = options.features !== void 0 ? options.features : null;
    let layerFilter;
    if (options.layers && !this.features_) {
      if (typeof options.layers === "function") {
        layerFilter = options.layers;
      } else {
        const layers = options.layers;
        layerFilter = function(layer) {
          return layers.includes(layer);
        };
      }
    } else {
      layerFilter = TRUE;
    }
    this.layerFilter_ = layerFilter;
    this.filter_ = options.filter && !this.features_ ? options.filter : TRUE;
    this.hitTolerance_ = options.hitTolerance ? options.hitTolerance : 0;
    this.condition_ = options.condition ? options.condition : always;
    this.lastFeature_ = null;
    this.addChangeListener(
      Property_default.ACTIVE,
      this.handleActiveChanged_
    );
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(event) {
    if (!event.originalEvent || !this.condition_(event)) {
      return false;
    }
    this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
    if (!this.lastCoordinate_ && this.lastFeature_) {
      this.startCoordinate_ = event.coordinate;
      this.lastCoordinate_ = event.coordinate;
      this.handleMoveEvent(event);
      const features = this.features_ || new Collection_default([this.lastFeature_]);
      this.dispatchEvent(
        new TranslateEvent(
          TranslateEventType.TRANSLATESTART,
          features,
          event.coordinate,
          this.startCoordinate_,
          event
        )
      );
      return true;
    }
    return false;
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(event) {
    if (this.lastCoordinate_) {
      this.lastCoordinate_ = null;
      this.handleMoveEvent(event);
      const features = this.features_ || new Collection_default([this.lastFeature_]);
      this.dispatchEvent(
        new TranslateEvent(
          TranslateEventType.TRANSLATEEND,
          features,
          event.coordinate,
          this.startCoordinate_,
          event
        )
      );
      this.startCoordinate_ = null;
      return true;
    }
    return false;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @override
   */
  handleDragEvent(event) {
    if (this.lastCoordinate_) {
      const newCoordinate = event.coordinate;
      const projection = event.map.getView().getProjection();
      const newViewCoordinate = fromUserCoordinate(newCoordinate, projection);
      const lastViewCoordinate = fromUserCoordinate(
        this.lastCoordinate_,
        projection
      );
      const deltaX = newViewCoordinate[0] - lastViewCoordinate[0];
      const deltaY = newViewCoordinate[1] - lastViewCoordinate[1];
      const features = this.features_ || new Collection_default([this.lastFeature_]);
      const userProjection = getUserProjection();
      features.forEach(function(feature) {
        const geom = feature.getGeometry();
        if (userProjection) {
          geom.transform(userProjection, projection);
          geom.translate(deltaX, deltaY);
          geom.transform(projection, userProjection);
        } else {
          geom.translate(deltaX, deltaY);
        }
        feature.setGeometry(geom);
      });
      this.lastCoordinate_ = newCoordinate;
      this.dispatchEvent(
        new TranslateEvent(
          TranslateEventType.TRANSLATING,
          features,
          newCoordinate,
          this.startCoordinate_,
          event
        )
      );
    }
  }
  /**
   * Handle pointer move events.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @override
   */
  handleMoveEvent(event) {
    const elem = event.map.getViewport();
    if (this.featuresAtPixel_(event.pixel, event.map)) {
      elem.classList.remove(this.lastCoordinate_ ? "ol-grab" : "ol-grabbing");
      elem.classList.add(this.lastCoordinate_ ? "ol-grabbing" : "ol-grab");
    } else {
      elem.classList.remove("ol-grab", "ol-grabbing");
    }
  }
  /**
   * Tests to see if the given coordinates intersects any of our selected
   * features.
   * @param {import("../pixel.js").Pixel} pixel Pixel coordinate to test for intersection.
   * @param {import("../Map.js").default} map Map to test the intersection on.
   * @return {Feature} Returns the feature found at the specified pixel
   * coordinates.
   * @private
   */
  featuresAtPixel_(pixel, map) {
    return map.forEachFeatureAtPixel(
      pixel,
      (feature, layer) => {
        if (!(feature instanceof Feature_default) || !this.filter_(feature, layer)) {
          return void 0;
        }
        if (this.features_ && !this.features_.getArray().includes(feature)) {
          return void 0;
        }
        return feature;
      },
      {
        layerFilter: this.layerFilter_,
        hitTolerance: this.hitTolerance_
      }
    );
  }
  /**
   * Returns the Hit-detection tolerance.
   * @return {number} Hit tolerance in pixels.
   * @api
   */
  getHitTolerance() {
    return this.hitTolerance_;
  }
  /**
   * Hit-detection tolerance. Pixels inside the radius around the given position
   * will be checked for features.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @api
   */
  setHitTolerance(hitTolerance) {
    this.hitTolerance_ = hitTolerance;
  }
  /**
   * Remove the interaction from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../Map.js").default} map Map.
   * @override
   */
  setMap(map) {
    const oldMap = this.getMap();
    super.setMap(map);
    this.updateState_(oldMap);
  }
  /**
   * @private
   */
  handleActiveChanged_() {
    this.updateState_(null);
  }
  /**
   * @param {import("../Map.js").default} oldMap Old map.
   * @private
   */
  updateState_(oldMap) {
    let map = this.getMap();
    const active = this.getActive();
    if (!map || !active) {
      map = map || oldMap;
      if (map) {
        const elem = map.getViewport();
        elem.classList.remove("ol-grab", "ol-grabbing");
      }
    }
  }
};
var Translate_default = Translate;
export {
  DblClickDragZoom_default as DblClickDragZoom,
  DoubleClickZoom_default as DoubleClickZoom,
  DragAndDrop_default as DragAndDrop,
  DragBox_default as DragBox,
  DragPan_default as DragPan,
  DragRotate_default as DragRotate,
  DragRotateAndZoom_default as DragRotateAndZoom,
  DragZoom_default as DragZoom,
  Draw_default as Draw,
  Extent_default as Extent,
  Interaction_default as Interaction,
  KeyboardPan_default as KeyboardPan,
  KeyboardZoom_default as KeyboardZoom,
  Link_default as Link,
  Modify_default as Modify,
  MouseWheelZoom_default as MouseWheelZoom,
  PinchRotate_default as PinchRotate,
  PinchZoom_default as PinchZoom,
  Pointer_default as Pointer,
  Select_default as Select,
  Snap_default as Snap,
  Translate_default as Translate,
  defaults
};
//# sourceMappingURL=ol_interaction.js.map
