// import $ from 'jquery'
/**
 * 坐标转换
 * @author wanghai
 */
export const Coordtransform = {
  //定义一些常量
  x_PI: 3.14159265358979324 * 3000.0 / 180.0,
  PI: 3.1415926535897932384626,
  a: 6378245.0,
  ee: 0.00669342162296594323,
  /**
   * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
   * 即 百度 转 谷歌、高德
   * @param bd_lon
   * @param bd_lat
   * @returns {*[]}
   */
  bd09togcj02: function (bd_lon, bd_lat) {
    bd_lon = +bd_lon;
    bd_lat = +bd_lat;
    let x = bd_lon - 0.0065;
    let y = bd_lat - 0.006;
    let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_PI);
    let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_PI);
    let gg_lng = z * Math.cos(theta);
    let gg_lat = z * Math.sin(theta);
    return {
      x: gg_lng,
      y: gg_lat
    }
  },

  /**
   * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
   * 即谷歌、高德 转 百度
   * @param lng
   * @param lat
   * @returns {*[]}
   */
  gcj02tobd09: function (lng, lat) {
    lat = +lat;
    lng = +lng;
    let z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * this.x_PI);
    let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * this.x_PI);
    let bd_lng = z * Math.cos(theta) + 0.0065;
    let bd_lat = z * Math.sin(theta) + 0.006;
    return {
      x: bd_lng,
      y: bd_lat
    }
  },

  /**
   * WGS84转GCj02
   * @param lng
   * @param lat
   * @returns {*[]}
   */
  wgs84togcj02: function (lng, lat) {
    lat = +lat;
    lng = +lng;
    if (out_of_china(lng, lat)) {
      return {
        x: lng,
        y: lat
      };
    } else {
      let dlat = transformlat(lng - 105.0, lat - 35.0);
      let dlng = transformlng(lng - 105.0, lat - 35.0);
      let radlat = lat / 180.0 * this.PI;
      let magic = Math.sin(radlat);
      magic = 1 - this.ee * magic * magic;
      let sqrtmagic = Math.sqrt(magic);
      dlat = (dlat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtmagic) * this.PI);
      dlng = (dlng * 180.0) / (this.a / sqrtmagic * Math.cos(radlat) * this.PI);
      let mglat = lat + dlat;
      let mglng = lng + dlng;
      return {
        x: mglng,
        y: mglat
      }
    }
  },

  /**
   * GCJ02 转换为 WGS84
   * @param lng
   * @param lat
   * @returns {*[]}
   */
  gcj02towgs84: function (lng, lat) {
    lat = +lat;
    lng = +lng;
    if (out_of_china(lng, lat)) {
      return {
        x: lng,
        y: lat
      };
    } else {
      let dlat = transformlat(lng - 105.0, lat - 35.0);
      let dlng = transformlng(lng - 105.0, lat - 35.0);
      let radlat = lat / 180.0 * this.PI;
      let magic = Math.sin(radlat);
      magic = 1 - this.ee * magic * magic;
      let sqrtmagic = Math.sqrt(magic);
      dlat = (dlat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtmagic) * this.PI);
      dlng = (dlng * 180.0) / (this.a / sqrtmagic * Math.cos(radlat) * this.PI);
      let mglat = lat + dlat;
      let mglng = lng + dlng;
      return {
        x: lng * 2 - mglng,
        y: lat * 2 - mglat
      };
    }
  },

  transformlat: function (lng, lat) {
    lat = +lat;
    lng = +lng;
    let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math
      .sqrt(Math.abs(lng));
    ret += (20.0 * Math.sin(6.0 * lng * this.PI) + 20.0 * Math.sin(2.0 * lng * this.PI)) * 2.0 /
      3.0;
    ret += (20.0 * Math.sin(lat * this.PI) + 40.0 * Math.sin(lat / 3.0 * this.PI)) * 2.0 / 3.0;
    ret += (160.0 * Math.sin(lat / 12.0 * this.PI) + 320 * Math.sin(lat * this.PI / 30.0)) *
      2.0 / 3.0;
    return ret
  },

  transformlng: function (lng, lat) {
    lat = +lat;
    lng = +lng;
    let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math
      .abs(lng));
    ret += (20.0 * Math.sin(6.0 * lng * this.PI) + 20.0 * Math.sin(2.0 * lng * this.PI)) * 2.0 /
      3.0;
    ret += (20.0 * Math.sin(lng * this.PI) + 40.0 * Math.sin(lng / 3.0 * this.PI)) * 2.0 / 3.0;
    ret += (150.0 * Math.sin(lng / 12.0 * this.PI) + 300.0 * Math.sin(lng / 30.0 * this.PI)) *
      2.0 / 3.0;
    return ret
  },

  /**
   * 判断是否在国内，不在国内则不做偏移
   * @param lng
   * @param lat
   * @returns {boolean}
   */
  out_of_china: function (lng, lat) {
    lat = +lat;
    lng = +lng;
    // 纬度3.86~53.55,经度73.66~135.05
    return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
  }
};

/**
 * GetViewExtent获取当前视图范围
 * GetViewCenter获取当前视图中心点
 */
