一、创作思路
1、创建一个自定义CustomPrimitive
2、然后根据两个点,生成圆
3、方便后期绘制圆
二、实现代码
1、在vue的包中加入turf.
npm install @turf/turf
1、创建一个CustomCirclePrimitive类,并加入更新的代码
export default class CustomCirclePrimitive {
constructor(options) {
this._props = options;
/**
* 渲染列表
* @type {*[]}
* @private
*/
this._primitiveCollection = [];
this._dynamicPrimitive = undefined;
}
updateProperty(options) {
this._props = {
...this._props,
...options,
};
}
/**
* 更新
* @param frameState
*/
update(frameState) {
this._primitiveCollection.forEach((primitive) => {
primitive && !primitive.isDestroyed() && primitive.update(frameState);
});
if (this._dynamicPrimitive) {
this._dynamicPrimitive.update(frameState);
}
}
destroy() {
this._primitiveCollection.forEach((primitive) => {
primitive && !primitive.isDestroyed() && primitive.destroy();
});
this._primitiveCollection = undefined;
if (this._dynamicPrimitive) {
this._dynamicPrimitive.destroy();
}
this._dynamicPrimitive = undefined;
}
}
2、编写更新代码
updateProperty(options) {
this._props = {
...this._props,
...options,
};
let positions = this._props.positions;
let complete = this._props.complete;
if (positions.length > 1) {
let dynamicPrimitive = this._dynamicPrimitive;
if (dynamicPrimitive) {
dynamicPrimitive.destroy();
dynamicPrimitive = null;
this._dynamicPrimitive = null;
}
let primitive = this.initCirclePrimitive(positions);
if (complete) {
this._primitiveCollection.push(primitive);
} else {
this._dynamicPrimitive = primitive;
}
}
}
3、编写绘制圆的代码
设定第一个点为中心点,第二个点为半径上面的点
半径为第一个点到第二个点的距离
initCirclePrimitive(positions) {
let centerP = positions[0];
let radiusP = positions[1];
let radius = getDistance(centerP, radiusP);
let circlePositions = getCircle(centerP, radius);
let instance = new GeometryInstance({
geometry: new GroundPolylineGeometry({
positions: circlePositions,
width: 4,
}),
});
return new GroundPolylinePrimitive({
geometryInstances: instance,
appearance: new PolylineMaterialAppearance({
material: new Material({
fabric: {
type: "Color",
uniforms: {
color: Color.fromCssColorString("#ff0000"),
},
},
}),
}),
asynchronous: false,
});
}
4、额外的算法代码
const ellipsoid = Ellipsoid.WGS84;
/**
* 将世界坐标系转换为球面坐标系
* @param {Cartesian3} position
* @return {{alt: number, lon: number, lat: number}}
*/
export const Cartesian3ToWgs84 = (position) => {
let cartographic = ellipsoid.cartesianToCartographic(position);
let lon = CesiumMath.toDegrees(cartographic.longitude);
let lat = CesiumMath.toDegrees(cartographic.latitude);
let alt = cartographic.height;
return {
lon,
lat,
alt,
};
};
/**
* 计算分段的距离
* @param {Cartesian3} startPoint 起点
* @param {Cartesian3} endPoint 终点
* @return {number} 平面距离
*/
export const getDistance = (startPoint, endPoint) => {
let start84 = Cartesian3ToWgs84(startPoint);
let end84 = Cartesian3ToWgs84(endPoint);
let startPosition = point([start84.lon, start84.lat]);
let endPosition = point([end84.lon, end84.lat]);
let startToEnd = distance(startPosition, endPosition, options);
return startToEnd * 1000;
};
/**
* 根据半径和中心点,获取圆形
* @param center
* @param radius
* @return {Cartesian3[]}
*/
export const getCircle = (center, radius) => {
let center84 = Cartesian3ToWgs84(center);
let centerP = [center84.lon, center84.lat];
let circleInfo = circle(centerP, radius / 1000.0, options);
return circleInfo.geometry.coordinates[0].map((item) => {
return Cartesian3.fromDegrees(item[0], item[1]);
});
};
5、测试代码
let primitive = new CustomCirclePrimitive();
viewer.scene.primitives.add(primitive);
let lon = 106;
let count = 0;
let lat = 26;
let centerP = Cartesian3.fromDegrees(lon, lat);
let interval = setInterval(() => {
let lonTemp = lon + count * 0.00001;
let nextP = Cartesian3.fromDegrees(lonTemp, lat);
primitive.updateProperty({
positions: [centerP, nextP],
complete: count === 11,
});
if (count > 10) {
clearInterval(interval);
}
count++;
}, 1000);
三、实现效果
四、代码
import {
Cartesian3,
Color,
GeometryInstance,
GroundPolylineGeometry,
GroundPolylinePrimitive,
Material,
PolylineMaterialAppearance,
} from "cesium";
import {
getCircle,
getDistance,
} from "@/components/MilitaryPlot/utils/PlotUtils";
export default class CustomCirclePrimitive {
constructor(options) {
this._props = options;
/**
* 渲染列表
* @type {*[]}
* @private
*/
this._primitiveCollection = [];
this._dynamicPrimitive = undefined;
}
updateProperty(options) {
this._props = {
...this._props,
...options,
};
let positions = this._props.positions;
let complete = this._props.complete;
if (positions.length > 1) {
let dynamicPrimitive = this._dynamicPrimitive;
if (dynamicPrimitive) {
dynamicPrimitive.destroy();
dynamicPrimitive = null;
this._dynamicPrimitive = null;
}
let primitive = this.initCirclePrimitive(positions);
if (complete) {
this._primitiveCollection.push(primitive);
} else {
this._dynamicPrimitive = primitive;
}
}
}
initCirclePrimitive(positions) {
let centerP = positions[0];
let radiusP = positions[1];
let radius = getDistance(centerP, radiusP);
let circlePositions = getCircle(centerP, radius);
let instance = new GeometryInstance({
geometry: new GroundPolylineGeometry({
positions: circlePositions,
width: 4,
}),
});
return new GroundPolylinePrimitive({
geometryInstances: instance,
appearance: new PolylineMaterialAppearance({
material: new Material({
fabric: {
type: "Color",
uniforms: {
color: Color.fromCssColorString("#ff0000"),
},
},
}),
}),
asynchronous: false,
});
}
/**
* 更新
* @param frameState
*/
update(frameState) {
this._primitiveCollection.forEach((primitive) => {
primitive && !primitive.isDestroyed() && primitive.update(frameState);
});
if (this._dynamicPrimitive) {
this._dynamicPrimitive.update(frameState);
}
}
destroy() {
this._primitiveCollection.forEach((primitive) => {
primitive && !primitive.isDestroyed() && primitive.destroy();
});
this._primitiveCollection = undefined;
if (this._dynamicPrimitive) {
this._dynamicPrimitive.destroy();
}
this._dynamicPrimitive = undefined;
}
}