实现鼠标动态绘制椭圆的类EllipseDraw
实现思路是:椭圆绘制是基于矩形绘制的基础,因为椭圆长半轴和短半轴实际上就是矩形长和宽,所以核心还是绘制左上和右下两个点,然后计算出椭圆的中心店,以及长短半轴的值,以此实现动态绘制椭圆。
实现代码如下:
import CesiumByZh from "../CesiumByZh";
import GlobalListener from "../GlobalListener";
export default class EllipseDraw {
public canvas = CesiumByZh.viewer.scene.canvas;
public camera = CesiumByZh.viewer.scene.camera;
public ellipsoid = CesiumByZh.viewer.scene.globe.ellipsoid;
public viewer = CesiumByZh.viewer;
public scene = CesiumByZh.viewer.scene;
protected positions: any[] = [];
protected position: any = CesiumByZh.Cesium.Cartesian3.fromDegrees(103, 30, 100);
protected dragIconLight: string = "./Images/circle_red.png";
protected shapeEntity: any;
protected okHandler: any;
protected cancelHandler: any;
protected handler: any;
protected modifyHandler: any;
protected mousePosition: any[] = [];
protected result: any;
public pointEntityArray: any[] = [];
beginDraw() {
this.handler = new CesiumByZh.Cesium.ScreenSpaceEventHandler(this.canvas);
this.handler.setInputAction((event: any) => {
let position = event.position;
if (!CesiumByZh.Cesium.defined(position)) {
return;
}
let ray = this.camera.getPickRay(position);
if (!CesiumByZh.Cesium.defined(ray)) {
return;
}
let cartesian = this.scene.globe.pick(ray, this.scene);
if (!CesiumByZh.Cesium.defined(cartesian)) {
return;
}
let num = this.positions.length;
if (num == 0) {
this.positions.push(cartesian);
this.createTemporaryShape();
}
this.positions.push(cartesian);
this.pointEntityArray.push(this._createPoint(cartesian));
if (num > 1) {
this.positions.pop();
}
}, CesiumByZh.Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.setInputAction((event: any) => {
let position = event.endPosition;
if (!CesiumByZh.Cesium.defined(position)) {
return;
}
let ray = this.camera.getPickRay(position);
if (!CesiumByZh.Cesium.defined(ray)) {
return;
}
let cartesian = this.scene.globe.pick(ray, this.scene);
if (!CesiumByZh.Cesium.defined(cartesian)) {
return;
}
if (this.positions.length == 0) {
GlobalListener.getInstance().runTipsCallback(['单击开始绘制,右键取消']);
return
} else {
GlobalListener.getInstance().runTipsCallback(['单击完成绘制,右键回退']);
}
this.positions.pop();
this.positions.push(cartesian);
}, CesiumByZh.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.handler.setInputAction((movement: any) => {
if (this.positions.length == 0) {
//重新开始绘制
} else {
if (this.positions.length == 2) {
this.positions = [];
if (this.shapeEntity != null) {
CesiumByZh.viewer.entities.remove(this.shapeEntity);
this.shapeEntity = null;
}
} else {
this.positions.splice(this.positions.length - 2, 1);
}
CesiumByZh.viewer.entities.remove(this.pointEntityArray[this.pointEntityArray.length - 1]);
this.pointEntityArray.pop();
}
}, CesiumByZh.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
_createPoint(cartesian: any) {
let point = CesiumByZh.viewer.entities.add({
position: cartesian,
billboard: {
image: this.dragIconLight,
eyeOffset: new CesiumByZh.Cesium.ConstantProperty(new CesiumByZh.Cesium.Cartesian3(0, 0, -500)),
heightReference: CesiumByZh.Cesium.HeightReference.CLAMP_TO_GROUND
}
});
return point;
}
//创建实体
createTemporaryShape() {
let outlineDynamicPositions = new CesiumByZh.Cesium.CallbackProperty(() => {
if (this.positions.length > 1) {
let rect = CesiumByZh.Cesium.Rectangle.fromCartesianArray(this.positions);
let arr = [rect.west, rect.north, rect.east, rect.north, rect.east, rect.south, rect.west, rect.south, rect.west, rect.north];
return CesiumByZh.Cesium.Cartesian3.fromRadiansArray(arr);
} else {
return null;
}
}, false);
this.shapeEntity = CesiumByZh.viewer.entities.add({
canSelect: false,
position: new CesiumByZh.Cesium.CallbackProperty(() => {
if (this.positions.length > 1) {
let posi = [this.positions[0], this.positions[1]];
return this._computeEllipsePosition(posi);
} else {
return null;
}
}, false),
ellipse: {
height: undefined,
semiMajorAxis: new CesiumByZh.Cesium.CallbackProperty(() => {
if (this.positions.length > 1) {
let posi = [this.positions[0], this.positions[1]];
let dis = this._computeEllipseRadius3D(posi);
if (dis) {
if (dis.chang < 100) {
return null
} else {
return Number(dis.chang / 2);
}
} else {
return null;
}
} else {
return null;
}
}, false),
semiMinorAxis: new CesiumByZh.Cesium.CallbackProperty(() => {
if (this.positions.length > 1) {
let posi = [this.positions[0], this.positions[1]];
let dis = this._computeEllipseRadius3D(posi);
if (dis) {
if (dis.duan < 100) {
return null
} else {
return Number(dis.duan / 2);
}
} else {
return null;
}
} else {
return null;
}
}, false),
material: CesiumByZh.Cesium.Color.fromCssColorString('#F60').withAlpha(0.5),
},
polyline: {
positions: outlineDynamicPositions,
clampToGround: true,
width: 2,
material: CesiumByZh.Cesium.Color.fromCssColorString('#F60').withAlpha(0.5),
}
});
}
//通过矩形的对角顶点计算矩形的中心点位置(也可用于计算椭圆的圆心)
_computeEllipsePosition(positions: any[]) {
let c1: any = positions[0];
let c2: any = positions[1];
let c3: any = {};
c3.x = (c1.x + c2.x) / 2;
c3.y = (c1.y + c2.y) / 2;
c3.z = (c1.z + c2.z) / 2;
return c3;
}
//通过矩形的对角顶点计算矩形长宽(也可用于计算椭圆的长半轴和短半轴,为计算的长宽的一半)
_computeEllipseRadius3D(positions: any[]) {
let rect = CesiumByZh.Cesium.Rectangle.fromCartesianArray(positions);
//console.log('rect',rect);
let arr = [rect.west, rect.north, rect.east, rect.north, rect.east, rect.south, rect.west, rect.south, rect.west, rect.north];
let outlinePositions = CesiumByZh.Cesium.Cartesian3.fromRadiansArray(arr);
let c1 = outlinePositions[0];
let c2 = outlinePositions[1];
let c3 = outlinePositions[3];
let x = Math.pow(c1.x - c2.x, 2);
let y = Math.pow(c1.y - c2.y, 2);
let z = Math.pow(c1.z - c2.z, 2);
let dis = Math.sqrt(x + y + z);
let x1 = Math.pow(c1.x - c3.x, 2);
let y1 = Math.pow(c1.y - c3.y, 2);
let z1 = Math.pow(c1.z - c3.z, 2);
let dis1 = Math.sqrt(x1 + y1 + z1);
let p: any = {};
if (dis >= dis1) {
p.chang = dis;
p.duan = dis1;
p.rotation = 0;
} else {
p.chang = dis1;
p.duan = dis;
p.rotation = 90;
}
return p;
}
}