export const CesiumViewTool = (function () {
  function _() {}
  _.GetViewExtent = function (viewer) {
    let extent = {};
    let scene = viewer.scene;
    let ellipsoid = scene.globe.ellipsoid;
    let canvas = scene.canvas;
    let car3_lt = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(0, 0),
      ellipsoid); // canvas左上角
    let car3_rb = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(canvas.width, canvas
      .height), ellipsoid); // canvas右下角
    // 当canvas左上角和右下角全部在椭球体上
    if (car3_lt && car3_rb) {
      let carto_lt = ellipsoid.cartesianToCartographic(car3_lt);
      let carto_rb = ellipsoid.cartesianToCartographic(car3_rb);
      extent.xmin = Cesium.Math.toDegrees(carto_lt.longitude);
      extent.ymax = Cesium.Math.toDegrees(carto_lt.latitude);
      extent.xmax = Cesium.Math.toDegrees(carto_rb.longitude);
      extent.ymin = Cesium.Math.toDegrees(carto_rb.latitude);
    } else if (!car3_lt && car3_rb) { // 当canvas左上角不在但右下角在椭球体上
      let car3_lt2 = null;
      let yIndex = 0;
      let xIndex = 0;
      do {
        // 这里每次10像素递加，一是10像素相差不大，二是为了提高程序运行效率
        yIndex <= canvas.height ? yIndex += 10 : canvas.height;
        xIndex <= canvas.width ? xIndex += 10 : canvas.width;
        car3_lt2 = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(xIndex, yIndex),
          ellipsoid);
      } while (!car3_lt2);
      let carto_lt2 = ellipsoid.cartesianToCartographic(car3_lt2);
      let carto_rb2 = ellipsoid.cartesianToCartographic(car3_rb);
      extent.xmin = Cesium.Math.toDegrees(carto_lt2.longitude);
      extent.ymax = Cesium.Math.toDegrees(carto_lt2.latitude);
      extent.xmax = Cesium.Math.toDegrees(carto_rb2.longitude);
      extent.ymin = Cesium.Math.toDegrees(carto_rb2.latitude);
    } else if (car3_lt && !car3_rb) { // 当canvas左上角在但右下角不在椭球体上
      let car3_rb2 = null;
      yIndex = canvas.height;
      xIndex = canvas.width;
      do {
        // 这里每次10像素递加，一是10像素相差不大，二是为了提高程序运行效率
        yIndex >= 10 ? yIndex -= 10 : 10;
        xIndex >= 10 ? xIndex -= 10 : 10;
        car3_rb2 = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(yIndex, yIndex),
          ellipsoid);
      } while (!car3_rb2);
      let carto_lt2 = ellipsoid.cartesianToCartographic(car3_lt);
      let carto_rb2 = ellipsoid.cartesianToCartographic(car3_rb2);
      extent.xmin = Cesium.Math.toDegrees(carto_lt2.longitude);
      extent.ymax = Cesium.Math.toDegrees(carto_lt2.latitude);
      extent.xmax = Cesium.Math.toDegrees(carto_rb2.longitude);
      extent.ymin = Cesium.Math.toDegrees(carto_rb2.latitude);
    } else if (!car3_lt && !car3_rb) {
      let car3_lt2 = null;
      yIndex = 0;
      xIndex = 0;
      do {
        // 这里每次10像素递加，一是10像素相差不大，二是为了提高程序运行效率
        yIndex <= canvas.height ? yIndex += 10 : canvas.height;
        xIndex <= canvas.width ? xIndex += 10 : canvas.width;
        car3_lt2 = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(xIndex, yIndex),
          ellipsoid);
      } while (!car3_lt2);
      let car3_rb2 = null;
      let yIndex = canvas.height;
      let xIndex = canvas.width;
      do {
        // 这里每次10像素递加，一是10像素相差不大，二是为了提高程序运行效率
        yIndex >= 10 ? yIndex -= 10 : 10;
        xIndex >= 10 ? xIndex -= 10 : 10;
        car3_rb2 = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(yIndex, yIndex),
          ellipsoid);
      } while (!car3_rb2);
      let carto_lt2 = ellipsoid.cartesianToCartographic(car3_lt2);
      let carto_rb2 = ellipsoid.cartesianToCartographic(car3_rb2);
      extent.xmin = Cesium.Math.toDegrees(carto_lt2.longitude);
      extent.ymax = Cesium.Math.toDegrees(carto_lt2.latitude);
      extent.xmax = Cesium.Math.toDegrees(carto_rb2.longitude);
      extent.ymin = Cesium.Math.toDegrees(carto_rb2.latitude);
    }
    // 获取高度
    extent.height = Math.ceil(viewer.camera.positionCartographic.height);
    return extent;
  }
  _.GetViewCenter = function (viewer) {
    let result = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(viewer.canvas.clientWidth /
      2, viewer.canvas.clientHeight / 2));
    if (result) {} else {
      return null;
    }
    let curPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(result);
    let lon = curPosition.longitude * 180 / Math.PI;
    let lat = curPosition.latitude * 180 / Math.PI;
    let height = viewer.camera.positionCartographic.height;
    return {
      lon: lon,
      lat: lat,
      height: height
    };
  }
  return _;
})();

/**
 * covert canvas to image
 * and save the image file
 */
export const Canvas2Image = function () {

  // check if support sth.
  let $support = function () {
    let canvas = document.createElement('canvas'),
      ctx = canvas.getContext('2d');

    return {
      canvas: !!ctx,
      imageData: !!ctx.getImageData,
      dataURL: !!canvas.toDataURL,
      btoa: !!window.btoa
    };
  }();

  let downloadMime = 'image/octet-stream';

  function scaleCanvas(canvas, width, height) {
    let w = canvas.width,
      h = canvas.height;
    if (width == undefined) {
      width = w;
    }
    if (height == undefined) {
      height = h;
    }

    let retCanvas = document.createElement('canvas');
    let retCtx = retCanvas.getContext('2d');
    retCanvas.width = width;
    retCanvas.height = height;
    retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height);
    return retCanvas;
  }

  function getDataURL(canvas, type, width, height) {
    canvas = scaleCanvas(canvas, width, height);
    return canvas.toDataURL(type);
  }

  function saveFile(strData) {
    document.location.href = strData;
  }

  function genImage(strData) {
    let img = document.createElement('img');
    img.src = strData;
    return img;
  }

  function fixType(type) {
    type = type.toLowerCase().replace(/jpg/i, 'jpeg');
    let r = type.match(/png|jpeg|bmp|gif/)[0];
    return 'image/' + r;
  }

  function encodeData(data) {
    if (!window.btoa) {
      throw 'btoa undefined'
    }
    let str = '';
    if (typeof data == 'string') {
      str = data;
    } else {
      for (let i = 0; i < data.length; i++) {
        str += String.fromCharCode(data[i]);
      }
    }

    return btoa(str);
  }

  function getImageData(canvas) {
    let w = canvas.width,
      h = canvas.height;
    return canvas.getContext('2d').getImageData(0, 0, w, h);
  }

  function makeURI(strData, type) {
    return 'data:' + type + ';base64,' + strData;
  }


  /**
   * create bitmap image
   * 按照规则生成图片响应头和响应体
   */
  let genBitmapImage = function (oData) {

    //
    // BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
    // BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
    //

    let biWidth = oData.width;
    let biHeight = oData.height;
    let biSizeImage = biWidth * biHeight * 3;
    let bfSize = biSizeImage + 54; // total header size = 54 bytes

    //
    //  typedef struct tagBITMAPFILEHEADER {
    //  	WORD bfType;
    //  	DWORD bfSize;
    //  	WORD bfReserved1;
    //  	WORD bfReserved2;
    //  	DWORD bfOffBits;
    //  } BITMAPFILEHEADER;
    //
    let BITMAPFILEHEADER = [
      // WORD bfType -- The file type signature; must be "BM"
      0x42, 0x4D,
      // DWORD bfSize -- The size, in bytes, of the bitmap file
      bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff,
      // WORD bfReserved1 -- Reserved; must be zero
      0, 0,
      // WORD bfReserved2 -- Reserved; must be zero
      0, 0,
      // DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
      54, 0, 0, 0
    ];

    //
    //  typedef struct tagBITMAPINFOHEADER {
    //  	DWORD biSize;
    //  	LONG  biWidth;
    //  	LONG  biHeight;
    //  	WORD  biPlanes;
    //  	WORD  biBitCount;
    //  	DWORD biCompression;
    //  	DWORD biSizeImage;
    //  	LONG  biXPelsPerMeter;
    //  	LONG  biYPelsPerMeter;
    //  	DWORD biClrUsed;
    //  	DWORD biClrImportant;
    //  } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
    //
    let BITMAPINFOHEADER = [
      // DWORD biSize -- The number of bytes required by the structure
      40, 0, 0, 0,
      // LONG biWidth -- The width of the bitmap, in pixels
      biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff,
      // LONG biHeight -- The height of the bitmap, in pixels
      biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff,
      // WORD biPlanes -- The number of planes for the target device. This value must be set to 1
      1, 0,
      // WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
      // has a maximum of 2^24 colors (16777216, Truecolor)
      24, 0,
      // DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
      0, 0, 0, 0,
      // DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
      biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >>
      24 & 0xff,
      // LONG biXPelsPerMeter, unused
      0, 0, 0, 0,
      // LONG biYPelsPerMeter, unused
      0, 0, 0, 0,
      // DWORD biClrUsed, the number of color indexes of palette, unused
      0, 0, 0, 0,
      // DWORD biClrImportant, unused
      0, 0, 0, 0
    ];

    let iPadding = (4 - ((biWidth * 3) % 4)) % 4;

    let aImgData = oData.data;

    let strPixelData = '';
    let biWidth4 = biWidth << 2;
    let y = biHeight;
    let fromCharCode = String.fromCharCode;

    do {
      let iOffsetY = biWidth4 * (y - 1);
      let strPixelRow = '';
      for (let x = 0; x < biWidth; x++) {
        let iOffsetX = x << 2;
        strPixelRow += fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) +
          fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) +
          fromCharCode(aImgData[iOffsetY + iOffsetX]);
      }

      for (let c = 0; c < iPadding; c++) {
        strPixelRow += String.fromCharCode(0);
      }

      strPixelData += strPixelRow;
    } while (--y);

    let strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(
      strPixelData);

    return strEncoded;
  };

  /**
   * saveAsImage
   * @param canvasElement
   * @param {String} image type
   * @param {Number} [optional] png width
   * @param {Number} [optional] png height
   */
  let saveAsImage = function (canvas, width, height, type) {
    if ($support.canvas && $support.dataURL) {
      if (typeof canvas == "string") {
        canvas = document.getElementById(canvas);
      }
      if (type == undefined) {
        type = 'png';
      }
      type = fixType(type);
      if (/bmp/.test(type)) {
        let data = getImageData(scaleCanvas(canvas, width, height));
        let strData = genBitmapImage(data);
        saveFile(makeURI(strData, downloadMime));
      } else {
        let strData = getDataURL(canvas, type, width, height);
        saveFile(strData.replace(type, downloadMime));
      }
    }
  };

  let convertToImage = function (canvas, width, height, type) {
    if ($support.canvas && $support.dataURL) {
      if (typeof canvas == "string") {
        canvas = document.getElementById(canvas);
      }
      if (type == undefined) {
        type = 'png';
      }
      type = fixType(type);

      if (/bmp/.test(type)) {
        let data = getImageData(scaleCanvas(canvas, width, height));
        let strData = genBitmapImage(data);
        return genImage(makeURI(strData, 'image/bmp'));
      } else {
        let strData = getDataURL(canvas, type, width, height);
        return genImage(strData);
      }
    }
  };



  return {
    saveAsImage: saveAsImage,
    saveAsPNG: function (canvas, width, height) {
      return saveAsImage(canvas, width, height, 'png');
    },
    saveAsJPEG: function (canvas, width, height) {
      return saveAsImage(canvas, width, height, 'jpeg');
    },
    saveAsGIF: function (canvas, width, height) {
      return saveAsImage(canvas, width, height, 'gif');
    },
    saveAsBMP: function (canvas, width, height) {
      return saveAsImage(canvas, width, height, 'bmp');
    },

    convertToImage: convertToImage,
    convertToPNG: function (canvas, width, height) {
      return convertToImage(canvas, width, height, 'png');
    },
    convertToJPEG: function (canvas, width, height) {
      return convertToImage(canvas, width, height, 'jpeg');
    },
    convertToGIF: function (canvas, width, height) {
      return convertToImage(canvas, width, height, 'gif');
    },
    convertToBMP: function (canvas, width, height) {
      return convertToImage(canvas, width, height, 'bmp');
    }
  };

}();


/**
 * 创建提示工具
 */
export const createTooltip = function (frameDiv) {

  let tooltip = function (frameDiv) {

    let div = document.createElement('DIV');
    div.className = "twipsy right";

    let arrow = document.createElement('DIV');
    arrow.className = "twipsy-arrow";
    div.appendChild(arrow);

    let title = document.createElement('DIV');
    title.className = "twipsy-inner";
    div.appendChild(title);

    this._div = div;
    this._title = title;
    this.message = '';

    // add to frame div and display coordinates
    frameDiv.appendChild(div);
    let that = this;
    div.onmousemove = function (evt) {
      that.showAt({
        x: evt.clientX,
        y: evt.clientY
      }, that.message);
    };
  };

  tooltip.prototype.setVisible = function (visible) {
    this._div.style.display = visible ? 'block' : 'none';
  };

  tooltip.prototype.showAt = function (position, message) {
    if (position && message) {
      this.setVisible(true);
      this._title.innerHTML = message;
      this._div.style.left = position.x + 30 + "px";
      this._div.style.top = (position.y - this._div.clientHeight) + "px";
      this.message = message;
    }
  };

  tooltip.prototype.remove = function () {
    $(this._div).remove();
  };

  return new tooltip(frameDiv);
}

/**
 * 自定义气泡窗体框
 */
export const InfoWindow = function (frameDiv, viewer) {
  let infowindow = function (frameDiv, viewer) {
    let div = document.createElement('DIV');
    div.className = "bubblewindow";
    div.style.display = "none";

    let title = document.createElement('DIV');
    title.className = "bubbletitle";
    div.appendChild(title);

    let close = document.createElement('DIV');
    close.className = "bubbleclose";
    div.appendChild(close);

    let content = document.createElement('DIV');
    content.className = "bubblecontent";
    div.appendChild(content);

    this._div = div;
    this._title = title;
    this._close = close;
    this._content = content;
    this._viewer = viewer;
    this._scenePosition = null;
    this._handler = null;
    this._removeCallback = null;
    frameDiv.appendChild(div);

    $(close).off("click").on("click", function (e) {
      this._div.style.display = 'none';
    }.bind(this))
    this._removeCallback = viewer.scene.postRender.addEventListener(this._changePosition.bind(
      this));
    this._handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
    this._handler.setInputAction(this._changeScenePosition.bind(this), Cesium
      .ScreenSpaceEventType.LEFT_CLICK);
  };

  infowindow.prototype._changeScenePosition = function (e) {
    let position = this._viewer.scene.pickPosition(e.position);
    if (!position) {
      position = Cesium.Cartesian3.fromDegrees(0, 0, 0);
    }
    this._scenePosition = position;
  };

  infowindow.prototype._changePosition = function () {
    if (this._scenePosition) {
      let canvasHeight = this._viewer.scene.canvas.clientHeight; //canvas实际高度
      let windowPosition = new Cesium.Cartesian2();
      Cesium.SceneTransforms.wgs84ToWindowCoordinates(this._viewer.scene, this._scenePosition,
        windowPosition);
      this._div.style.bottom = (canvasHeight - windowPosition.y + 14 + 5) + 'px';
      let left = this._div.clientWidth / 2;
      this._div.style.left = (windowPosition.x - left) + 'px';
      this._div.style.visibility = "visible";
    }
  };

  infowindow.prototype.show = function (title, content) {
    $(this._content).empty();
    $(this._title).empty();
    if (content)
      this._setContent(content);
    if (title)
      this._setTitle(title);

    this._div.style.display = 'block';
  };

  infowindow.prototype.hide = function () {
    this._div.style.display = 'none';
  };

  infowindow.prototype.remove = function () {
    //this._viewer.scene.postRender.removeEventListener(this._changePosition.bind(this));
    if (this._removeCallback)
      this._removeCallback();
    if (this._handler != null && !this._handler.isDestroyed())
      this._handler.destroy();
    $(this._div).remove();
  };

  infowindow.prototype._setContent = function (contentDiv) {
    $(this._content).empty().append(contentDiv);
  };

  infowindow.prototype._setTitle = function (title) {
    $(this._title).empty().append(title);
  };
  //清除点击事件
  infowindow.prototype._setHandler = function (isSet) {
    if (isSet) {

      this._handler.setInputAction(this._changeScenePosition.bind(this), Cesium
        .ScreenSpaceEventType.LEFT_CLICK);

    } else {
      this._handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }
  };

  return new infowindow(frameDiv, viewer);
}

/**
 * Cesium对象转换为SuperMap点、线、面对象
 */
