mirror of
https://github.com/jiawanlong/Cesium-Examples.git
synced 2025-07-04 15:17:36 +00:00
539 lines
16 KiB
JavaScript
539 lines
16 KiB
JavaScript
var util = {};
|
||
|
||
util.isNumber = function (obj) {
|
||
return (typeof obj == 'number') && obj.constructor == Number;
|
||
}
|
||
|
||
util.isString = function (str) {
|
||
return (typeof str == 'string') && str.constructor == String;
|
||
}
|
||
|
||
/**
|
||
* @function Util.extend
|
||
* @description 对象拷贝赋值。
|
||
* @param {Object} dest - 目标对象。
|
||
* @param {Object} arguments - 待拷贝的对象。
|
||
* @returns {Object} 赋值后的目标对象。
|
||
*/
|
||
util.extend = function (dest) {
|
||
for (var index = 0; index < Object.getOwnPropertyNames(arguments).length; index++) {
|
||
var arg = Object.getOwnPropertyNames(arguments)[index];
|
||
if (arg == "caller" || arg == "callee" || arg == "length" || arg == "arguments") {
|
||
continue;
|
||
}
|
||
var obj = arguments[arg];
|
||
if (obj) {
|
||
for (var j = 0; j < Object.getOwnPropertyNames(obj).length; j++) {
|
||
var key = Object.getOwnPropertyNames(obj)[j];
|
||
if (arg == "caller" || arg == "callee" || arg == "length" || arg == "arguments") {
|
||
continue;
|
||
}
|
||
dest[key] = obj[key];
|
||
}
|
||
}
|
||
}
|
||
return dest;
|
||
}
|
||
|
||
//url参数获取
|
||
util.getRequest = function () {
|
||
var url = location.search; //获取url中"?"符后的字串
|
||
var theRequest = new Object();
|
||
if (url.indexOf("?") != -1) {
|
||
var str = url.substr(1);
|
||
var strs = str.split("&");
|
||
for (var i = 0; i < strs.length; i++) {
|
||
theRequest[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);
|
||
}
|
||
}
|
||
return theRequest;
|
||
}
|
||
|
||
util.getRequestByName = function (name) {
|
||
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
|
||
var r = window.location.search.substr(1).match(reg);
|
||
if (r != null) return decodeURI(r[2]);
|
||
return null;
|
||
}
|
||
|
||
|
||
util.clone = function (obj) {
|
||
if (null == obj || "object" != typeof obj) return obj;
|
||
|
||
// Handle Date
|
||
if (obj instanceof Date) {
|
||
var copy = new Date();
|
||
copy.setTime(obj.getTime());
|
||
return copy;
|
||
}
|
||
|
||
// Handle Array
|
||
if (obj instanceof Array) {
|
||
var copy = [];
|
||
for (var i = 0, len = obj.length; i < len; ++i) {
|
||
copy[i] = clone(obj[i]);
|
||
}
|
||
return copy;
|
||
}
|
||
|
||
// Handle Object
|
||
if (typeof obj === 'object') {
|
||
var copy = {};
|
||
for (var attr in obj) {
|
||
if (attr == "_layer" || attr == "_layers" || attr == "_parent") continue;
|
||
|
||
if (obj.hasOwnProperty(attr))
|
||
copy[attr] = clone(obj[attr]);
|
||
}
|
||
return copy;
|
||
}
|
||
return obj;
|
||
}
|
||
|
||
|
||
util.isPCBroswer = function () {
|
||
var sUserAgent = navigator.userAgent.toLowerCase();
|
||
|
||
var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
|
||
var bIsIphoneOs = sUserAgent.match(/iphone/i) == "iphone";
|
||
var bIsMidp = sUserAgent.match(/midp/i) == "midp";
|
||
var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
|
||
var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
|
||
var bIsAndroid = sUserAgent.match(/android/i) == "android";
|
||
var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
|
||
var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
|
||
if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
//检测浏览器webgl支持
|
||
util.webglreport = function () {
|
||
var exinfo = getExplorerInfo();
|
||
if (exinfo.type == "IE" && exinfo.version < 11) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
var glContext;
|
||
var canvas = document.createElement('canvas');
|
||
var requestWebgl2 = (typeof WebGL2RenderingContext !== 'undefined');
|
||
if (requestWebgl2) {
|
||
glContext = canvas.getContext('webgl2') || canvas.getContext('experimental-webgl2') || undefined;
|
||
}
|
||
if (glContext == null) {
|
||
glContext = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') || undefined;
|
||
}
|
||
if (glContext == null) {
|
||
return false;
|
||
}
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
//计算贴地路线
|
||
util.terrainPolyline = function (params) {
|
||
var viewer = params.viewer;
|
||
var positions = params.positions;
|
||
if (positions == null || positions.length == 0) {
|
||
if (params.calback)
|
||
params.calback(positions);
|
||
return;
|
||
}
|
||
|
||
var flatPositions = Cesium.PolylinePipeline.generateArc({
|
||
positions: positions,
|
||
granularity: params.granularity || 0.00001
|
||
});
|
||
|
||
|
||
var cartographicArray = [];
|
||
var ellipsoid = viewer.scene.globe.ellipsoid;
|
||
for (var i = 0; i < flatPositions.length; i += 3) {
|
||
var cartesian = Cesium.Cartesian3.unpack(flatPositions, i);
|
||
cartographicArray.push(ellipsoid.cartesianToCartographic(cartesian));
|
||
}
|
||
|
||
//用于缺少地形数据时,赋值的高度
|
||
var tempHeight = Cesium.Cartographic.fromCartesian(positions[0]).height;
|
||
|
||
Cesium.when(Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, cartographicArray), function (samples) {
|
||
var noHeight = false;
|
||
var offset = params.offset || 2; //增高高度,便于可视
|
||
|
||
for (var i = 0; i < samples.length; ++i) {
|
||
if (samples[i].height == null) {
|
||
noHeight = true;
|
||
samples[i].height = tempHeight;
|
||
} else {
|
||
samples[i].height = offset + (samples[i].height * viewer.scene._terrainExaggeration);
|
||
}
|
||
}
|
||
|
||
var raisedPositions = ellipsoid.cartographicArrayToCartesianArray(samples);
|
||
if (params.calback)
|
||
params.calback(raisedPositions, noHeight);
|
||
else if (positions.setValue)
|
||
positions.setValue(raisedPositions);
|
||
});
|
||
|
||
|
||
}
|
||
|
||
//地形构造
|
||
var _ellipsoid = new Cesium.EllipsoidTerrainProvider({
|
||
ellipsoid: Cesium.Ellipsoid.WGS84
|
||
});
|
||
|
||
util.getEllipsoidTerrain = function () {
|
||
return _ellipsoid;
|
||
}
|
||
|
||
util.getTerrainProvider = function (cfg) {
|
||
if (!cfg.hasOwnProperty("requestWaterMask")) cfg.requestWaterMask = true;
|
||
if (!cfg.hasOwnProperty("requestVertexNormals")) cfg.requestVertexNormals = true;
|
||
|
||
var terrainProvider;
|
||
|
||
if (cfg.url == "" || cfg.url == null || cfg.url == "cesium") {
|
||
terrainProvider = new Cesium.CesiumTerrainProvider({
|
||
url: Cesium.IonResource.fromAssetId(1)
|
||
})
|
||
} else if (cfg.url == "ellipsoid" || cfg.url == "null") {
|
||
terrainProvider = _ellipsoid;
|
||
} else {
|
||
terrainProvider = new Cesium.CesiumTerrainProvider(cfg);
|
||
}
|
||
return terrainProvider;
|
||
}
|
||
|
||
//创建模型
|
||
util.createModel = function (cfg, viewer) {
|
||
cfg = viewer.globe.point2map(cfg); //转换坐标系
|
||
|
||
var position = Cesium.Cartesian3.fromDegrees(cfg.x, cfg.y, cfg.z || 0);
|
||
var heading = Cesium.Math.toRadians(cfg.heading || 0)
|
||
var pitch = Cesium.Math.toRadians(cfg.pitch || 0)
|
||
var roll = Cesium.Math.toRadians(cfg.roll || 0);
|
||
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
|
||
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
|
||
|
||
var model = viewer.entities.add({
|
||
name: cfg.name || "",
|
||
position: position,
|
||
orientation: orientation,
|
||
model: cfg,
|
||
tooltip: cfg.tooltip,
|
||
popup: cfg.popup,
|
||
});
|
||
return model;
|
||
}
|
||
|
||
util.formatDegree = function (value) {
|
||
value = Math.abs(value);
|
||
var v1 = Math.floor(value); //度
|
||
var v2 = Math.floor((value - v1) * 60); //分
|
||
var v3 = Math.round((value - v1) * 3600 % 60); //秒
|
||
return v1 + '° ' + v2 + '\' ' + v3 + '"';
|
||
};
|
||
|
||
function getExplorerInfo() {
|
||
var explorer = window.navigator.userAgent.toLowerCase();
|
||
//ie
|
||
if (explorer.indexOf("msie") >= 0) {
|
||
var ver = Number(explorer.match(/msie ([\d]+)/)[1]);
|
||
return {
|
||
type: "IE",
|
||
version: ver
|
||
};
|
||
}
|
||
//firefox
|
||
else if (explorer.indexOf("firefox") >= 0) {
|
||
var ver = Number(explorer.match(/firefox\/([\d]+)/)[1]);
|
||
return {
|
||
type: "Firefox",
|
||
version: ver
|
||
};
|
||
}
|
||
//Chrome
|
||
else if (explorer.indexOf("chrome") >= 0) {
|
||
var ver = Number(explorer.match(/chrome\/([\d]+)/)[1]);
|
||
return {
|
||
type: "Chrome",
|
||
version: ver
|
||
};
|
||
}
|
||
//Opera
|
||
else if (explorer.indexOf("opera") >= 0) {
|
||
var ver = Number(explorer.match(/opera.([\d]+)/)[1]);
|
||
return {
|
||
type: "Opera",
|
||
version: ver
|
||
};
|
||
}
|
||
//Safari
|
||
else if (explorer.indexOf("Safari") >= 0) {
|
||
var ver = Number(explorer.match(/version\/([\d]+)/)[1]);
|
||
return {
|
||
type: "Safari",
|
||
version: ver
|
||
};
|
||
}
|
||
return {
|
||
type: explorer,
|
||
version: -1
|
||
};
|
||
}
|
||
//解决浮点问题
|
||
function floatObj() {
|
||
|
||
/*
|
||
* 判断obj是否为一个整数
|
||
*/
|
||
function isInteger(obj) {
|
||
return Math.floor(obj) === obj
|
||
}
|
||
|
||
/*
|
||
* 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100
|
||
* @param floatNum {number} 小数
|
||
* @return {object}
|
||
* {times:100, num: 314}
|
||
*/
|
||
function toInteger(floatNum) {
|
||
var ret = {
|
||
times: 1,
|
||
num: 0
|
||
};
|
||
if (isInteger(floatNum)) {
|
||
ret.num = floatNum;
|
||
return ret
|
||
}
|
||
var strfi = floatNum + '';
|
||
var dotPos = strfi.indexOf('.');
|
||
var len = strfi.substr(dotPos + 1).length;
|
||
var times = Math.pow(10, len);
|
||
var intNum = parseInt(floatNum * times + 0.5, 10);
|
||
ret.times = times;
|
||
ret.num = intNum;
|
||
return ret
|
||
}
|
||
|
||
/*
|
||
* 核心方法,实现加减乘除运算,确保不丢失精度
|
||
* 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除)
|
||
*
|
||
* @param a {number} 运算数1
|
||
* @param b {number} 运算数2
|
||
* @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide)
|
||
*
|
||
*/
|
||
function operation(a, b, op) {
|
||
var o1 = toInteger(a);
|
||
var o2 = toInteger(b);
|
||
var n1 = o1.num;
|
||
var n2 = o2.num;
|
||
var t1 = o1.times;
|
||
var t2 = o2.times;
|
||
var max = t1 > t2 ? t1 : t2;
|
||
var result = null;
|
||
switch (op) {
|
||
case 'add':
|
||
if (t1 === t2) { // 两个小数位数相同
|
||
result = n1 + n2
|
||
} else if (t1 > t2) { // o1 小数位 大于 o2
|
||
result = n1 + n2 * (t1 / t2)
|
||
} else { // o1 小数位 小于 o2
|
||
result = n1 * (t2 / t1) + n2
|
||
}
|
||
return result / max;
|
||
case 'subtract':
|
||
if (t1 === t2) {
|
||
result = n1 - n2
|
||
} else if (t1 > t2) {
|
||
result = n1 - n2 * (t1 / t2)
|
||
} else {
|
||
result = n1 * (t2 / t1) - n2
|
||
}
|
||
return result / max;
|
||
case 'multiply':
|
||
result = (n1 * n2) / (t1 * t2);
|
||
return result;
|
||
case 'divide':
|
||
result = (n1 / n2) * (t2 / t1);
|
||
return result
|
||
}
|
||
}
|
||
|
||
// 加减乘除的四个接口
|
||
function add(a, b) {
|
||
return operation(a, b, 'add')
|
||
}
|
||
|
||
function subtract(a, b) {
|
||
return operation(a, b, 'subtract')
|
||
}
|
||
|
||
function multiply(a, b) {
|
||
return operation(a, b, 'multiply')
|
||
}
|
||
|
||
function divide(a, b) {
|
||
return operation(a, b, 'divide')
|
||
}
|
||
|
||
// exports
|
||
return {
|
||
add: add,
|
||
subtract: subtract,
|
||
multiply: multiply,
|
||
divide: divide
|
||
}
|
||
};
|
||
util.floatObj = floatObj();
|
||
|
||
|
||
//生成多边形范围内随机点polygon:折点集合
|
||
util.randomPointsWithinPolygon = function (polygon, num, type) {
|
||
var xmin = 1000000000,
|
||
xmax = -1000000000,
|
||
ymin = 1000000000,
|
||
ymax = -1000000000;
|
||
//获取面的矩形
|
||
for (var i = 0; i < polygon.length; i++) {
|
||
xmin = Math.min(xmin, polygon[i].x);
|
||
xmax = Math.max(xmax, polygon[i].x);
|
||
ymin = Math.min(ymin, polygon[i].y);
|
||
ymax = Math.max(ymax, polygon[i].y);
|
||
}
|
||
var points = [];
|
||
if (type && type == "geojson") {
|
||
points = {
|
||
"type": "FeatureCollection",
|
||
"features": []
|
||
};
|
||
}
|
||
for (var j = 0; j < num; j++) {
|
||
var point = util.randomPointsWithinBbox(xmin, xmax, ymin, ymax, 1)[0];
|
||
if (!util.isDotInPolygon(point, polygon)) {
|
||
j--;
|
||
} else {
|
||
if (type == "geojson") {
|
||
var p = {
|
||
"type": "Feature",
|
||
"properties": {
|
||
"value": parseInt(Math.random() * 10000000)
|
||
},
|
||
"geometry": {
|
||
"type": "Point",
|
||
"coordinates": [point.x, point.y]
|
||
}
|
||
}
|
||
points.features.push(p);
|
||
|
||
} else {
|
||
points.push(point);
|
||
}
|
||
};
|
||
}
|
||
return points;
|
||
}
|
||
//生成矩形范围类随机点
|
||
util.randomPointsWithinBbox = function (xmin, xmax, ymin, ymax, num, type) {
|
||
if (type && type == "geojson") {
|
||
var points = {
|
||
"type": "FeatureCollection",
|
||
"features": []
|
||
};
|
||
for (var i = 0; i < num; i++) {
|
||
var point = {
|
||
"type": "Feature",
|
||
"properties": {
|
||
"value": parseInt(Math.random() * 10000000)
|
||
},
|
||
"geometry": {
|
||
"type": "Point",
|
||
"coordinates": [(Math.random() * (xmax - xmin) + xmin), (Math.random() * (ymax - ymin) + ymin)]
|
||
}
|
||
}
|
||
points.features.push(point);
|
||
}
|
||
return points;
|
||
} else {
|
||
var points = [];
|
||
for (var i = 0; i < num; i++) {
|
||
var point = {
|
||
x: (Math.random() * (xmax - xmin) + xmin),
|
||
y: (Math.random() * (ymax - ymin) + ymin)
|
||
}
|
||
points.push(point);
|
||
}
|
||
return points;
|
||
}
|
||
}
|
||
//判断点在多边形上(平面)point:{x,y},polygonPoints:[{x,y},{x,y},{x,y}]
|
||
util.isDotInPolygon = function (point, polygonPoints, onborder = true) {
|
||
var flag = false,
|
||
p1,
|
||
p2;
|
||
if (!point.x) {
|
||
point.x = point[0];
|
||
point.y = point[1];
|
||
}
|
||
for (var i = 0, j = polygonPoints.length - 1; i < polygonPoints.length; j = i++) {
|
||
p1 = polygonPoints[i];
|
||
p2 = polygonPoints[j];
|
||
p1 = p1.x ? {
|
||
x: p1.x,
|
||
y: p1.y
|
||
} : {
|
||
x: p1[0],
|
||
y: p1[1]
|
||
};
|
||
p2 = p2.x ? {
|
||
x: p2.x,
|
||
y: p2.y
|
||
} : {
|
||
x: p2[0],
|
||
y: p2[1]
|
||
};
|
||
if (onborder) {
|
||
// 这里判断是否刚好被测点在多边形的边上
|
||
if (util.onSegment(p1, p2, point)) return true;
|
||
}
|
||
if ((p1.y > point.y != p2.y > point.y) && (point.x < (point.y - p1.y) * (p1.x - p2.x) / (p1.y - p2.y) +
|
||
p1.x)) {
|
||
flag = !flag;
|
||
}
|
||
}
|
||
return flag;
|
||
}
|
||
//判断点在线段上(平面)Pi:{x,y},Pj{x,y},Q{x,y}
|
||
util.onSegment = function (Pi, Pj, Q) {
|
||
if ((Q.x - Pi.x) * (Pj.y - Pi.y) == (Pj.x - Pi.x) * (Q.y - Pi.y) //叉乘
|
||
//保证Q点坐标在pi,pj之间
|
||
&&
|
||
Math.min(Pi.x, Pj.x) <= Q.x && Q.x <= Math.max(Pi.x, Pj.x) &&
|
||
Math.min(Pi.y, Pj.y) <= Q.y && Q.y <= Math.max(Pi.y, Pj.y))
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
//获取json文件
|
||
util.getJSON = function (url, callback) {
|
||
const xhr = new XMLHttpRequest();
|
||
xhr.responseType = 'json';
|
||
xhr.open('get', url, true);
|
||
xhr.onload = function () {
|
||
if (xhr.status >= 200 && xhr.status < 300) {
|
||
callback(xhr.response);
|
||
} else {
|
||
throw new Error(xhr.statusText);
|
||
}
|
||
};
|
||
xhr.send();
|
||
} |