开源三维地球GIS引擎Cesium常用功能的开发
Cesium是一个非常优秀的三维地球GIS引擎(开源且免费)。能够加载各种符合标准的地图图层,瓦片图、矢量图等都支持。支持3DMax等建模软件生成的obj文件,支持通用的GIS计算;支持DEM高程图。测试中的3D-Tiles分支还支持倾斜摄影生成的城市三维建筑群。国内许多三维GIS产品都基于Cesium进行封装(包括一些大厂)。因为工作关系,我对Cesium的一些基本GIS功能进行了研究,特此记录下来。
如上图,这是一个给市政GIS\BIM管理平台做的原型,GIS部分使用Cesium,BIM部分使用第三方商业引擎。GIS控制宏观、BIM支持微观(现在还没有什么好的引擎能做到GIS\BIM的无缝切换)。
常用功能介绍:
- 卫星\矢量地图切换
我这里使用的是天地图提供的服务,卫星地图和矢量地图分别调用不同的接口,卫星地图显示效果如上图,矢量地图显示如下图:
- 道路及基本标注
点“道路及基本标注”后,将路名等显示并加载在原先的图层上
- 加标记点
首先在地图上点击需要加点的位置,然后在弹出框内选取颜色,设置提示文字和显示内容,点击保存;可以添加多个标记。
- 绘制线段
连续点击地图两次就可以绘制线段(可绘制折线)
- 绘制圆形
支持绘制多个圆形,每个圆形随机颜色,能够显示园的半径、面积等
- 绘制多边形
连续点击地图上的点,再右键闭合,就可以绘制多边形,能够计算多边形每一边的边长、总面积等
- 保存视角、跳转视角
保存当前的视角;输入经纬度,跳转到指定位置
- 隐藏、加载模型
可以动态加载、隐藏三维模型(为了便于演示,所有的模型均放大了几百倍);地图上的绘制功能对所有模型都有效,包含在范围内的模型会自动高亮并显示;点选模型能自动居中并提示是否跳转到BIM模型显示(BIM模型也是基于三维WebGL的)
- 搜索
可以根据输入的关键词进行搜索,使用百度或者高德的API,或者使用天地图的API,搜索后进行定位,只是百度、高德、天地图等用的是不同的坐标系,转换非常麻烦。
- 清除绘制
清除所有绘制的部分
以上功能只要再完善下,封装下就可以成为一个很不错的三维GIS项目基础平台了,附我们公司做的GIS+BIM的产品截图,使用了3D-Tiles:)
附:示例程序的js部分代码
var bimEngine; var msgControl; var toolbar; var fileControl; var spaceControl; var domainControl; var propertyControl; var searchControl; var markControl;
var storeyControl; var roamingControl; var bimevent; var viewer = new Cesium.Viewer("cesiumContainer", {
animation: false, //是否显示动画控件
baseLayerPicker: false, //是否显示图层选择控件
geocoder: true, //是否显示地名查找控件
timeline: false, //是否显示时间线控件
sceneModePicker: true, //是否显示投影方式控件
navigationHelpButton: false, //是否显示帮助信息控件
infoBox: true, //是否显示点击要素之后显示的信息
imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
url: "http://t0.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles",
layer: "tdtBasicLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible",
show: false
})
});
var scene = viewer.scene;
var pinBuilder = new Cesium.PinBuilder(); var vecLayer = null, roadLayer = null, electricLayers = null; var getEnumPropertyNames = function(obj) {
var props = [];
for (prop in obj) {
props.push(prop + ': ' + obj[prop]);
}
return props;
} var models = new Array();
models[0] = { id: 'house1', name: 'house1', url: '../SampleData/house/house1.gltf', lon: 121.41, lat: 31.22, height: 0, pid: '4e027d42-f033-4bab-87f1-e34c8860b90e' };
models[1] = { id: 'house2', name: 'house2', url: '../SampleData/house/house2.gltf', lon: 121.42, lat: 31.21, height: 0, pid: '918dcfaa-4568-4468-ba03-e379deaa99b7' };
models[2] = { id: 'house3', name: 'house3', url: '../SampleData/house/house3.gltf', lon: 121.43, lat: 31.20, height: 0, pid: '2071736b-0054-4041-ad34-34f2e7a975e5' };
models[3] = { id: 'house4', name: 'house4', url: '../SampleData/house/house4.gltf', lon: 121.44, lat: 31.22, height: 0, pid: '4e027d42-f033-4bab-87f1-e34c8860b90e' };
models[4] = { id: 'house5', name: 'house5', url: '../SampleData/house/house5.gltf', lon: 121.41, lat: 31.21, height: 0, pid: '918dcfaa-4568-4468-ba03-e379deaa99b7' };
models[5] = { id: 'house6', name: 'house6', url: '../SampleData/house/house6.gltf', lon: 121.42, lat: 31.20, height: 0, pid: '2071736b-0054-4041-ad34-34f2e7a975e5' };
models[6] = { id: 'house7', name: 'house7', url: '../SampleData/house/house7.gltf', lon: 121.43, lat: 31.22, height: 0, pid: '4e027d42-f033-4bab-87f1-e34c8860b90e' };
models[7] = { id: 'house8', name: 'house8', url: '../SampleData/house/house8.gltf', lon: 121.44, lat: 31.21, height: 0, pid: '918dcfaa-4568-4468-ba03-e379deaa99b7' };
models[8] = { id: 'house9', name: 'house9', url: '../SampleData/house/house9.gltf', lon: 121.45, lat: 31.20, height: 0, pid: '2071736b-0054-4041-ad34-34f2e7a975e5' };
models[9] = { id: 'house10', name: 'house10', url: '../SampleData/house/house10.gltf', lon: 121.46, lat: 31.21, height: 0, pid: '918dcfaa-4568-4468-ba03-e379deaa99b7' };
models[10] = { id: 'house11', name: 'house11', url: '../SampleData/house/house11.gltf', lon: 121.40, lat: 31.20, height: 0, pid: '4e027d42-f033-4bab-87f1-e34c8860b90e' };
models[11] = { id: 'villa', name: 'villa', url: '../SampleData/house3/house3.gltf', lon: 121.45, lat: 31.22, height: 0, pid: '2071736b-0054-4041-ad34-34f2e7a975e5' }; var loadedModels = []; var shapes = new Array();
shapes[0] = { layer: '测试层', author: 'liu', date: '2017-06-18', ploy: [
{ name: 'A区', type: 'ploy', points: [] }
]}; var tempPoints = [];
var tempEntities = [];
var tempPinEntities = [];
var tempPinLon, tempPinLat; var handler = null; $(function() { /**初始化**/
$("input[name='optionsRadios']").click(function() {
if ($("input[name='optionsRadios']:eq(1)").prop("checked")) {
//viewer.imageryLayers.addImageryProvider(vecLayer);
vecLayer = viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
url: "http://t0.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles",
layer: "tdtVecBasicLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible",
show: false
}));
} else if ($("input[name='optionsRadios']:eq(0)").prop("checked")) {
if (viewer.imageryLayers.contains(vecLayer)) {
viewer.imageryLayers.remove(vecLayer);
}
}
});
//标记层
$("#cbxPinLayer").change(function() {
if ($("#cbxPinLayer").prop("checked")) {
for (var i = 0; i < tempPinEntities.length; i++) {
viewer.entities.add(tempPinEntities[i]);
} } else {
for (var i = 0; i < tempPinEntities.length; i ++) {
viewer.entities.remove(tempPinEntities[i]);
}
}
});
$("#pinColor").change(function() {
$(this).css("background-color", $(this).val());
}); $("#cbxRoad").click(function() {
if ($(this).prop("checked")) {
roadLayer = viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
url: "http://t0.tianditu.com/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles",
layer: "tdtImgAnnoLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible",
show: false
}));
} else {
viewer.imageryLayers.remove(roadLayer);
}
});
$("#cbxTestArc").click(function() {
if ($(this).prop("checked")) {
electricLayers = viewer.imageryLayers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({
url: 'https://nationalmap.gov.au/proxy/http://services.ga.gov.au/site_3/rest/services/Electricity_Infrastructure/MapServer'
}));
viewer.camera.flyTo({
destination: Cesium.Rectangle.fromDegrees(114.591, -45.837, 148.970, -5.730)
});
} else {
viewer.imageryLayers.remove(electricLayers);
}
});
$("#opts .btn").click(function () {
window.setTimeout(function() {
if ($("input[name='opt']:eq(0)").prop("checked")) {
clearEffects();
setTips("");
}
else if ($("input[name='opt']:eq(1)").prop("checked")) {
clearEffects();
SetMode("addPin");
setTips("首先在地图上点击需要加点的位置,然后在弹出框内选取颜色,设置提示文字和显示内容,点击保存");
}
else if ($("input[name='opt']:eq(2)").prop("checked")) {
tempPoints = [];
for (var i = 0; i < tempEntities.length; i++) {
viewer.entities.remove(tempEntities[i]);
}
for (var i = 0; i < loadedModels.length; i++) {
if (loadedModels[i].color == Cesium.Color.SPRINGGREEN) {
loadedModels[i].color = {red:1,green:1, blue:1, alpha:1};
}
}
clearEffects();
setTips("绘制的图形被清除,点选页面标记可以删除标记");
SetMode("erase");
}
else if ($("input[name='opt']:eq(3)").prop("checked")) {
clearEffects();
SetMode("drawLine");
setTips("在地图上分别点击,即可绘制多个线段,点右键结束绘制");
}
else if ($("input[name='opt']:eq(4)").prop("checked")) {
clearEffects();
SetMode("drawCircle");
setTips("第一次点击绘制圆心,第二次点击根据和圆心的位置绘制半径");
}
else if ($("input[name='opt']:eq(5)").prop("checked")) {
clearEffects();
SetMode("drawSquare");
setTips("第一、二次点击绘制长方形的一个边,再次点击根据点和边的距离绘制方形");
}
else if ($("input[name='opt']:eq(6)").prop("checked")) {
clearEffects();
SetMode("drawPloy");
setTips("如果需要绘制多边形,在地图上使用左键逐个点选地点,右击闭合多边形");
}
else if ($("input[name='opt']:eq(7)").prop("checked")) {
clearEffects();
SetMode("pickBuilding");
setTips("点选建筑查看详细的三维模型");
}
},100);
}); var homeView = {
destination: new Cesium.Cartesian3(-2852877.756667368, 4655857.919027944, 3288673.682311567),
orientation: {
direction: new Cesium.Cartesian3(0.5437275903005284, -0.8386290220423197, -0.03258329225728158),
up: new Cesium.Cartesian3(0.05520718287689969, -0.00299987805272847, 0.9984704140286108)
},
complete: function() { LoadModel(); },
}; setTimeout(
function() {
// scene.primitives.removeAll();
//reset();
viewer.camera.flyTo(homeView); //viewer.zoomTo(wyoming);
}, 3000); //var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
//Cesium.Cartesian3.fromDegrees(121.49, 31.22, 0.0));
//var model = scene.primitives.add(Cesium.Model.fromGltf({
// url: '../SampleData/house/house1.gltf',
// modelMatrix: modelMatrix,
// scale: 20.0,
// name: 'SampleHouse',
// color: getColor('Red', 1)
//})); $("#poly-show").click(function () {
LoadModel();
}); $("#poly-hide").click(function () {
HideModel();
}); //alert(getEnumPropertyNames(model).join('\r')); }); function LoadModel() {
for (var i = 0; i < models.length; i++) {
var hasLoaded = false;
for (var j = 0; j < loadedModels.length; j ++) {
if (models[i].id == loadedModels[j].id) {
hasLoaded = true;
}
}
if (!hasLoaded) {
var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(models[i].lon, models[i].lat, models[i].height)); var model = scene.primitives.add(
Cesium.Model.fromGltf({
url: models[i].url,
modelMatrix: modelMatrix,
scale: 20.0,
name: models[i].name,
id: models[i].id
}));
loadedModels.push(model);
}
}
//var cartesian = viewer.camera.pickEllipsoid(loadedModels[0].modelMatrix, scene.globe.ellipsoid);
//alert(getEnumPropertyNames(cartesian).join('\r')); } function HideModel() {
for (var i = 0; i < loadedModels.length; i++) {
scene.primitives.remove(loadedModels[i]);
}
loadedModels = [];
} function setTips(message, close) {
if ("" == message) {
$("#message").fadeOut();
} else {
if (close != undefined && close == true) {
$("#message").html(message).fadeOut();
} else {
$("#message").html(message).fadeIn();
}
}
} function clearEffects() {
if (handler != null) {
handler.destroy();
}
} //设置各种操作模式
function SetMode(mode) {
if (mode == "drawPloy")
{
tempPoints = [];
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (click) {
var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
if (cartesian) {
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
tempPoints.push({ lon: longitudeString, lat: latitudeString });
var tempLength = tempPoints.length;
drawPoint(tempPoints[tempPoints.length-1]);
if (tempLength > 1) {
drawLine(tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1], true);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); handler.setInputAction(function (click) {
var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
if (cartesian) {
var tempLength = tempPoints.length;
if (tempLength < 3) {
alert('请选择3个以上的点再执行闭合操作命令');
} else {
drawLine(tempPoints[0], tempPoints[tempPoints.length - 1], true);
drawPoly(tempPoints);
highLightAssetsInArea(tempPoints);
alert('多边形面积' + SphericalPolygonAreaMeters(tempPoints) + '平方米');
tempPoints = [];
} }
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
else if (mode == "pickBuilding")
{
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function(click) {
var pick = scene.pick(click.position);
if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) {
for (var i = 0; i < models.length; i ++) {
if (models[i].id == pick.node._model.id) {
var modelName = models[i].name;
var modelId = models[i].id;
var modelBimId = models[i].pid;
highLigthModel(modelId);
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(models[i].lon, parseFloat(models[i].lat) - 0.01, 2000.0),
orientation: {
direction: new Cesium.Cartesian3(0.5437275903005284, -0.8386290220423197, -0.03258329225728158),
up: new Cesium.Cartesian3(0.05520718287689969, -0.00299987805272847, 0.9984704140286108)
},
complete: function() {
if (confirm("你选择的是" + modelName + ",是否查看详细模型?")) {
LoadBim(modelBimId);
}
unHighLightModel(modelId);
},
});
}
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
else if ("addPin" == mode)
{
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (click) {
var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
if (cartesian) {
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
tempPinLon = Cesium.Math.toDegrees(cartographic.longitude);
tempPinLat = Cesium.Math.toDegrees(cartographic.latitude);
$('#addPinModal').modal('show');
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
else if ("erase" == mode)
{
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (click) {
var pick = scene.pick(click.position);
if (Cesium.defined(pick) && Cesium.defined(pick.id) && Cesium.defined(pick.id._id)) {
for (var i = 0; i < models.length; i++) {
if ( pick.id != undefined && tempPinEntities[i].id == pick.id._id) {
removePoint(tempPinEntities[i]);
tempPinEntities.splice(i, 1);
}
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
else if ("drawLine" == mode)
{
tempPoints = [];
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (click) {
var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
if (cartesian) {
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
tempPoints.push({ lon: longitudeString, lat: latitudeString });
var tempLength = tempPoints.length;
drawPoint(tempPoints[tempPoints.length - 1]);
if (tempLength > 1) {
drawLine(tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1], true);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
handler.setInputAction(function (click) {
tempPoints = [];
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
else if ("drawCircle" == mode)
{
tempPoints = [];
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (click) {
var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
if (cartesian) {
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
tempPoints.push({ lon: longitudeString, lat: latitudeString });
var tempLength = tempPoints.length;
if (tempLength == 1) {
drawPoint(tempPoints[0]);
}
else if (tempLength == 2) {
drawPoint(tempPoints[1]);
drawLine(tempPoints[0], tempPoints[1], true);
//算两点间距离
var distance = getFlatternDistance(tempPoints[0].lat, tempPoints[0].lon, tempPoints[1].lat, tempPoints[1].lon); var entity =
viewer.
entities.add({
position: Cesium.Cartesian3.fromDegrees(tempPoints[0].lon, tempPoints[0].lat),
ellipse: {
semiMinorAxis: distance,
semiMajorAxis: distance,
height: 0,
material: Cesium.Color.fromRandom({ alpha: 0.8 })
}
});
tempEntities.push(entity); //高亮圈内模型
for (var i = 0; i < loadedModels.length; i++) {
for (var j = 0; j < models.length; j++) {
if (loadedModels[i].id == models[j].id && getFlatternDistance(models[j].lat, models[j].lon, tempPoints[0].lat, tempPoints[0].lon) <= distance) {
loadedModels[i].color = Cesium.Color.SPRINGGREEN;
}
}
} //面积
setTimeout(function () { alert("面积是 " + Math.PI * distance * distance + "平方米") },500); tempPoints = [];
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
else if ("drawSquare" == mode) {
tempPoints = [];
handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (click) {
var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
if (cartesian) {
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
tempPoints.push({ lon: longitudeString, lat: latitudeString });
var tempLength = tempPoints.length;
if (tempLength == 1) {
drawPoint(tempPoints[0]);
}
else if (tempLength == 2) {
//算两点间距离
var distance = getFlatternDistance(tempPoints[0].lat, tempPoints[0].lon, tempPoints[1].lat, tempPoints[1].lon); var entity =
viewer.
entities.add({
position: Cesium.Cartesian3.fromDegrees(tempPoints[0].lon, tempPoints[0].lat),
ellipse: {
semiMinorAxis: distance,
semiMajorAxis: distance,
height: 0,
material: Cesium.Color.fromRandom({ alpha: 0.8 })
}
});
tempEntities.push(entity); //高亮圈内模型
for (var i = 0; i < loadedModels.length; i++) {
for (var j = 0; j < models.length; j++) {
if (loadedModels[i].id == models[j].id && getFlatternDistance(models[j].lat, models[j].lon, tempPoints[0].lat, tempPoints[0].lon) <= distance) {
loadedModels[i].color = Cesium.Color.SPRINGGREEN;
}
}
} tempPoints = [];
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
} function drawPoint(point) {
var entity =
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat),
point: {
pixelSize: 10,
color: Cesium.Color.CHARTREUSE
}
});
tempEntities.push(entity);
} function removePoint(entity) {
viewer.entities.remove(entity);
} function drawLine(point1, point2, showDistance) {
var entity =
viewer.entities.add({
polyline: {
positions: [Cesium.Cartesian3.fromDegrees(point1.lon, point1.lat), Cesium.Cartesian3.fromDegrees(point2.lon, point2.lat)],
width: 10.0,
material: new Cesium.PolylineGlowMaterialProperty({
color: Cesium.Color.CHARTREUSE.withAlpha(.5)
})
}
});
tempEntities.push(entity);
if (showDistance) {
var w = Math.abs(point1.lon - point2.lon);
var h = Math.abs(point1.lat - point2.lat);
var offsetV = w >= h ? 0.0005 : 0;
var offsetH = w < h ? 0.001 : 0;
var distance = getFlatternDistance(point1.lat, point1.lon, point2.lat, point2.lon);
entity =
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(((point1.lon + point2.lon) / 2) + offsetH,
((point1.lat + point2.lat) / 2) + offsetV),
label: {
text: distance.toFixed(1) + 'm',
font: '22px Helvetica',
fillColor: Cesium.Color.WHITE
}
});
tempEntities.push(entity);
}
} function drawPoly(points) {
var pArray = [];
for (var i = 0; i < points.length; i ++) {
pArray.push(points[i].lon);
pArray.push(points[i].lat);
}
var entity =
viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(pArray)),
material: Cesium.Color.CHARTREUSE.withAlpha(.5)
}
});
tempEntities.push(entity);
} function getColor(colorName, alpha) {
var color = Cesium.Color[colorName.toUpperCase()];
return Cesium.Color.fromAlpha(color, parseFloat(alpha));
} //判断点是否在多边形内
function PointInPoly(point, polyPoints) {
for (var c = false, i = -1, l = polyPoints.length, j = l - 1; ++i < l; j = i)
((polyPoints[i].lat <= point.lat && point.lat < polyPoints[j].lat) || (polyPoints[j].lat <= point.lat && point.lat < polyPoints[i].lat))
&& (point.lon < (polyPoints[j].lon - polyPoints[i].lon) * (point.lat - polyPoints[i].lat) / (polyPoints[j].lat - polyPoints[i].lat) + polyPoints[i].lon)
&& (c = !c);
return c;
} //选区内模型高亮
function highLightAssetsInArea(points) { for (var i = 0; i < loadedModels.length; i++) {
for (var j = 0; j < models.length; j ++) {
if (loadedModels[i].id == models[j].id && PointInPoly(models[j], points)) {
loadedModels[i].color = Cesium.Color.SPRINGGREEN;
}
}
}
} //高亮模型
function highLigthModel(modelId) {
for (var i = 0; i < loadedModels.length; i ++) {
if (loadedModels[i].id == modelId) {
loadedModels[i].color = Cesium.Color.SPRINGGREEN;
}
}
} //取消高亮模型
function unHighLightModel(modelId) {
for (var i = 0; i < loadedModels.length; i++) {
if (loadedModels[i].id == modelId) {
loadedModels[i].color = {
red: 1,
green: 1,
blue: 1,
alpha: 1
};
}
}
} //定位
function goLocation() {
$('#flyToModal').modal('hide');
$('#flyToModal').on('hidden.bs.modal', function(e) {
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees($("#jumpLon").val(), $("#jumpLat").val(), 1000.0)
});
});
} //加点
function addPin() {
$('#addPinModal').modal('hide');
var pin = viewer.entities.add({
name: $("#pinContent").val(),
position: Cesium.Cartesian3.fromDegrees(tempPinLon, tempPinLat),
billboard: {
image: $("#pinLabel").val() == "" ? pinBuilder.fromColor(Cesium.Color[$("#pinColor").val().toUpperCase()], 48).toDataURL() :
pinBuilder.fromText($("#pinLabel").val(), Cesium.Color[$("#pinColor").val().toUpperCase()], 64).toDataURL(),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
}
});
tempPinEntities.push(pin);
$("#pinLabel").val("");
$("#pinContent").val("");
} //计算两点间距离
function getFlatternDistance(lat1, lng1, lat2, lng2) {
var EARTH_RADIUS = 6378137.0; //单位M
var PI = Math.PI; function getRad(d) {
return d * PI / 180.0;
}
var f = getRad((lat1 + lat2) / 2);
var g = getRad((lat1 - lat2) / 2);
var l = getRad((lng1 - lng2) / 2); var sg = Math.sin(g);
var sl = Math.sin(l);
var sf = Math.sin(f); var s, c, w, r, d, h1, h2;
var a = EARTH_RADIUS;
var 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));
} //计算多边形面积
var earthRadiusMeters = 6371000.0;
var metersPerDegree = 2.0 * Math.PI * earthRadiusMeters / 360.0;
var radiansPerDegree = Math.PI / 180.0;
var degreesPerRadian = 180.0 / Math.PI;
var pointArr;
function SphericalPolygonAreaMeters(points) {
var totalAngle = 0;
for (var i = 0; i < points.length; i++) {
var j = (i + 1) % points.length;
var k = (i + 2) % points.length;
totalAngle += Angle(points[i], points[j], points[k]);
}
var planarTotalAngle = (points.length - 2) * 180.0;
var sphericalExcess = totalAngle - planarTotalAngle;
if (sphericalExcess > 420.0) {
totalAngle = points.length * 360.0 - totalAngle;
sphericalExcess = totalAngle - planarTotalAngle;
} else if (sphericalExcess > 300.0 && sphericalExcess < 420.0) {
sphericalExcess = Math.abs(360.0 - sphericalExcess);
}
return sphericalExcess * radiansPerDegree * earthRadiusMeters * earthRadiusMeters;
} /*角度*/
function Angle(p1, p2, p3) {
var bearing21 = Bearing(p2, p1);
var bearing23 = Bearing(p2, p3);
var angle = bearing21 - bearing23;
if (angle < 0) {
angle += 360;
}
return angle;
}
/*方向*/
function Bearing(from, to) {
var lat1 = from.lat * radiansPerDegree;
var lon1 = from.lon * radiansPerDegree;
var lat2 = to.lat * radiansPerDegree;
var lon2 = to.lon * radiansPerDegree;
var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
if (angle < 0) {
angle += Math.PI * 2.0;
}
angle = angle * degreesPerRadian;
return angle;
} function LoadBim(projId) {
//加载模型
$('#myTabs li:eq(1) a').tab('show'); }
开源三维地球GIS引擎Cesium常用功能的开发的更多相关文章
- 驰骋开源的asp.net工作流程引擎java工作流 2015 正文 驰骋工作流引擎ccflow6的功能列表
关键词: 驰骋工作流引擎 ccflow的功能列表 工作流功能列表 表单引擎功能列表 我们工作流引擎ccflow6重构之后对功能做了一些调整,要想快速了解ccbpm的功能,可以以下面列表为准 ...
- 无插件,跨平台,基于WebGL的三维地球来了!!!
用户通过浏览器即可递交数据到同一个地理信息系统中,操作简单,跨平台 ,无插件,可扩展,高效共享 ,完美匹配超大数据量发布! 近年来,随着计算机图形学.虚拟现实.卫星遥感.航空摄影.激光雷达等技术的迅猛 ...
- 开源项目OEIP 游戏引擎与音视频多媒体(UE4/Unity3D)
现开源一个项目 OEIP 项目实现的功能Demo展示 这个项目演示了在UE4中,接入摄像机通过OEIP直接输出到UE4纹理上,并直接把UE4里的RenderTarget当做输入源通过OEIP里GPU管 ...
- C#两行代码实现三维地球
一. 为什么要用三维地球? 三维地球是地理信息技术的一个重要发展方向,相比较二维地图技术,三维地球最大的特点是更直观更形象地表达地理信息和空间上的方位.我们可以在三维气象模拟. ...
- 前端3D引擎-Cesium自定义动态材质
本文代码基于Vue-cli4和使用WebGL的地图引擎Cesium,主要内容为三维场景下不同对象的动态材质构建. 参考了很多文章,链接附在文末. 为不同的几何对象添加动态材质 不知道这一小节的名称概况 ...
- JavaScript 常用功能总结
小编吐血整理加上翻译,太辛苦了~求赞! 本文主要总结了JavaScript 常用功能总结,如一些常用的JS 对象,基本数据结构,功能函数等,还有一些常用的设计模式. 目录: 众所周知,JavaScri ...
- CSS3常用功能的写法
随着浏览器的升级,CSS3已经可以投入实际应用了. 但是,不同的浏览器有不同的CSS3实现,兼容性是一个大问题.上周的YDN介绍了CSS3 Please网站,该网站总结了一些常用功能的写法. 以下就是 ...
- Keil的使用方法 - 常用功能(一)
Ⅰ.概述 学习一门软件的开发,开发工具的掌握可以说尤为重要.由于Keil集成开发工具支持多种MCU平台的开发,是市面上比较常见的,也是功能比较强大一款IDE.所以,对于大多数人说,选择Keil几乎是单 ...
- CSS3常用功能的写法 转
CSS3常用功能的写法 作者: 阮一峰 随着浏览器的升级,CSS3已经可以投入实际应用了. 但是,不同的浏览器有不同的CSS3实现,兼容性是一个大问题.上周的YDN介绍了CSS3 Please网站 ...
随机推荐
- java 类方法和实例方法 以及 类变量和实例变量
类体中的方法分为实例方法和类方法两种,用static修饰的是类方法 类方法: 对于类中的类方法,在该类被加载到内存时,就分配了相应的入口地址.从而类方法不仅可以被类创建的任何对象调用执行,也可以直接通 ...
- shell 变量的间接引用
参考: 高级 bash 脚本编程指南 eval var1=\$$var2 变量间接引用 贴个脚本: server1=1.1.1.1 server2=1.1.1.2 server3=1.1.1.3 fo ...
- dotnet core 自定义配置文件
首先添加一个.json 文件,比如 setting.json 文件内容如下,记得把文件设置为“复制到输出目录” { "ConfigSetting": { "XXXName ...
- [js高手之路] vue系列教程 - 事件专题(4)
本文主要讲解事件冒泡,事件绑定的简写,事件默认行为,按键码等一系列与事件相关的知识. 一.事件绑定的简写,@事件类型. 之前我的[js高手之路] vue系列教程 - vue的事件绑定与方法(2) 用 ...
- TurnipBit之DIY无线遥控智能小车
一.准备工作 TurnipBit 开发板 2块 TurnipBit 扩展板 1块 数据线 1条 智能小车器件 1套 电机驱动模块(L298N) 1个 在线可视化编程 点击进入 二.思路设计 2 ...
- TurnipBit—MicroPython开发板:从积木式编程语言开始学做小小创客
编程.建模.制作动画和游戏--这些当初我们默认只有成年人玩得转的事情,现在早已经被无数小孩子给颠覆甚至玩出新境界了.热爱科技和动手的"创客"(Maker)现在在全世界都炙手可热.今 ...
- SQLserver中小数点怎么自定义取的问题
第一次写博客,正好我也在写作业的时候遇到了这个问题,所以就看看 我正在写T-SQL的代码!在经过计算后 结果的小数点多了几位,很烦躁,所以百度了一个方法"round(数字,保留几位小数),两 ...
- android利用adb安装应用程序出现“more than one device and emulator wait for device ”
今天,写自动化脚本时,因在这之前进行了一下真机版本的更新,还没有从电脑上拔出,就又在adt打开了一个AVD. 于是,自由自在的就去写脚本了,企图在emulator上装一个APK,在cmd窗口下,利用: ...
- 【转载】漫谈HADOOP HDFS BALANCER
Hadoop的HDFS集群非常容易出现机器与机器之间磁盘利用率不平衡的情况,比如集群中添加新的数据节点.当HDFS出现不平衡状况的时候,将引发很多问题,比如MR程序无法很好地利用本地计算的优势,机器之 ...
- 0.python class
http://pythonprogramminglanguage.com/ 什么是python? python是一款让你工作比起用其他语言更快的编程语言.老练的程序员用其他的语言会比用python更顺 ...