export const CesiumToSuperMap = {
  convertPoint: function (Cesium, SuperMap, point) {
    if (!Cesium || !SuperMap || !point) {
      return undefined;
    }
    let lonlatPoint = Cesium.Cartographic.fromCartesian(point);
    let x = Cesium.Math.toDegrees(lonlatPoint.longitude);
    let y = Cesium.Math.toDegrees(lonlatPoint.latitude);
    if (x && y) {
      return new SuperMap.Geometry.Point(x, y);
    }
    return undefined;
  },
  convertPolyline: function (Cesium, SuperMap, polyline) {
    if (!Cesium || !SuperMap || !polyline) {
      throw undefined;
    }
    let points = polyline.positions;
    if (points && points instanceof Array && points.length >= 2) {
      let arr = [];
      for (let i = 0, j = points.length; i < j; i++) {
        let point = this.convertPoint(Cesium, SuperMap, points[i]);
        if (point) {
          arr.push(point);
        }
      }
      return new SuperMap.Geometry.LineString(arr);
    }
    return undefined;
  },
  convertPolygon: function (Cesium, SuperMap, polygon) {
    if (!Cesium || !SuperMap || !polygon) {
      throw undefined;
    }
    let points = polygon.positions;
    if (points && points instanceof Array && points.length >= 3) {
      let arr = [];
      for (let i = 0, j = points.length; i < j; i++) {
        let point = this.convertPoint(Cesium, SuperMap, points[i]);
        if (point) {
          arr.push(point);
        }
      }
      let linearRing = new SuperMap.Geometry.LinearRing(arr);
      return new SuperMap.Geometry.Polygon(linearRing);
    }
    return undefined;
  },
  convertDirPolygon: function (Cesium, SuperMap, polygon) {
    if (!Cesium || !SuperMap || !polygon) {
      throw undefined;
    }
    let points = polygon.positions;
    if (points && points instanceof Array && points.length >= 3) {
      let arr = [];
      for (let i = 0, j = points.length; i < j; i++) {
        let point = new SuperMap.Geometry.Point(points[i][0], points[i][1]);
        if (point) {
          arr.push(point);
        }
      }
      let linearRing = new SuperMap.Geometry.LinearRing(arr);
      return new SuperMap.Geometry.Polygon(linearRing);
    }
    return undefined;
  }
};

/**
 * SuperMap对象转换为Cesium对象
 */
export const SuperMapToCesium = {
  geometryToEntity: function (Cesium, SuperMap, geometry) {
    let className = geometry.CLASS_NAME;
    if (className == 'SuperMap.Geometry.MultiPolygon') {
      return this.multipolygonToEntities(Cesium, SuperMap, geometry);
    } else if (className == 'SuperMap.Geometry.Polygon') {
      return [this.polygonToEntity(Cesium, SuperMap, geometry)];
    }
    return undefined;
  },
  polygonToEntity: function (Cesium, SuperMap, geometry) {
    let hierarchy = {};
    for (let i = 0, j = geometry.components.length; i < j; i++) {
      if (i == 0) {
        hierarchy.positions = this.GeometrytoDegreesArray(Cesium, SuperMap, geometry.components[
          i]);
      } else {
        if (!hierarchy.holes) {
          hierarchy.holes = [];
        }
        hierarchy.holes.push({
          positions: this.GeometrytoDegreesArray(Cesium, SuperMap, geometry.components[i])
        });
      }
    }
    return new Cesium.Entity({
      polygon: {
        hierarchy: hierarchy,
        material: Cesium.Color.BLUE.withAlpha(0.5)
      },
      depthTestEnabled: false
    });

  },
  multipolygonToEntities: function (Cesium, SuperMap, geometry) {
    let components = geometry.components;
    let resultEntities = [];
    let entity;
    for (let item in components) {
      entity = this.polygonToEntity(Cesium, SuperMap, components[item]);
      resultEntities.push(entity);
    }
    return resultEntities;
  },
  GeometrytoDegreesArray: function (Cesium, SuperMap, geometry) {
    let vertices = geometry.getVertices();
    let degreesArr = [];
    for (let o in vertices) {
      degreesArr.push(vertices[o].x, vertices[o].y);
    }
    return Cesium.Cartesian3.fromDegreesArray(degreesArr);
  }
};

/**
 * 需要转换投影
 */
export const PrjCesiumToSuperMap = {
  convertPoint: function (Cesium, SuperMap, point) {
    if (!Cesium || !SuperMap || !point) {
      return undefined;
    }
    let lonlatPoint = Cesium.Cartographic.fromCartesian(point);
    let pt = new SuperMap.LonLat(Cesium.Math.toDegrees(lonlatPoint.longitude), Cesium.Math
      .toDegrees(lonlatPoint.latitude));
    const CRS_4544 = new L.Proj.CRS('EPSG:4544', {
      def: '+proj=tmerc +lat_0=0 +lon_0=105 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs'
    });
    let center_latLng = L.latLng(pt.lat, pt.lon);
    let GcsObj = CRS_4544.project(center_latLng);
    let x = GcsObj.x;
    let y = GcsObj.y;

    if (x && y) {
      return new SuperMap.Geometry.Point(x, y);
    }
    return undefined;
  },
  convertPolyline: function (Cesium, SuperMap, polyline) {
    if (!Cesium || !SuperMap || !polyline) {
      throw undefined;
    }
    let points = polyline.positions;
    if (points && points instanceof Array && points.length >= 2) {
      let arr = [];
      for (let i = 0, j = points.length; i < j; i++) {
        let point = this.convertPoint(Cesium, SuperMap, points[i]);
        if (point) {
          arr.push(point);
        }
      }
      return new SuperMap.Geometry.LineString(arr);
    }
    return undefined;
  },
  convertPolygon: function (Cesium, SuperMap, polygon) {
    if (!Cesium || !SuperMap || !polygon) {
      throw undefined;
    }
    let points = polygon.positions;
    if (points && points instanceof Array && points.length >= 3) {
      let arr = [];
      for (let i = 0, j = points.length; i < j; i++) {
        let point = this.convertPoint(Cesium, SuperMap, points[i]);
        if (point) {
          arr.push(point);
        }
      }
      let linearRing = new SuperMap.Geometry.LinearRing(arr);
      return new SuperMap.Geometry.Polygon(linearRing);
    }
    return undefined;
  },
  wgsToGcs: function (Cesium, SuperMap, LonLat) {
    if (!Cesium || !SuperMap || LonLat.length != 2) {
      return undefined;
    }
    const CRS_4544 = new L.Proj.CRS('EPSG:4544', {
      def: '+proj=tmerc +lat_0=0 +lon_0=105 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs'
    });
    let center_latLng = L.latLng(LonLat[1], LonLat[0]);
    let GcsObj = CRS_4544.project(center_latLng);
    let x = GcsObj.x;
    let y = GcsObj.y;
    if (!isNaN(x) && !isNaN(y)) {
      return [x, y];
    }
    return undefined;
  },
  wgsToGcsXY: function (Cesium, SuperMap, LonLat) {
    if (!Cesium || !SuperMap || LonLat.length != 2) {
      return undefined;
    }
    const CRS_4544 = new L.Proj.CRS('EPSG:4544', {
      def: '+proj=tmerc +lat_0=0 +lon_0=105 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs'
    });
    let center_latLng = L.latLng(LonLat[1], LonLat[0]);
    return CRS_4544.project(center_latLng);
  },
  gcsToWgs: function (Cesium, SuperMap, LonLat) {
    if (!Cesium || !SuperMap || LonLat.length != 2) {
      return undefined;
    }
    const CRS_4544 = new L.Proj.CRS('EPSG:4544', {
      def: '+proj=tmerc +lat_0=0 +lon_0=105 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs'
    });
    let point_old = new L.Point(LonLat[0], LonLat[1]);
    let point_new = CRS_4544.unproject(point_old);
    let x = point_new.lng;
    let y = point_new.lat;
    if (x && y) {
      return [x, y];
    }
    return undefined;
  }
};

