Cesium抛物线方程

15 篇文章 0 订阅
12 篇文章 18 订阅

公司项目上有两个功能模块,进口贸易和出口贸易。属于全球性质的,拿到两个坐标之后,需要有一根抛物连线连接这两个点。有时候一根线需要跨越半个地球,就导致了有些线会出现穿地的现象。

因为使用的是path,有线条动画,没有使用polyline。如果是用polyline的话,不会有穿地的情况发生,而是会近乎贴着地面。

原先项目上的处理方法是:已知两个坐标点,已知设定的动画时间。使用SampledPositionProperty方法来求中间点。然后三个点连成一条线。

// 86400 总时间,43200就是中间时刻
var startTime = viewer.clock.startTime;
var midTime = Cesium.JulianDate.addSeconds(startTime, 43200, new Cesium.JulianDate());
var stopTime = Cesium.JulianDate.addSeconds(startTime, 86400, new Cesium.JulianDate());

// 从地点坐标到终点坐标,在中间时刻就是中点
var property = new Cesium.SampledPositionProperty();
var startPosition = Cesium.Cartesian3.fromDegrees(起点坐标, 起点坐标, 0);
property.addSample(startTime, startPosition);
var stopPosition = Cesium.Cartesian3.fromDegrees(终点坐标, 终点坐标, 0);
property.addSample(stopTime, stopPosition);

// 求中点, 并给予中点一个高度
var midPoint = Cesium.Cartographic.fromCartesian(property.getValue(midTime));
midPoint.height = Cesium.Math.nextRandomNumber() * 100000 + 900000;
var midPosition = viewer.scene.globe.ellipsoid.cartographicToCartesian(midPoint, new Cesium.Cartesian3());

// 三个坐标点
const resultproperty = new Cesium.SampledPositionProperty();
resultproperty .addSample(startTime, startPosition);
resultproperty .addSample(midTime, midPosition);
resultproperty .addSample(stopTime, stopPosition);

// 添加到entity中
const entity = viewer.entities.add({
    position: resultproperty,
    .....  其他配置   ......
})
// 设置插值方式
entity.position.setInterpolationOptions({
    interpolationDegree : 5,
    interpolationAlgorithm : Cesium.LagrangePolynomialApproximation
});

指定两个点的行进动画,当动画时间到一半的时候,所取得的位置就是两个线段的中点。再由三点绘制一条抛物线。但是这条抛物线会有穿地的问题。

 原本最优的结果应该是都从一个点发散出去,然而有些线却没有正确的出发,而是看起来像从地下出发的一样。这种方法只适用于一定区域,当两点的距离可能横跨半个地球的时候,就不太行了。

于是考虑使用第二种方法,自己在网上找了一个抛物线的方程,基于这个方程自己绘制一条抛物线。

绘制方法接收    起始坐标点,终点坐标点,高度,坐标点数量  四个参数。

1.先判断是经度间距大,还是纬度间距大

南北半球直接相减求出绝对值就是纬度的跨度了。东西半球的经度就麻烦一点,也是相减求绝对值,如果这个绝对值大于了180,说明它从另一个方向更近点,跨度就按360-经度绝对值来算。如果不转换一下,绘制出来的线会多绕路。

2.按指点的坐标点数量,求出经度变化量和纬度变化量

于是就有了下面的代码:

//抛物线方程  { pt1: {lon: 114.302312702, lat: 30.598026044}, pt2: {lon: 114.302312702, lat: 30.598026044}, height: height, num: 100 }
function parabolaEquation(options) {
    //方程 y=-(4h/L^2)*x^2+h h:顶点高度 L:横纵间距较大者
    // 设置最低高度
    const h = options.height && options.height > 5000 ? options.height : 5000;
    let latLength = Math.abs(options.pt1.lat - options.pt2.lat);
    let lonLength = Math.abs(options.pt1.lon - options.pt2.lon);
    if (lonLength > 180) {
        lonLength = 360 - lonLength;
    }
    const L = lonLength > latLength ? lonLength : latLength;
    const result = [];
    // 设置坐标点最少50个
    const num = options.num && options.num > 50 ? options.num : 50;
    let dlt = L / num;
    if (lonLength > latLength) {//以lon为基准
        const delLat = (options.pt2.lat - options.pt1.lat) / num;
        // 由西向东递增为正数。由东向西递增为负数
        if (Math.abs(options.pt1.lon - options.pt2.lon) > 180 || options.pt1.lon - options.pt2.lon > 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 lon = options.pt1.lon + dlt * i;
            const lat = options.pt1.lat + delLat * i;
            result.push([lon, lat, tempH]);
        }
    } else {//以lat为基准
        let delLon = (options.pt2.lon - options.pt1.lon) / num;
        if (options.pt1.lat - options.pt2.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 lon = options.pt1.lon + delLon * i;
            const lat = options.pt1.lat + dlt * i;
            result.push([lon, lat, tempH]);
        }
    }
    // 落地
    result.push([options.pt2.lon,options.pt2.lat,options.pt2.height || 0])
    return result;
}

如果坐标点数量传了一个50进去,实际返回的数组有51个。这个数组每一个子项都是数组,如果绘制成polyline还需要遍历展开。

最后再生成动态值

            // 动态路径
            const property = new Cesium.SampledPositionProperty();
            const allTime = 86400;
            const stepTime = 86400 / (坐标点数量+1);
            const startTime = viewer.clock.startTime;
            const stopTime = Cesium.JulianDate.addSeconds(startTime, allTime, new Cesium.JulianDate());
            for (let index = 0; index < positionsArr.length; index++) {
                const point = positionsArr[index];
                if (index === 0) {
                    property.addSample(startTime, Cesium.Cartesian3.fromDegrees(起点坐标, 起点坐标, 0));
                }else if (index === positionsArr.length - 1) {
                    property.addSample(stopTime, Cesium.Cartesian3.fromDegrees(终点坐标, 终点坐标, 0));
                }else {
                    property.addSample(Cesium.JulianDate.addSeconds(startTime, (index)*stepTime, new Cesium.JulianDate()),Cesium.Cartesian3.fromDegrees(point[0],point[1],point[2]))
                }
            }

替换掉原先的resultproperty就行了。

效果图如下

 不再有穿地的了,这是进口效果,起点终点交换一下就是散开来的出口效果了。

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cesium中,可以使用`Cesium.CatmullRomSpline`来创建抛物线,并设置起点和终点。下面是一个示例代码: ```javascript // 创建场景 var viewer = new Cesium.Viewer('cesiumContainer'); // 设置起点和终点的经纬度坐标 var startLon = -75.59777; var startLat = 40.03883; var endLon = -122.41942; var endLat = 37.77493; // 创建起点和终点的Cartesian3坐标 var startPoint = Cesium.Cartesian3.fromDegrees(startLon, startLat); var endPoint = Cesium.Cartesian3.fromDegrees(endLon, endLat); // 创建抛物线的控制点 var controlPoints = [ startPoint, Cesium.Cartesian3.multiplyByScalar(startPoint, 2, new Cesium.Cartesian3()), Cesium.Cartesian3.multiplyByScalar(endPoint, 2, new Cesium.Cartesian3()), endPoint ]; // 创建抛物线 var catmullRomSpline = new Cesium.CatmullRomSpline({ times: [0, 0.33, 0.66, 1], points: controlPoints }); // 创建抛物线的样式 var polyline = viewer.entities.add({ polyline: { positions: catmullRomSpline.getPositions(100), width: 5, material: Cesium.Color.RED } }); // 将相机视角设置为抛物线的中点 viewer.camera.flyTo({ destination: Cesium.Cartesian3.midpoint(startPoint, endPoint), orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-90), roll: Cesium.Math.toRadians(0) }, duration: 3 }); ``` 这段代码会在Cesium的场景中创建一个抛物线,起点和终点分别为指定的经纬度坐标。抛物线会经过控制点,通过调整控制点的位置可以改变抛物线的形状。抛物线的样式可以通过设置`polyline`的属性来调整,例如线的宽度和颜色。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值