cesium-examples/map/3d/code/entityFactory.js

443 lines
18 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Descripttion:
* @version: 1.0
* @Author: zhangti
* @Date: 2019-09-20 09:32:20
* @LastEditors : sueRimn
* @LastEditTime : 2020-01-02 12:12:49
*/
/**
* 动态画实体
*/
export default 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)
}
}