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

443 lines
18 KiB
JavaScript
Raw Permalink Normal View History

2019-11-21 15:46:14 +08:00
/*
* @Descripttion:
* @version: 1.0
* @Author: zhangti
* @Date: 2019-09-20 09:32:20
* @LastEditors : sueRimn
* @LastEditTime : 2020-01-02 12:12:49
2019-11-21 15:46:14 +08:00
*/
/**
* 动态画实体
*/
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 +')';
2019-11-21 15:46:14 +08:00
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);
2019-11-21 15:46:14 +08:00
};
//实时更新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)
}
}