UNPKG

gisthreemap

Version:

基于webGL的三维api

437 lines (426 loc) 18.2 kB
/** * 动态画实体 */ class entityFactory{ constructor(obj){ //初始化 this.options = null switch(obj.type){ case 'triangleMeasure':this.createTriangleMeasure(obj.data);break case 'createLine' :this.createLine(obj.data);break case 'dynamicCylinder' :this.dynamicCylinder(obj.data);break case 'createPolygon' :this.createPolygon(obj.data);break case 'createScan' :this.createScan(obj.data);break } return this.options } /** * 动态创建三角形 * 应用于 三角测量 * @param {*} poly */ createTriangleMeasure(poly){ this.options = { name: poly.name, polyline: { show: true, positions: [], material: Cesium.Color.GOLD, width: 2 }, label: { font: '18px sans-serif', fillColor: Cesium.Color.GOLD, style: Cesium.LabelStyle.FILL_AND_OUTLINE, outlineWidth: 2, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: poly.label.offset } }; this.positions = poly.positions this.label = poly.label //实时更新polygon.hierarchy var _self = this var _update = function () { return _self.positions }; var _update_label = function () { if(_self.positions.length == 1) return false return _self.positions[1] }; var _text = function () { if(typeof _self.label.fn == 'function'){ //fn 转换函数 scaler 换算 unit 单位 var text_temp = _self.label.fn(_self.positions) text_temp = poly.name + ' : ' + (text_temp / _self.label.scaler).toFixed(3) + ' ('+_self.label.unit +')' return text_temp } }; this.options.polyline.positions = new Cesium.CallbackProperty(_update, false) this.options.position = new Cesium.CallbackProperty(_update_label, false) this.options.label.text = new Cesium.CallbackProperty(_text, false) } /** * 动态创建直线 * @param {*} positions */ createLine(opt){ this.options = { name: '直线', polyline: { show: true, positions: [], material: opt.material == undefined ? Cesium.Color.CHARTREUSE : opt.material, width: opt.width == undefined ? 5 : opt.width, clampToGround:opt.clampToGround == undefined ? false : true //贴地 } }; this.positions = opt.positions //实时更新polyline.positions var _self = this; var _update = function () { return _self.positions }; this.options.polyline.positions = new Cesium.CallbackProperty(_update, false) } /** * 动态绑定柱体 * 应用于 卫星过境 无人机 * 扫描 * @param {*} obj */ dynamicCylinder(obj){ let c = obj.cylinder this.options = { cylinder: { HeightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, //表示相对于地形的位置。 length: c.length, //长度 topRadius:0, //顶点半径 bottomRadius:c.bottomRadius, //底部半径 material:new Cesium.Color(0, 1, 1, .4), slices:c.slices } } this.positions = obj.positions this.entity = obj.entity this.v = obj.v var _self = this var _update = function(){ var positions = _self.entity.position.getValue(_self.v.clock.currentTime) var cartographic = _self.v.scene.globe.ellipsoid.cartesianToCartographic(positions) var lat = Cesium.Math.toDegrees(cartographic.latitude) , lng = Cesium.Math.toDegrees(cartographic.longitude) ,hei = parseFloat(cartographic.height/4) return Cesium.Cartesian3.fromDegrees(lng, lat,0) } var _length = function(){ var positions = _self.entity.position.getValue(_self.v.clock.currentTime) var cartographic = _self.v.scene.globe.ellipsoid.cartesianToCartographic(positions) return cartographic.height * 2 } this.options.position = new Cesium.CallbackProperty(_update,false) this.options.cylinder.length = new Cesium.CallbackProperty(_length,false) } /** * 动态创建多边形 * 应用 面积量测 淹没分析 * @param {*} positions */ createPolygon(obj){ try { this.options = { name:'多边形', polygon : { hierarchy : [], // perPositionHeight : true, material : obj.material == undefined ? Cesium.Color.CHARTREUSE.withAlpha(0.3):obj.material, //Cesium.Color.CHARTREUSE.withAlpha(0.5) // heightReference:20000 } } this.hierarchy = obj.positions let _self = this let _update = function(){ return new Cesium.PolygonHierarchy(_self.hierarchy) }; //实时更新polygon.hierarchy this.options.polygon.hierarchy = new Cesium.CallbackProperty(_update,false) } catch (error) { console.log(error) } } /*** * 创建扫描实体 * opt.v * opt.positions * positions{lat,lon,alt} */ createScan(opt){ let _self = this,viewer= opt.v,length = opt.positions.alt _self.modelMatrix = opt.modelMatrix // 4 创建雷达放射波 var cylinderGeometry = new Cesium.CylinderGeometry({ // 4.1 先创建Geometry length:length, topRadius: 0.0, bottomRadius: length * 0.5, //vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT vertexFormat: Cesium.MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat }); var redCone = new Cesium.GeometryInstance({ // 4.2 创建GeometryInstance geometry: cylinderGeometry, modelMatrix:_self.modelMatrix, // attributes : { // color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED) // } }) var radar = viewer.scene.primitives.add(new Cesium.Primitive({// 4.3 创建Primitive geometryInstances: [redCone], // appearance : new Cesium.PerInstanceColorAppearance({ // closed : true, // translucent: false // }) appearance: new Cesium.MaterialAppearance({ // 贴图像纹理 // material: Cesium.Material.fromType('Image', { // image: '../../SampleData/models/CesiumBalloon/CesiumBalloonPrint_singleDot.png' // }), // 贴棋盘纹理 // material: Cesium.Material.fromType('Checkerboard'), // 自定义纹理 material: new Cesium.Material({ fabric: { type: 'VtxfShader1', uniforms: { color: new Cesium.Color(0.2, 1.0, 0.0, 1.0), repeat: 30.0, offset: 0.0, thickness: 0.3, }, source: ` uniform vec4 color; uniform float repeat; uniform float offset; uniform float thickness; czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material = czm_getDefaultMaterial(materialInput); float sp = 1.0/repeat; vec2 st = materialInput.st; float dis = distance(st, vec2(0.5)); float m = mod(dis + offset, sp); float a = step(sp*(1.0-thickness), m); material.diffuse = color.rgb; material.alpha = a * color.a; return material; } ` }, translucent: false }), faceForward : false, // 当绘制的三角面片法向不能朝向视点时,自动翻转法向,从而避免法向计算后发黑等问题 closed: true // 是否为封闭体,实际上执行的是是否进行背面裁剪 }), })) // 5 动态修改雷达材质中的offset变量,从而实现动态效果。 viewer.scene.preUpdate.addEventListener(function() { var offset = radar.appearance.material.uniforms.offset offset -= 0.001; if (offset > 1.0) { offset = 0.0; } radar.appearance.material.uniforms.offset = offset }) let _update = function(){ return _self.modelMatrix } radar.modelMatrix = new Cesium.CallbackProperty(_update,true) return radar } /** * 创建移动扫描物 * createLightScan var data={ circle:[0.003,117,35,30]// 第一个参数 0.003表示半径,第二个第三个分别表示底座圆心的坐标,第四个表示切割成多少个点。组成多少个面。越多会越卡 尽量实际项目不影响效果,越少越好。 ,observer:[117.01,35.01,500]//观察点,也就是光源点 ,positionList:[ //我们这里就不加高度了。不然太麻烦了 //以圆心为参考做偏移值获取,圆心坐标 [117,35],简单点画个正方形吧 如果画圆的画,也可以多取点 [117,35],//初始位置 (圆心坐标 [117,35]要和这个初始位置统一,不然会偏移出去) [117.01,35], //下一个点 [117.01,35.01], [117,35.01], [117,35],//回来 ] ,material:Cesium.Color.RED.withAlpha(0.5)//光的材质 ,number:100//数字越小速度越快 }; */ static createLightScan(opt){ let viewer = opt.v, data = opt.data; let point = LightScanHelps.createLightScan_getCirclePoints(data.circle[0],data.circle[1],data.circle[2],data.circle[3]) //生成分割点 let entityCList =LightScanHelps.createLightScan_entityCList(viewer,point,data) //生成 entityCList 圆锥 LightScanHelps.createLightScan_changeAllPosition(data,entityCList,point) //运行 return entityCList } /** * 灯光随着模型变化 * 模型需要播放动画 * czml * @param {*} viewer * @param {*} data * @param {*} model */ static createLightScanFollowEntity(opt){ let viewer = opt.v, data = opt.data, model = opt.model let point = LightScanHelps.createLightScan_getCirclePoints(data.circle[0],data.circle[1],data.circle[2],data.circle[3]) //生成分割点 let entityCList=LightScanHelps.createLightScan_entityCList(viewer,point,data) //生成 entityCList 圆锥 viewer.scene.postRender.addEventListener(function () { // 实时获取模型的经纬度。 let center =model.position.getValue(viewer.clock.currentTime)//获取模型当前位置 //世界坐标(笛卡尔坐标) if(center){ let ellipsoid=viewer.scene.globe.ellipsoid let cartographic=ellipsoid.cartesianToCartographic(center) let lon=Cesium.Math.toDegrees(cartographic.longitude) let lat=Cesium.Math.toDegrees(cartographic.latitude) //var height=cartographic.height; //console.log(lon+";"+lat+";"+height); let X0=lon-data.circle[1],Y0=lat-data.circle[2] //差值 for(let i=0;i<entityCList.length;i++){ if(i==(entityCList.length-1)){ f(entityCList[i],[point[i].x, point[i].y, point[0].x, point[0].y],X0,Y0) }else{ f(entityCList[i],[point[i].x, point[i].y, point[i+1].x, point[i+1].y],X0,Y0) } } } }); //修改每一个entity function f(entity,arr,X0,Y0) { entity.polygon.hierarchy=new Cesium.CallbackProperty(function () { //回调函数 return new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights( [ data.observer[0],data.observer[1],data.observer[2],//观察点 arr[0]+X0,arr[1]+Y0,0, arr[2]+X0,arr[3]+Y0,0 ])) },false) } return entityCList } } /** * 灯光移动扫描 * 辅助函数 */ class LightScanHelps { constructor(){} /* * 求圆周上等分点的坐标 * ox,oy为圆心坐标 * r为半径 * count为等分个数 */ static createLightScan_getCirclePoints(r, ox, oy, count){ var point = [] //结果 var radians = (Math.PI / 180) * Math.round(360 / count), //弧度 i = 0; for(; i < count; i++){ var x = ox + r * Math.sin(radians * i), y = oy + r * Math.cos(radians * i) point.unshift({x:x,y:y}) //为保持数据顺时针 } return point } /** * 生成 entityCList面--形成圆锥 * @param {*} viewer * @param {*} point * @param {*} data */ static createLightScan_entityCList(viewer,point,data){ let lon=data.observer[0],lat=data.observer[1],h=data.observer[2] let entityCList=[] //创建 面 for(let i=0;i<point.length;i++){ let hierarchy if(i==(point.length-1)){ hierarchy = new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights( [ lon,lat,h, point[i].x,point[i].y,0, point[0].x,point[0].y,0 ])) }else{ hierarchy = new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights( [ lon,lat,h, point[i].x,point[i].y,0, point[i+1].x,point[i+1].y,0 ])) } let entityC= viewer.entities.add({ name:"三角形", polygon : { hierarchy:hierarchy, outline : false, perPositionHeight:true,//允许三角形使用点的高度 material :data.material } }); entityCList.push(entityC) } return entityCList } /** * 改变所有面的位置 * @param {*} data * @param {*} entityCList * @param {*} point */ static createLightScan_changeAllPosition (data,entityCList,point){ for(let i=0;i<entityCList.length;i++){ if(i!=entityCList.length-1){ this.createLightScan_changeOnePosition(data,entityCList[i],[point[i].x, point[i].y, point[i+1].x, point[i+1].y]); //中间arr 代表的是点的坐标 }else{ this.createLightScan_changeOnePosition(data,entityCList[i],[point[i].x, point[i].y, point[0].x, point[0].y]); } } } /** * 改变每个面的位置 * @param {*} data * @param {*} entity * @param {*} arr */ static createLightScan_changeOnePosition(data,entity,arr){ let positionList=data.positionList let x,y,x0,y0,X0,Y0,n=0,a=0//x代表差值 x0代表差值等分后的值,X0表示每次回调改变的值。a表示回调的循环窜次数,n表示扫描的坐标个数 function f(i){ x= positionList[i+1][0]-positionList[i][0]//差值 y= positionList[i+1][1]-positionList[i][1]//差值 x0=x/data.number//将差值等分500份 y0=y/data.number a=0 } f(n) entity.polygon.hierarchy=new Cesium.CallbackProperty(function () { //回调函数 if((Math.abs(X0)>=Math.abs(x))&&(Math.abs(Y0)>=Math.abs(y))){ //当等分差值大于等于差值的时候 就重新计算差值和等分差值 Math.abs n=n+1 if(n==positionList.length-1){ n=0 } arr[0]= arr[0]+X0 arr[1]= arr[1]+Y0 arr[2]= arr[2]+X0 arr[3]= arr[3]+Y0 f(n)//重新赋值 x y x0 y0 } X0=a*x0//将差值的等份逐渐递增。直到大于差值 会有精度丢失,所以扩大再加 x0=x0+0.0001 Y0=a*y0//将差值的等份逐渐递增。直到大于差值 会有精度丢失,所以扩大再加 a++; return new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights( [ data.observer[0],data.observer[1],data.observer[2], arr[0]+X0,arr[1]+Y0,0, arr[2]+X0,arr[3]+Y0,0 ])) },false) } } export default entityFactory