/**
 * 管线分析基本工具集合
 * @author wanghai
 */
export const PipeAnalysisTool = {
  /**
   * 判断两管线是否相交
   * @param sourcegeometry 判断管线
   * @param comparegeometry 比较管线
   * @returns {crossPoint:{x:x,y:y},iscross:Boolean(true相交，false不相交)}
   */
  IsOrNotIntersect: function (sourcegeometry, comparegeometry) {
    let crossPt = {
      x: 0,
      y: 0
    };
    let wgssourcePoint1 = sourcegeometry.components[0];
    let wgssourcePoint2 = sourcegeometry.components[1];
    let wgscomparePoint1 = comparegeometry.components[0];
    let wgscomparePoint2 = comparegeometry.components[1];
    let isCover = this.IsPointsCover([wgssourcePoint1, wgssourcePoint2, wgscomparePoint1,
      wgscomparePoint2
    ]);
    if (isCover)
      return {
        crossPoint: crossPt,
        iscross: true
      };
    let sourcePoint1 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [wgssourcePoint1.x,
      wgssourcePoint1.y
    ]);
    let sourcePoint2 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [wgssourcePoint2.x,
      wgssourcePoint2.y
    ]);
    let comparePoint1 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [wgscomparePoint1.x,
      wgscomparePoint1.y
    ]);
    let comparePoint2 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [wgscomparePoint2.x,
      wgscomparePoint2.y
    ]);
    let a1 = sourcePoint2.y - sourcePoint1.y;
    let b1 = sourcePoint1.x - sourcePoint2.x;
    let c1 = sourcePoint1.x * sourcePoint2.y - sourcePoint2.x * sourcePoint1.y;
    let a2 = comparePoint2.y - comparePoint1.y;
    let b2 = comparePoint1.x - comparePoint2.x;
    let c2 = comparePoint1.x * comparePoint2.y - comparePoint2.x * comparePoint1.y;
    let det = a1 * b2 - a2 * b1;
    if (det == 0)
      return {
        crossPoint: crossPt,
        iscross: false
      };
    let x = (c1 * b2 - c2 * b1) / det;
    let y = (a1 * c2 - a2 * c1) / det;
    if ((Math.abs(x - (sourcePoint1.x + sourcePoint2.x) / 2) <= Math.abs(sourcePoint2.x -
        sourcePoint1.x) / 2) &&
      (Math.abs(y - (sourcePoint1.y + sourcePoint2.y) / 2) <= Math.abs(sourcePoint2.y -
        sourcePoint1.y) / 2) &&
      (Math.abs(x - (comparePoint1.x + comparePoint2.x) / 2) <= Math.abs(comparePoint2.x -
        comparePoint1.x) / 2) &&
      (Math.abs(y - (comparePoint1.y + comparePoint2.y) / 2) <= Math.abs(comparePoint2.y -
        comparePoint1.y) / 2)) {
      crossPt.x = x;
      crossPt.y = y;
      return {
        crossPoint: crossPt,
        iscross: true
      };
    }
    return {
      crossPoint: crossPt,
      iscross: false
    };
  },
  /**
   * 判断管线两点是否有重合点
   * @param points
   * @returns Boolean(true重合，false不重合)
   */
  IsPointsCover: function (points) {
    for (let i = 0; i < points.length - 1; i++) {
      {
        let point1 = points[i];
        for (let j = i + 1; j < points.length; j++) {
          let point2 = points[j];
          if (point1.x == point2.x && point1.y == point2.y)
            return true;
        }
      }
    }
    return false;
  },
  /**
   * 计算最短水平距离(使用外壁最小距离)
   * @param sourcegeometry 管线图形
   * @param comparegeometry 比较管线图形
   * @param sdiameter 管径，单位：mm
   * @param cdiameter 比较管线管径，单位：mm
   */
  GetShortestDistance: function (sourcegeometry, comparegeometry, sdiameter, cdiameter) {
    let sourcePoint1 = sourcegeometry.components[0];
    let sourcePoint2 = sourcegeometry.components[1];
    let comparePoint1 = comparegeometry.components[0];
    let comparePoint2 = comparegeometry.components[1];
    let sd = 0,
      cd = 0;
    if (sdiameter.indexOf("X") > 0) {
      sd = sdiameter.split("X")[0];
    } else if (sdiameter.indexOf("*") > 0) {
      sd = sdiameter.split("*")[0];
    } else
      sd = sdiameter;

    if (cdiameter.indexOf("X") > 0) {
      cd = cdiameter.split("X")[0];
    } else if (cdiameter.indexOf("*") > 0) {
      cd = cdiameter.split("*")[0];
    } else
      cd = cdiameter;
    let s_cdiameter = sd / 2000.0 + cd / 2000.0;
    let distances = [];
    comparePoint1 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [comparePoint1.x,
      comparePoint1.y
    ]);
    comparePoint2 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [comparePoint2.x,
      comparePoint2.y
    ]);
    sourcePoint1 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [sourcePoint1.x,
      sourcePoint1.y
    ]);
    sourcePoint2 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [sourcePoint2.x,
      sourcePoint2.y
    ]);
    let distance1 = this.GetPointToLineDistance(comparePoint1, sourcePoint1, sourcePoint2);
    distances.push((distance1 - s_cdiameter).toFixed(4));
    let distance2 = this.GetPointToLineDistance(comparePoint2, sourcePoint1, sourcePoint2);
    distances.push((distance2 - s_cdiameter).toFixed(4));
    let distance3 = this.GetPointToLineDistance(sourcePoint1, comparePoint1, comparePoint2);
    distances.push((distance1 - s_cdiameter).toFixed(4));
    let distance4 = this.GetPointToLineDistance(sourcePoint2, comparePoint1, comparePoint2);
    distances.push((distance1 - s_cdiameter).toFixed(4));
    return Math.min.apply(Math, distances);
  },
  /**
   * 以参考对象作为线，比较对象端点作为求取点
   */
  GetPointToLineDistance: function (Point, LinePointa, LinePointb) {
    let cross = (LinePointb.x - LinePointa.x) * (Point.x - LinePointa.x) + (LinePointb.y -
      LinePointa.y) * (Point.y - LinePointa.y);
    if (cross <= 0)
      return Math.sqrt((Point.x - LinePointa.x) * (Point.x - LinePointa.x) + (Point.y -
        LinePointa.y) * (Point.y - LinePointa.y));

    let d2 = (LinePointb.x - LinePointa.x) * (LinePointb.x - LinePointa.x) + (LinePointb.y -
      LinePointa.y) * (LinePointb.y - LinePointa.y);
    if (cross >= d2)
      return Math.sqrt((Point.x - LinePointb.x) * (Point.x - LinePointb.x) + (Point.y -
        LinePointb.y) * (Point.y - LinePointb.y));

    let r = cross / d2;
    let px = LinePointa.x + (LinePointb.x - LinePointa.x) * r;
    let py = LinePointa.y + (LinePointb.y - LinePointa.y) * r;
    return Math.sqrt((Point.x - px) * (Point.x - px) + (py - Point.y) * (py - Point.y));
  },
  /**
   * 获交点深
   */
  GetCrossPointDepth: function (point, geometry, startdepth, enddepth) {
    let wgsgeometryPoint1 = geometry.components[0];
    let wgsgeometryPoint2 = geometry.components[1];
    let geometryPoint1 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [wgsgeometryPoint1.x,
      wgsgeometryPoint1.y
    ]);
    let geometryPoint2 = PrjCesiumToSuperMap.wgsToGcsXY(Cesium, SuperMap, [wgsgeometryPoint2.x,
      wgsgeometryPoint2.y
    ]);
    let lineLength = Math.sqrt(Math.pow((geometryPoint1.x - geometryPoint2.x), 2) + Math.pow((
      geometryPoint1.y - geometryPoint2.y), 2));
    let pointLength = Math.sqrt(Math.pow((geometryPoint1.x - point.x), 2) + Math.pow((
      geometryPoint1.y - point.y), 2));
    let elevation;
    if (lineLength != 0) {
      elevation = (pointLength / lineLength) * (startdepth - enddepth);
    }
    return Math.min.apply(Math, [startdepth, enddepth]) + elevation;
  },
  /**
   * 计算最短垂直距离(使用外壁最小距离)
   * @param sourceElevation 管线高度
   * @param compareElevation 比较管线高度
   * @param sdiameter 管径，单位：mm
   * @param cdiameter 比较管线管径，单位：mm
   */
  GetShortestVDistance: function (sourceElevation, compareElevation, sdiameter, cdiameter) {
    let D_value = Math.abs(sourceElevation - compareElevation);
    let sd = 0,
      cd = 0;
    if (sdiameter.indexOf("X") > 0) {
      sd = sdiameter.split("X")[0];
    } else if (sdiameter.indexOf("*") > 0) {
      sd = sdiameter.split("*")[0];
    } else
      sd = sdiameter;

    if (cdiameter.indexOf("X") > 0) {
      cd = cdiameter.split("X")[0];
    } else if (cdiameter.indexOf("*") > 0) {
      cd = cdiameter.split("*")[0];
    } else
      cd = cdiameter;
    let s_cdiameter = sd / 2000.0 + cd / 2000.0;
    return D_value - s_cdiameter;
  },

  /**
   * 处理半径小数点
   * @param diameter
   */
  FixedDiameter: function (diameter) {
    let dinfo = diameter + "";
    if (dinfo.indexOf(".") > -1 && dinfo.indexOf("*") <= -1 && dinfo.indexOf("X") <= -1) {
      return dinfo.split(".")[0];
    } else {
      return diameter
    }
  },

  /**
   * 处理数据小数点
   * @param diameter 数字
   * @param num 保留小数位数
   */
  FixedDiameterNumber: function (diameter, num) {
    let dinfo = diameter + "";
    if (dinfo.indexOf(".") > -1) {
      return parseFloat(dinfo).toFixed(num);
    } else {
      return diameter
    }
  },

  /**
   * 取出两个数组中相同的元素
   */
  GetArrEqual(arr1, arr2) {
    let newArr = [];
    if (arr1 && arr2) {
      for (let i = 0; i < arr2.length; i++) {
        for (let j = 0; j < arr1.length; j++) {
          if (arr1[j] === arr2[i]) {
            newArr.push(arr1[j]);
          }
        }
      }
    }
    return newArr;
  },

  /**
   * where条件中in的字符串组合
   * @param ids
   */
  GetWhereStr(ids) {
    let str = "(";
    for (let i = 0; i < ids.length; i++) {
      if (i != ids.length - 1) {
        str += ids[i] + ",";
      } else {
        str += ids[i] + ")";
      }
    }
    return str;
  },

  /**
   * 从第一个数组中移除第二个数组相同的
   */
  RemoveArrEqual(arr1, arr2) {
    let newArr = [];
    if (!arr2 || arr2.length == 0) {
      return arr1;
    }
    if (arr2 && arr1) {
      newArr = arr1;
      for (let i = 0; i < arr2.length; i++) {
        let index = newArr.indexOf(arr2[i]);
        if (index > -1) {
          newArr.splice(index, 1);
        }
      }
    }

    return newArr;
  },

  /**
   * 复制数组
   */
  CopyArr(arr2) {
    let newArr = [];
    if (arr2) {
      for (let i = 0; i < arr2.length; i++) {
        newArr.push(arr2[i]);
      }
    }
    return newArr;
  },

  /**
   * 开启或关闭右键调试菜单
   * @param open true打开，false关闭
   */
  HideRight(open) {
    if (open) {
      let oncontextmenu = "return true";
      document.oncontextmenu = function (e) {
        return true;
      }
    } else {
      let oncontextmenu = "return false";
      document.oncontextmenu = function (e) {
        return false;
      }
    }
  }
};

/**
 * 画图工具集合
 * @author wanghai
 */
export const CesiumDrawTool = {
  /**
   * 画点工具
   * 返回点集合及实体集合
   * @param callback 回调函数，callback(positions,entities)
   * @param viewer 当前视图
   * @param pointStyle 点样式
   */
  DrawPoint: function (callback, viewer, pointStyle) {
    let _this = this;
    if (!_this.viewer)
      _this.viewer = viewer;
    let positions = [];
    let entities = [];
    let handler = new Cesium.ScreenSpaceEventHandler(_this.viewer.scene.canvas);
    let point = {
      color: Cesium.Color.RED,
      pixelSize: 5,
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
    };
    if (pointStyle) {
      point = pointStyle;
    }
    handler.setInputAction(function (movement) { //单击鼠标左键画点
      let cartesian = _this.viewer.scene.camera.pickEllipsoid(movement.position, _this
        .viewer.scene.globe.ellipsoid);
      positions.push(cartesian);
      entities.push(_this.viewer.entities.add({
        position: cartesian,
        point: point
      }));
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    handler.setInputAction(function (movement) { //单击鼠标右键结束画点
      handler.destroy();
      callback(positions, entities);
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  },

  /**
   * 画线工具
   * 返回线点集合及实体集合
   * @param callback 回调函数，callback(positions,entities)
   * @param viewer 当前视图
   * @param polylineStyle 线样式
   */
  DrawLineString: function (callback, viewer, polylineStyle) {
    let _this = this;
    if (!_this.viewer)
      _this.viewer = viewer;
    _this.entities = [];
    _this.polyline = {
      show: true,
      positions: [],
      material: Cesium.Color.RED,
      width: 3
    };
    if (polylineStyle)
      _this.polyline = polylineStyle;
    let PolyLinePrimitive = (function () {
      function _(positions) {
        this.options = {
          polyline: _this.polyline
        };
        this.positions = positions;
        this._init();
      }

      _.prototype._init = function () {
        let _self = this;
        let _update = function () {
          return _self.positions;
        };
        //实时更新polyline.positions
        this.options.polyline.positions = new Cesium.CallbackProperty(_update, false);
        _this.entities.push(_this.viewer.entities.add(this.options));
      };
      return _;
    })();

    let handler = new Cesium.ScreenSpaceEventHandler(_this.viewer.scene.canvas);
    let positions = [];
    let poly = undefined;
    //鼠标左键单击画点
    handler.setInputAction(function (movement) {
      let cartesian = _this.viewer.scene.camera.pickEllipsoid(movement.position, _this
        .viewer.scene.globe.ellipsoid);
      if (positions.length == 0) {
        positions.push(cartesian.clone());
      }
      positions.push(cartesian);
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    //鼠标移动
    handler.setInputAction(function (movement) {
      let cartesian = _this.viewer.scene.camera.pickEllipsoid(movement.endPosition, _this
        .viewer.scene.globe.ellipsoid);
      if (positions.length >= 2) {
        if (!Cesium.defined(poly)) {
          poly = new PolyLinePrimitive(positions);
        } else {
          if (cartesian != undefined) {
            positions.pop();
            cartesian.y += (1 + Math.random());
            positions.push(cartesian);
          }
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    //单击鼠标右键结束画线
    handler.setInputAction(function (movement) {
      handler.destroy();
      callback(positions, _this.entities);
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  },

  /**
   * 画多边形工具
   * 返回多边形点集合及实体集合
   * @param callback 回调函数，callback(positions,entities)
   * @param viewer 当前视图
   * @param polygonStyle 面样式
   */
  DrawPolygon: function (callback, viewer, polygonStyle) {
    let _this = this;
    if (!_this.viewer)
      _this.viewer = viewer
    _this.entities = [];
    _this.polygon = {
      hierarchy: [],
      perPositionHeight: true,
      outline: true,
      outlineColor: Cesium.Color.RED,
      outlineWidth: 2,
      material: Cesium.Color.DARKSEAGREEN.withAlpha(0.3)
    };
    if (polygonStyle)
      _this.polygon = polygonStyle;
    let PolygonPrimitive = (function () {
      function _(positions) {
        this.options = {
          name: '多边形',
          polygon: _this.polygon
        };
        this.hierarchy = positions;
        this._init();
      }

      _.prototype._init = function () {
        let _self = this;
        let _update = function () {
          return _self.hierarchy;
        };
        //实时更新polygon.hierarchy
        this.options.polygon.hierarchy = new Cesium.CallbackProperty(_update, false);
        _this.entities.push(_this.viewer.entities.add(this.options));
      };
      return _;
    })();

    let handler = new Cesium.ScreenSpaceEventHandler(_this.viewer.scene.canvas);
    let positions = [];
    let poly = undefined;

    //鼠标单击画点
    handler.setInputAction(function (movement) {
      //let cartesian = _this.viewer.scene.camera.pickEllipsoid(movement.position, _this.viewer.scene.globe.ellipsoid);

      let cartesian = viewer.scene.pickPosition(movement.position);

      if (positions.length == 0) {
        positions.push(cartesian.clone());
      }
      positions.push(cartesian);
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    //鼠标移动
    handler.setInputAction(function (movement) {
      //let cartesian = _this.viewer.scene.camera.pickEllipsoid(movement.endPosition, _this.viewer.scene.globe.ellipsoid);

      let cartesian = viewer.scene.pickPosition(movement.endPosition);
      if (positions.length >= 2) {
        if (!Cesium.defined(poly)) {
          poly = new PolygonPrimitive(positions);
        } else {
          if (cartesian != undefined) {
            positions.pop();
            positions.push(cartesian);
          }
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    //鼠标右键单击结束绘制
    handler.setInputAction(function (movement) {
      handler.destroy();
      callback(positions, _this.entities);
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  },

  /**
   * 画圆形工具
   * 返回圆形点集合及实体集合
   * @param callback 回调函数，callback(positions,entities)
   * @param viewer 当前视图
   */
  CircleDraw(_callBack, viewer) {
    let _self = this;
    if (!_self.viewer)
      _self.viewer = viewer;
    _self.viewer.scene.globe.depthTestAgainstTerrain = true;
    _self.circle = {
      points: [],
      rect: null,
      entity: null,
      r: 1
    };
    _self.entities = [];
    let tempPosition;
    let cartographic1;
    let p;
    let tempLon;
    let tempLat;
    let ShapeEventHandler = new Cesium.ScreenSpaceEventHandler(_self.viewer.scene.canvas);

    ShapeEventHandler.setInputAction(function (click) {
      tempPosition = _self.getPointFromWindowPoint(click.position);
      //选择的点在球面上
      if (tempPosition) {
        function callBackPos() {
          const minlon = Cesium.Math.toDegrees(_self.circle.points[0].longitude);
          const minlat = Cesium.Math.toDegrees(_self.circle.points[0].latitude);
          const maxlon = Cesium.Math.toDegrees(_self.circle.points[1].longitude);
          const maxlat = Cesium.Math.toDegrees(_self.circle.points[1].latitude);
          const r = _self.GetFlatternDistance(minlat, minlon, maxlat, maxlon);
          if (r) {
            return r;
          }
          return 1;
        };
        if (_self.circle.points.length == 0) {
          p = click.position;
          cartographic1 = Cesium.Ellipsoid.WGS84.cartesianToCartographic(tempPosition);
          _self.circle.points.push(_self.viewer.scene.globe.ellipsoid.cartesianToCartographic(
            tempPosition));
          _self.circle.points.push(_self.viewer.scene.globe.ellipsoid.cartesianToCartographic(
            tempPosition));
          tempLon = Cesium.Math.toDegrees(cartographic1.longitude);
          tempLat = Cesium.Math.toDegrees(cartographic1.latitude);
          _self.circle.entity = _self.viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(tempLon, tempLat),
            ellipse: {
              semiMinorAxis: new Cesium.CallbackProperty(callBackPos, false),
              semiMajorAxis: new Cesium.CallbackProperty(callBackPos, false),
              outline: true,
              outlineColor: Cesium.Color.RED,
              outlineWidth: 2,
              material: Cesium.Color.DARKSEAGREEN.withAlpha(0.3)
            }
          });
          _self.entities.push(_self.circle.entity)
        } else {
          ShapeEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
          ShapeEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
          let tempCircle = new Cesium.CircleOutlineGeometry({
            center: Cesium.Cartesian3.fromDegrees(tempLon, tempLat),
            radius: callBackPos(),
            granularity: Math.PI / 2
          });
          let geometry = Cesium.CircleOutlineGeometry.createGeometry(tempCircle);
          let float64ArrayPositionsIn = geometry.attributes.position.values;
          let positionsIn = [].slice.call(float64ArrayPositionsIn);
          ShapeEventHandler.destroy();
          _callBack(positionsIn, _self.entities);
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    ShapeEventHandler.setInputAction(function (movement) {
      if (_self.circle.points.length == 0) {
        return;
      }
      let moveEndPosition = _self.getPointFromWindowPoint(movement.endPosition);
      //选择的点在球面上
      if (moveEndPosition) {
        _self.circle.points.pop();
        _self.circle.points.push(_self.viewer.scene.globe.ellipsoid.cartesianToCartographic(
          moveEndPosition));
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  },

  /**
   * 画矩形工具
   * 返回矩形点集合及实体集合
   * @param callback 回调函数，callback(positions,entities)
   * @param viewer 当前视图
   */
  DrawRect: function (callback, viewer) {
    let _self = this;
    let pointsArr = [];
    if (!_self.viewer)
      _self.viewer = viewer;
    _self.entities = [];
    _self.shape = {
      points: [],
      rect: null,
      entity: null
    };
    let tempPosition;
    let handle = new Cesium.ScreenSpaceEventHandler(_self.viewer.scene.canvas);
    //鼠标左键单击画点
    handle.setInputAction(function (click) {
      tempPosition = _self.getPointFromWindowPoint(click.position);
      //选择的点在球面上
      if (tempPosition) {
        if (_self.shape.points.length == 0) {
          pointsArr.push(tempPosition);
          _self.shape.points.push(_self.viewer.scene.globe.ellipsoid
            .cartesianToCartographic(tempPosition));
          _self.shape.rect = Cesium.Rectangle.fromCartographicArray(_self.shape.points);
          _self.shape.rect.east += 0.000001;
          _self.shape.rect.north += 0.000001;
          _self.shape.entity = _self.viewer.entities.add({
            rectangle: {
              coordinates: _self.shape.rect,
              material: Cesium.Color.DARKSEAGREEN.withAlpha(0.3),
              outline: true,
              outlineWidth: 2,
              outlineColor: Cesium.Color.RED,
              height: 0
            }
          });
          _self.bufferEntity = _self.shape.entity;

          _self.entities.push(_self.shape.entity);
        } else {
          handle.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
          handle.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
          handle.destroy();
          callback(pointsArr, _self.entities);
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    //鼠标移动
    handle.setInputAction(function (movement) {
      if (_self.shape.points.length == 0) {
        return;
      }
      let moveEndPosition = _self.getPointFromWindowPoint(movement.endPosition);
      //选择的点在球面上
      if (moveEndPosition) {
        pointsArr[1] = moveEndPosition;
        _self.shape.points[1] = _self.viewer.scene.globe.ellipsoid.cartesianToCartographic(
          moveEndPosition);
        _self.shape.rect = Cesium.Rectangle.fromCartographicArray(_self.shape.points);
        if (_self.shape.rect.west == _self.shape.rect.east)
          _self.shape.rect.east += 0.000001;
        if (_self.shape.rect.south == _self.shape.rect.north)
          _self.shape.rect.north += 0.000001;
        _self.shape.entity.rectangle.coordinates = _self.shape.rect;
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  },

  /**
   * 从屏幕坐标获取点
   */
  getPointFromWindowPoint(point) {
    if (this.viewer.scene.terrainProvider.constructor.name == "EllipsoidTerrainProvider") {
      return this.viewer.camera.pickEllipsoid(point, this.viewer.scene.globe.ellipsoid);
    } else {
      let ray = this.viewer.scene.camera.getPickRay(point);
      return this.viewer.scene.globe.pick(ray, this.viewer.scene);
    }
  },

  /**
   * 移除实体对象集合
   * @param viewer 视图对象
   * @param entities 实体对象集合，array
   */
  RemoveEntities: function (viewer, entities) {
    if (viewer && entities) {
      for (let i = 0; i < entities.length; i++) {
        viewer.entities.remove(entities[i]);
      }
      entities = [];
    }
  },

  /**
   * 笛卡尔坐标系转WGS84坐标系
   */
  Cartesian3_to_WGS84: function (point) {
    let cartesian33 = new Cesium.Cartesian3(point.x, point.y, point.z);
    let cartographic = Cesium.Cartographic.fromCartesian(cartesian33);
    let lat = Cesium.Math.toDegrees(cartographic.latitude);
    let lng = Cesium.Math.toDegrees(cartographic.longitude);
    let alt = cartographic.height;
    return {
      lat: lat,
      lng: lng,
      alt: alt
    };
  },

  /**
   * WGS84坐标系转笛卡尔坐标系
   */
  WGS84_to_Cartesian3: function (point) {
    let car33 = Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.alt);
    let x = car33.x;
    let y = car33.y;
    let z = car33.z;
    return {
      x: x,
      y: y,
      z: z
    };
  },

  /**
   * 计算两点间距离
   * @param lat1 第一个点纬度
   * @param lng1 第一个点经度
   * @param lat2 第二个点纬度
   * @param lng2 第二个点经度
   */
  GetFlatternDistance(lat1, lng1, lat2, lng2) {
    let EARTH_RADIUS = 6378137.0; //单位M
    let PI = Math.PI;

    function getRad(d) {
      return d * PI / 180.0;
    }
    let f = getRad((lat1 + lat2) / 2);
    let g = getRad((lat1 - lat2) / 2);
    let l = getRad((lng1 - lng2) / 2);

    let sg = Math.sin(g);
    let sl = Math.sin(l);
    let sf = Math.sin(f);

    let s, c, w, r, d, h1, h2;
    let a = EARTH_RADIUS;
    let fl = 1 / 298.257;

    sg = sg * sg;
    sl = sl * sl;
    sf = sf * sf;

    s = sg * (1 - sl) + (1 - sf) * sl;
    c = (1 - sg) * (1 - sl) + sf * sl;

    w = Math.atan(Math.sqrt(s / c));
    r = Math.sqrt(s * c) / w;
    d = 2 * w * a;
    h1 = (3 * r - 1) / 2 / c;
    h2 = (3 * r + 1) / 2 / s;

    return d * (1 + fl * (h1 * sf * (1 - sg) - h2 * (1 - sf) * sg));
  }
};

export const createGifLayer = function (frameDiv, opts, viewer, func) {

  let giflayer = function (frameDiv, opts, viewer, func) {
    this._opts = opts;
    this._viewer = viewer;
    this._eventName = "gifevent";
    for (let i = 0; i < this._opts.length; i++) {
      this._opts[i]['element'] = $(this._opts[i].imgdiv);
      this._opts[i]['element'].appendTo(frameDiv);
      this._opts[i]['element'].data('name', this._opts[i].name);
      this._opts[i]['element'].on('click', func);
    }

    let scratch = new Cesium.Cartesian2();
    viewer.scene.preRender.addEventListener(function () {
      for (let i = 0; i < this._opts.length; i++) {
        let item = this._opts[i];
        let pt = Cesium.Cartesian3.fromDegrees(item.lgtd, item.lttd, item.height);
        let scratch = new Cesium.Cartesian2();
        let canvasPosition = this._viewer.scene.cartesianToCanvasCoordinates(pt, scratch);
        if (Cesium.defined(canvasPosition)) {
          item.element.css('top', canvasPosition.y + 'px');
          item.element.css('left', canvasPosition.x + 'px');
        }
      }
    }.bind(this), this._eventName);
  };

  giflayer.prototype.setVisible = function (visible) {
    this._opts.forEach((opt) => {
      opt.element.style.display = visible ? 'block' : 'none';
    });
  };

  giflayer.prototype.remove = function () {
    this._opts.forEach((opt) => {
      opt.element.remove();
    });

    for (let i = 0; i < this._viewer.scene.preRender._scopes.length;) {
      if (this._viewer.scene.preRender._scopes[i] == this._eventName) {
        this._viewer.scene.preRender._scopes.splice(i, 1);
        this._viewer.scene.preRender._listeners.splice(i, 1);
      } else
        i++;
    }
  };

  return new giflayer(frameDiv, opts, viewer, func);
};

/**
 * 
 * @param {String} viewer 
 * @param {Number} alpha 透明度0-1之间
 */
export const setTransparentGround = function (viewer, alpha) {
  let layers = ["Config"]; //透明地表
  viewer.scene.globe.globeAlpha = 1 - alpha;
  viewer.scene.globe.baseColor = new Cesium.Color(0, 0, 0, 1);
  viewer.scene.layers.layerQueue.forEach(function (layer) {
    if (_.indexOf(layers, layer.name) !== -1) {
      layer.style3D.fillForeColor.alpha = 1 - alpha;
    }
  });
  for (let i = 0; i < viewer.scene.imageryLayers.length; i++) {
    let ly = viewer.scene.imageryLayers.get(i);
    ly.alpha = 1 - alpha;
  }
};
