一、SuperMap引入在线tileset
这块tileset服务是同事发布在服务器上的服务,我们直接通过supermap的api引入即可,这里需要注意的是倾斜摄影数据默认的地理坐标系与超图的坐标系不一样,所以我们需要手动转一下椭球体,不然会发生坐标偏移导致你找不到自己添加的tileset位置。
//转椭球体
var obj = [6378137.0, 6378137.0, 6356752.3142451793];
Cesium.Ellipsoid.WGS84 = Object.freeze(
new Cesium.Ellipsoid(obj[0], obj[1], obj[2])
);
//添加tileset
let ts = new Cesium.Cesium3DTileset({
url: url,//改为自己要添加的tileset链接或json文件位置
clippingPlanes: clippingPlanes,//裁切平面集合
maximumScreenSpaceError: 18, //最大的屏幕空间误差
maximumNumberOfLoadedTiles: 1600, //最大加载瓦片个数
});
let tileset = viewer.scene.primitives.add(ts);
viewer.zoomTo(tileset);//调整视角到tileset位置
最基础的添加相信大家都没什么问题,如果有什么不会的也可以去网上搜索一下教程。
二、tileset简单裁切
这里添加好瓦片之后就可以进行第一步的简单裁切了,这里博主主要用的是clippingPlanes去添加裁切平面来完成瓦片的简单裁切。
添加tileset前,先初始化裁切平面集合,由于我这边的效果初始时要完整展示瓦片集,所以planes先置空。
let clippingPlanes = new Cesium.ClippingPlaneCollection({
planes: [],
enabled: true,
unionClippingRegions: true,
});
当我需要进行简单裁切时,可以通过clippingPlanes.add函数向集合中添加裁切平面。
clippingPlanes.removeAll();
let r = Number(radius) / 2;//radius为页面上设置的裁切半径数值
clippingPlanes.add(
new Cesium.ClippingPlane(new Cesium.Cartesian3(-1.0, 0.0, 0.0), r)
);
clippingPlanes.add(
new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), r)
);
clippingPlanes.add(
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), r)
);
clippingPlanes.add(
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, -1.0, 0.0), r)
);
我这里添加的裁切平面集合的裁切效果是一个中心点在tileset原点的正方形,Cesium.ClippingPlane是裁切平面的构造函数,其中第一个参数是平面的法线(归一化),如果想要调整裁切的形状可以通过调整这个参数来旋转裁切平面,或者添加更多平面。
第二个参数是平面到原点的的最短距离,这个值可以为负数,值的正负会决定平面在原点的哪一侧,如果想改变裁切的大小,可以改变这个值,这个值的单位博主暂时没有找到是什么,但是通过一些地理数据的判断,将这个值除以2大致的显示效果会比较符合米的单位,博主比较菜,如果有哪位读者知道这块内容可以在评论区指点一下博主,感谢。
顺便放一下裁切后和裁切前的效果图。
三、tileset移动裁切
上述简单裁切功能过于简单,不够实用,局限性比较大,而移动裁切自由度就相对来说较高,实用性也比较强。
移动裁切的实现其实也并不困难,博主的思路是通过鼠标点击位置与平面中心点也就是默认裁切的中心的距离和夹角,来计算裁切中心相对于默认裁切各个方向的分量,然后将这个分量附加到裁切半径上,这样就可以在不改变裁切形状情况下移动裁切位置了。
这里使用ScreenSpaceEventHandler函数来创建屏幕空间的事件对象,通过点击事件回调函数的默认参数来获取此次点击的信息。然后通过点击的坐标和中心点坐标的角度和距离来计算偏移量,然后通过简单裁切中添加裁切面的方法来添加裁切面即可。
这块由于博主的计算方法略有问题,导致点击位置与显示位置有百米左右的偏差,所以具体的计算代码就不放出来误导大家了。
移动裁剪效果:
四、裁剪横截面测量
最后要做的是横截面测量,这个其实也是相当简单的一个功能了,通过viewer.scene.pick函数来判断选择的点是否在你的瓦片集上,然后通过坐标计算高度差即可,期间可以通过一些自己的方式来引导和规范用户操作。
//跟随鼠标移动的tooltip工具
function createTooltip (frameDiv) {
var tooltip1 = function (frameDiv) {
var div = document.createElement('DIV');
div.className = "twipsy right";
var arrow = document.createElement('DIV');
arrow.className = "twipsy-arrow";
div.appendChild(arrow);
var 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);
var that = this;
div.onmousemove = function (evt) {
that.showAt({ x: evt.clientX, y: evt.clientY }, that.message);
};
};
tooltip1.prototype.setVisible = function (visible) {
this._div.style.display = visible ? 'block' : 'none';
};
tooltip1.prototype.showAt = function (position, message) {
if (position && message) {
this.setVisible(true);
this._title.innerHTML = message;
this._div.style.left = position.x + 10 + "px";
this._div.style.top = (position.y - this._div.clientHeight / 2) + "px";
this.message = message;
}
};
return new tooltip1(frameDiv);
}
这块我只给用户选中的位置添加了两个提示的点,如果追求更好的效果可以再加一些线条之类的,测量效果展示: