效果图
代码思路,根据起点终点坐标以及需要设置的抛物线高度生成抛物线坐标串,然后根据坐标串生成cesium实体线,并修改材质为流动线
viewer.entities.removeById('pwxline')
viewer.entities.removeById('verticalPwxline')
let startPoint = this.clickPoint
let endPoint = row.geoPositon.split(',')
let height = this.getFlatternDistance(startPoint.lat, startPoint.lng, parseFloat(endPoint[1]), parseFloat(endPoint[0]))//高度是根据起始点距离的一半
let positions = this.parabolaEquation({//生成抛物线代码
startPoint: { lng: parseFloat(endPoint[0]), lat: parseFloat(endPoint[1]) },
endPoint: { lng: startPoint.lng, lat: startPoint.lat },
height: height / 2,
num: 100
})
this.positionsParabola2.push(positions) //获取抛物线坐标串
let postionarry = []
for (let i = 0; i < positions.length; i++) {
postionarry.push(positions[i].lng, positions[i].lat, positions[i].height)
}
//let entity = viewer.entities.getOrCreateEntity(this.PDPointSelectID)
//因为流动线材质代码
require('../../../../assets/plugins/PolylineTrailLinkMaterial')
let model = viewer.entities.add({
id: 'pwxline',
name: 'polyline',
polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights(postionarry),
width: 20,
material: new Cesium.PolylineTrailLinkMaterialProperty(Cesium.Color.AQUA, 5000)//修改抛物线材质
}
})
let verticalPwxlinePosition = []
verticalPwxlinePosition.push(parseFloat(endPoint[0]), parseFloat(endPoint[1]), 0)
verticalPwxlinePosition.push(parseFloat(endPoint[0]), parseFloat(endPoint[1]), 55)
viewer.entities.add({
id: 'verticalPwxline',
name: 'verticalPwxline',
polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights(verticalPwxlinePosition),
width: 5,
material: Cesium.Color.AQUA.withAlpha(0.5)
}
})
viewer.flyTo(model, {
complete: () => {}
})
生成抛物线代码
parabolaEquation(options) {
// 方程 y=-(4h/L^2)*x^2+h h:顶点高度 L:横纵间距较大者
const h = options.height && options.height > 50 ? options.height : 50
const L =
Math.abs(options.startPoint.lng - options.endPoint.lng) > Math.abs(options.startPoint.lat - options.endPoint.lat)
? Math.abs(options.startPoint.lng - options.endPoint.lng)
: Math.abs(options.startPoint.lat - options.endPoint.lat)
const num = options.num && options.num > 50 ? options.num : 50
const result = []
let dlt = L / num
if (Math.abs(options.startPoint.lng - options.endPoint.lng) > Math.abs(options.startPoint.lat - options.endPoint.lat)) {
//以 lng 为基准
const delLat = (options.endPoint.lat - options.startPoint.lat) / num
if (options.startPoint.lng - options.endPoint.lng > 0) {
dlt = -dlt
}
for (let i = 0; i < num; i++) {
const tempH = h - (Math.pow(-0.5 * L + Math.abs(dlt) * i, 2) * 4 * h) / Math.pow(L, 2)
const lng = options.startPoint.lng + dlt * i
const lat = options.startPoint.lat + delLat * i
result.push({ lng, lat, height: tempH })
}
} else {
//以 lat 为基准
let dellng = (options.endPoint.lng - options.startPoint.lng) / num
if (options.startPoint.lat - options.endPoint.lat > 0) {
dlt = -dlt
}
for (let i = 0; i < num; i++) {
const tempH = h - (Math.pow(-0.5 * L + Math.abs(dlt) * i, 2) * 4 * h) / Math.pow(L, 2)
const lng = options.startPoint.lng + dellng * i
const lat = options.startPoint.lat + dlt * i
result.push({ lng, lat, height: tempH })
}
}
// 落地
result.push({ lng: options.endPoint.lng, lat: options.endPoint.lat, height: options.endPoint.height || 0 })
return result
},
流动线代码
// 流动线纹理
function PolylineTrailLinkMaterialProperty(color, duration) {
this._definitionChanged = new Cesium.Event()
this._color = undefined
this._colorSubscription = undefined
this.color = color
this.duration = duration
this._time = new Date().getTime()
}
Object.defineProperties(PolylineTrailLinkMaterialProperty.prototype, {
isConstant: {
get: function () {
return false
}
},
definitionChanged: {
get: function () {
return this._definitionChanged
}
},
color: Cesium.createPropertyDescriptor('color')
})
PolylineTrailLinkMaterialProperty.prototype.getType = function (time) {
return 'PolylineTrailLink'
}
PolylineTrailLinkMaterialProperty.prototype.getValue = function (time, result) {
if (!Cesium.defined(result)) {
result = {}
}
result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color)
result.image = Cesium.Material.PolylineTrailLinkImage
result.time = ((new Date().getTime() - this._time) % this.duration) / this.duration
return result
}
PolylineTrailLinkMaterialProperty.prototype.equals = function (other) {
return this === other || (other instanceof PolylineTrailLinkMaterialProperty && Cesium.Property.equals(this._color, other._color))
}
Cesium.PolylineTrailLinkMaterialProperty = PolylineTrailLinkMaterialProperty
Cesium.Material.PolylineTrailLinkType = 'PolylineTrailLink'
Cesium.Material.PolylineTrailLinkImage = '/static/images/a3.png' //图片 图片为箭头
Cesium.Material.PolylineTrailLinkSource =
'czm_material czm_getMaterial(czm_materialInput materialInput)\n\
{\n\
czm_material material = czm_getDefaultMaterial(materialInput);\n\
vec2 st = materialInput.st;\n\
vec4 colorImage = texture2D(image, vec2(fract(st.s - time), st.t));\n\
material.alpha = colorImage.a * color.a;\n\
material.diffuse = (colorImage.rgb+color.rgb)/2.0;\n\
return material;\n\
}'
Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailLinkType, {
fabric: {
type: Cesium.Material.PolylineTrailLinkType,
uniforms: {
color: new Cesium.Color(255.0, 255.0, 255.0, 1),
image: Cesium.Material.PolylineTrailLinkImage,
time: 0
},
source: Cesium.Material.PolylineTrailLinkSource
},
translucent: function (material) {
return true
}
})
计算起始点距离代码
//计算两点间距离
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))
},