欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Cesium专栏-样条插值(平滑路径、飞行动画)

最编程 2024-01-18 08:45:20
...

关于插值的认识

在Cesium官网中有介绍飞机飞行路线插值的例子,介绍了3中插值的使用方式。
分别是:
LinearApproximation

entity.position.setInterpolationOptions({
    interpolationDegree : 1,
    interpolationAlgorithm : Cesium.LinearApproximation
});

LagrangePolynomialApproximation

entity.position.setInterpolationOptions({
    interpolationDegree : 5,
    interpolationAlgorithm : Cesium.LagrangePolynomialApproximation
});

HermitePolynomialApproximation

entity.position.setInterpolationOptions({
    interpolationDegree : 2,
    interpolationAlgorithm : Cesium.HermitePolynomialApproximation
});

关于样条插值

百度百科给的解释是:

    样条插值法是一种以可变样条来作出一条经过一系列点的光滑曲线的数学方法。插值样条是由一些多项式组成的,每一个多项式都是由相邻的两个数据点决定的,这样,任意的两个相邻的多项式以及它们的导数(不包括仇阶导数)在连接点处都是连续的。

一位搞游戏引擎开发的博主在博客上是这样的说的:

    在离散数据的基础上补插连续函数,使得这条连续曲线通过全部给定的离散数据点。插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。插值可以用于填充图像变换时像素之间的空隙。插值,拟合,逼近是数值分析的三大基础工具,通俗意义上它们的区别在于:插值是已知点列并且完全经过点列;拟合是已知点列,从整体上靠近它们,逼近是已知曲线,或者点列,通过逼近使得构造的函数无限靠近它们。科学和工程问题可以通过诸如采样、实验等方法获得若干离散的数据,根据这些数据,我们往往希望得到一个连续的函数(也就是曲线)或者更加密集的离散方程与已知数据相吻合。
插值问题的提法是:假定区间[a,b]上的实值函数f(x)在该区间上 n+1个互不相同点x0,x1……xn 处的值是f (x0),……f(xn),要求估算f(x)在[a,b]中某点x

的值。基本思路是,找到一个函数P(x),在x0,x1……xn 的节点上与f(x)函数值相同(有时,甚至一阶导数值也相同),用P(x

)的值作为函数f(x*)的近似。简单地讲就是已知数据上的若干值,为其补上未知的值。
样条方程是一类分段光滑、并且在各段交接处也有一定光滑性的函数。样条一词来源于工程绘图人员为了将一些指定点连接成一条光顺曲线所使用的工具,即富有弹性的细木条或薄钢条。由这样的样条形成的曲线在连接点处具有连续的坡度与曲率。分段低次多项式、在分段处具有一定光滑性的函数插值就是模拟以上原理发展起来的,它克服了高次多项式插值可能出现的振荡现象,具有较好的数值稳定性和收敛性,由这种插值过程产生的函数就是多项式样条函数。

Cesium中的样条插值

在cesium里,提供了三种样条插值方法,LinearSpline,CatmullRomSpline,HermiteSpline。
在具体的实例上,可以使用样条插值法利用已知的控制点,插值出一系列的点,用于平滑曲线,特别是在路径的追朔重演。
下面,我们分别介绍这三种样条插值的使用方法以及效果。

LinearSpline(线性样条)

线性样条从效果上看,是把所有控制点一一连线,并在连线上做定点取值

1、设置几个控制点,并添加到场景中,聚焦视角

var controls = [    Cesium.Cartesian3.fromDegrees(110, 10),    Cesium.Cartesian3.fromDegrees(111, 11),    Cesium.Cartesian3.fromDegrees(112, 9),    Cesium.Cartesian3.fromDegrees(114, 10),    Cesium.Cartesian3.fromDegrees(113, 8)];
for (var i = 0; i < controls.length; i++) {
    viewer.entities.add({
        position: controls[i],
        point: {
            color: Cesium.Color.RED,
            pixelSize: 10
        }
    });
}
viewer.zoomTo(viewer.entities);

2、创建LinearSpline对象

var spline = new Cesium.LinearSpline({
    times: [0.0, 0.25, 0.5, 0.75, 1],
    points: controls
});

3、插值100个点

var positions = [];
for (var i = 0; i <= 100; i++) {
    var cartesian3 = spline.evaluate(i / 100);
    positions.push(cartesian3);
    viewer.entities.add({
        position: cartesian3,
        point: {
            color: Cesium.Color.YELLOW,
            pixelSize: 6
        }
    });
}

4、将插值所有的点绘制成线

viewer.entities.add({
    name: 'LinearSpline',
    polyline: {
        positions: positions,
        width: 3,
        material: Cesium.Color.GREEN
    }
});

CatmullRomSpline(Catmull-ROM样条)

CatmullRom样条的曲线会经过其每一个控制点。Catmull_Rom样条曲线拟合方法需要至少四个控制点,实际上,四个控制点,曲线只会经过其中两个控制点,如现在有控制点A,B,C,D,得到的BC之间的拟合曲线,那么若要得到ABCD的拟合曲线应该怎么办呢。实际上,引入两个新的控制点A’,D’即可,A’由AB计算而得,D’由CD计算而得,例如,A’计算如下:

A’.x = A.x + (A.x - B.x)
A’.y = A.y + (A.y - B.y)

B’点计算类似。于是,由A’ABC可以得到AB曲线,由ABCD可以得到BC曲线,由BCDD’可以得到CD曲线,经过三次计算,可以得到ABCD曲线。

// 创建CatmullRomSpline对象
var spline = new Cesium.CatmullRomSpline({
    points: controls,
    times: [0.0, 0.25, 0.5, 0.75, 1],
});

// 插值100个点
var positions = [];
for (var i = 0; i <= 100; i++) {
    var cartesian3 = spline.evaluate(i / 100);
    positions.push(cartesian3);
    viewer.entities.add({
        position: cartesian3,
        point: {
            color: Cesium.Color.BLUE,
            pixelSize: 6
        }
    });
}

// 将插值所有的点绘制成线
viewer.entities.add({
    name: 'CatmullRomSpline',
    polyline: {
        positions: positions,
        width: 3,
        material: Cesium.Color.WHITE
    }
});

HermiteSpline(埃尔米特样条)
埃尔米特样条是在Catmull-ROM样条的基础上演变来的

// 创建HermiteSpline对象
var spline = Cesium.HermiteSpline.createNaturalCubic({
    times: [0.0, 0.25, 0.5, 0.75, 1],
    points: controls
});

// 插值100个点
var positions = [];
for (var i = 0; i <= 100; i++) {
    var cartesian3 = spline.evaluate(i / 100);
    positions.push(cartesian3);
    viewer.entities.add({
        position: cartesian3,
        point: {
            color: Cesium.Color.WHITE,
            pixelSize: 6
        }
    });
}

// 将插值所有的点绘制成线
viewer.entities.add({
    name: 'HermiteSpline',
    polyline: {
        positions: positions,
        width: 3,
        material: Cesium.Color.RED
    }
});

三种插值效果

其中白色为线条为CatmullRomSpline,红色线条为HermiteSpline,绿色线条为LinearSpline,大家可以按照具体的要求选择不同的插值方式达到自己的效果即可。

link==>