Skip to content

Commit

Permalink
新需求-支持AI-iFrame-PostMessage监听传递分析参数
Browse files Browse the repository at this point in the history
  • Loading branch information
supermap123 committed Nov 27, 2024
1 parent a1a8fca commit 5287639
Show file tree
Hide file tree
Showing 2 changed files with 336 additions and 0 deletions.
331 changes: 331 additions & 0 deletions SuperMap iEarth/src/lib/AIFunction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,331 @@
class AIFunction {
constructor(viewer) {
this.viewer = viewer;
this.init();
}

// 初始化
init() {
this.isCoexist = true; // 是否支持同时存在多个分析功能
this.viewshed3D = undefined;
this.skyline = undefined;
this.shadowQuery = undefined;
this.sightline = undefined;
this.viewshedOptions = {};
this.skylineOptions = {};
this.shadowOptions = {};
this.sightLineOptions = {};
this.updateViewShed3D_Bind = undefined;
this.updateSkyline_Bind = undefined;
this.updateShadowQuery_Bind = undefined;
this.updateSightLine_Bind = undefined;
}

startListenIFramePostMessage() {
// 通过bind将this强制绑定为aifuntion实例对象,否则默认为window
window.addEventListener("message", this.postMessageFunction.bind(this), false);
}

// iframe-Postmessage-回调事件
postMessageFunction(event) {
if (!event || !event.data) return;

// 返回信息
let data = JSON.parse(event.data);
event.source.postMessage({
info: 'I Got it!',
data: data
}, event.origin);

// 获取数据
if(window.iEarthConsole) console.log("分析功能接受到的信息: ", data);

// 设置分析功能是否能够共存
if(Object.keys(data).includes('isCoexist')) this.isCoexist = data.isCoexist;

// 清除当前存在的分析
this.clearExitAnalyses();

// 执行可视域分析
if (data.viewshedOption) {
this.initViewShed3D(data.viewshedOption);
}

// 执行天际线分析
if (data.skylineOption) {
this.initSkyline(data.skylineOption);
}

// 执行阴影查询分析
if (data.shadowOption) {
this.initShadow(data.shadowOption);
}

// 执行通视分析
if (data.sightLineOption) {
this.initSightLine(data.sightLineOption);
}
}

// 清除其他分析功能
clearExitAnalyses() {
if (this.viewshed3D) {
this.viewshed3D.distance = 0.00001;
this.viewshed3D.viewPosition = [0, 0, 0];
this.viewshed3D = undefined;
if(!this.isCoexist) this.viewer.camera.moveEnd.removeEventListener(this.updateViewShed3D_Bind);
}

if (this.skyline) {
this.skyline.clear();
this.skyline = undefined;
if(!this.isCoexist) this.viewer.camera.moveEnd.removeEventListener(this.updateSkyline_Bind);
}

if (this.shadowQuery) {
this.shadowQuery.clear();
this.shadowQuery.destroy();
this.shadowQuery = undefined;
this.viewer.shadows = false;
let layers = viewer.scene.layers.layerQueue;
for (let i = 0; i < layers.length; i++) {
layers[i].shadowType = SuperMap3D.ShadowType.NONE;
}
if(!this.isCoexist) this.viewer.camera.moveEnd.removeEventListener(this.updateShadowQuery_Bind);
}

if (this.sightline) {
this.sightline.destroy();
this.sightline = undefined;
if(!this.isCoexist) this.viewer.camera.moveEnd.removeEventListener(this.updateSightLine_Bind);
}
}

// 初始化可视域分析
initViewShed3D(viewshedOption) {
const viewshedParams = viewshedOption.option;
if (!viewshedParams.observerPosition) return; // 没有观察点,无法执行可视域分析

// 计算包围盒
const observerPosition = viewshedParams.observerPosition;
const targetPosition = this.computedTargetPositionByDistance(observerPosition, viewshedParams.distance);
const boundingSphere = this.computedBoundingSphereFromPoints([observerPosition, targetPosition]);
this.viewer.camera.flyToBoundingSphere(boundingSphere, {
duration: 2
});

this.viewshedOptions = {
observerPosition: observerPosition,
targetPosition: targetPosition,
option: viewshedParams,
}
this.updateViewShed3D_Bind = this.updateViewShed3D.bind(this); // bind返回一个新函数,导致removeEventListener无效
this.viewer.camera.moveEnd.addEventListener(this.updateViewShed3D_Bind); // bind绑定this,不然里面的this是undefined
}

// 初始化天际线分析
initSkyline(skylineOption) {
const skylineParams = skylineOption.option;
const cameraPosition = skylineParams.cameraPosition;
if (cameraPosition && cameraPosition.destination) { // 如果参数携带了坐标,将定位后执行天际线分析
const destination = cameraPosition.destination;
if (destination instanceof Array && destination.length === 3) {
const position = SuperMap3D.Cartesian3.fromDegrees(destination[0], destination[1], destination[0])
cameraPosition.destination = position;
this.viewer.camera.flyTo(cameraPosition);
}
}

this.skylineOptions = {
option: skylineParams,
}
this.updateSkyline(); // 由于不一定有定位相机跳转,所以这里直接执行一次
this.updateSkyline_Bind = this.updateSkyline.bind(this);
this.viewer.camera.moveEnd.addEventListener(this.updateSkyline_Bind);
}

// 初始化阴影查询分析
initShadow(shadowOption) {
const shadowParams = shadowOption.option;
const region = shadowParams.region;
if (!region || region.length < 3) return; // 没有分析区域或分析区域不满足要求
const boundingSphere = this.computedBoundingSphereFromPoints(region);
this.viewer.camera.flyToBoundingSphere(boundingSphere, {
duration: 2
});

this.shadowOptions = {
option: shadowParams,
}
this.updateShadowQuery_Bind = this.updateShadowQuery.bind(this);
this.viewer.camera.moveEnd.addEventListener(this.updateShadowQuery_Bind);
}

// 初始化通视分析
initSightLine(sightLineOption) {
const sightLineParams = sightLineOption.option;
if(!sightLineParams.observerPosition) return; // 必须要有观察点和至少一个目标点
if(!sightLineParams.targetPositions || sightLineParams.targetPositions.length<1) return;
const points = [];
points.push(sightLineParams.observerPosition);
sightLineParams.targetPositions.forEach(targetPoint => points.push(targetPoint));
const boundingSphere = this.computedBoundingSphereFromPoints(points);
this.viewer.camera.flyToBoundingSphere(boundingSphere, {
duration: 2
});

this.sightLineOptions = {
option: sightLineParams,
}
this.updateSightLine_Bind = this.updateSightLine.bind(this);
this.viewer.camera.moveEnd.addEventListener(this.updateSightLine_Bind);
}

// 更新可视域分析效果
updateViewShed3D() {
const { observerPosition, targetPosition, option } = this.viewshedOptions;
if (!this.viewshed3D) this.viewshed3D = new SuperMap3D.ViewShed3D(this.viewer.scene); // 初始化
this.viewshed3D.viewPosition = observerPosition;
this.viewshed3D.build();
this.viewshed3D.setDistDirByPoint(targetPosition);
this.viewshed3D.horizontalFov = option.horizontalFov || 90;
this.viewshed3D.verticalFov = option.verticalFov || 60;
this.viewshed3D.hintLineColor = SuperMap3D.Color.fromCssColorString(option.hintLineColor || "rgb(212,202,45)");
this.viewshed3D.visibleAreaColor = SuperMap3D.Color.fromCssColorString(option.visibleAreaColor || "rgba(9,199,112,0.4)");
this.viewshed3D.hiddenAreaColor = SuperMap3D.Color.fromCssColorString(option.hiddenAreaColor || "rgba(238,114,22,0.4)");
}

// 更新天际线分析效果
updateSkyline() {
const { option } = this.skylineOptions;
if (!this.skyline) this.skyline = new SuperMap3D.Skyline(this.viewer.scene); // 初始化
this.skyline.clear();
this.skyline.radius = option.radius || 10000;
this.skyline.ignoreGlobe = option.ignoreGlobe || true; //地球表面不参与分析
this.skyline.color = SuperMap3D.Color.fromCssColorString(option.skylineColor || "rgb(200, 0, 0, 1.0)");
this.skyline.displayStyle = option.displayStyle || 0;
this.skyline.lineWidth = option.lineWidth || 2;
let cartographic = this.viewer.scene.camera.positionCartographic;
let lon = SuperMap3D.Math.toDegrees(cartographic.longitude);
let lat = SuperMap3D.Math.toDegrees(cartographic.latitude);
let hei = cartographic.height;
let observerObj = {
viewPosition: [lon, lat, hei],
pitch: SuperMap3D.Math.toDegrees(this.viewer.scene.camera.pitch),
direction: SuperMap3D.Math.toDegrees(this.viewer.scene.camera.heading)
};
this.skyline.viewPosition = observerObj.viewPosition;
this.skyline.pitch = observerObj.pitch;
this.skyline.direction = observerObj.direction;
this.skyline.build();
}

// 更新阴影查询分析效果
updateShadowQuery() {
const { option } = this.shadowOptions;
if (!this.shadowQuery) this.shadowQuery = new SuperMap3D.ShadowQueryPoints(this.viewer.scene); // 初始化
this.viewer.shadows = true;
const layers = this.viewer.scene.layers.layerQueue;
for (let i = 0; i < layers.length; i++) {
layers[i].selectEnabled = false;
layers[i].shadowType = 2; // 设置图层的阴影模式
}

//设置分析对象的开始结束时间
const startTime = new Date(option.startTime && option.startTime.date ||'2017-05-13');
startTime.setHours(Number(option.startTime && option.startTime.hour || 10)); // 10点
this.shadowQuery.startTime = SuperMap3D.JulianDate.fromDate(startTime);
const endTime = new Date(option.endTime && option.endTime.date ||'2017-05-13');
endTime.setHours(Number(option.endTime && option.endTime.hour || 12)); // 12点
this.shadowQuery.endTime = SuperMap3D.JulianDate.fromDate(endTime);

// 计算分析区域点
let points = [];
option.region.forEach((point) => {
points.push(point[0]);
points.push(point[1]);
})

// 执行阴影率分析
this.shadowQuery.spacing = Number(option.spacing || 10);
this.shadowQuery.timeInterval = Number(option.timeInterval || 60);
this.shadowQuery.qureyRegion({
position: points, // 分析区域:由包含经度、纬度的数组表示
bottom: Number(option.bottom || 20), // 底部高程
extend: Number(option.extend || 30) // 拉伸高度
});
this.shadowQuery.build();
}

// 更新通视分析效果
updateSightLine() {
const { option } = this.sightLineOptions;
if (!this.sightline) this.sightline = new SuperMap3D.Sightline(this.viewer.scene); // 初始化
this.sightline.build();
this.sightline.removeAllTargetPoint();
this.sightline.lineWidth = option.lineWidth || 5;
this.sightline.viewPosition = option.observerPosition;
option.targetPositions.forEach((targetPoint, index) => {
this.sightline.addTargetPoint({
position: targetPoint,
name: `point-${index}-${new Date().getTime()}` // 必须加上index,因为执行速度太快name相同导致其他目标点没有参与分析
});
})
}

// 笛卡尔转经纬度
cartesiantoDegrees(cartesian3) {
let array = [].concat(cartesian3);
let positions = [];
for (let i = 0, len = array.length; i < len; i++) {
let cartographic = SuperMap3D.Cartographic.fromCartesian(array[i]);
let longitude = Number(SuperMap3D.Math.toDegrees(cartographic.longitude));
let latitude = Number(SuperMap3D.Math.toDegrees(cartographic.latitude));
let height = Number(cartographic.height);
if (positions.indexOf(longitude) == -1 && positions.indexOf(latitude) == -1) {
positions.push(longitude);
positions.push(latitude);
positions.push(height);
}
}
return positions;
}

// 计算传入的经纬点数组的包围盒:[[longitude, latitude, height],[]]
computedBoundingSphereFromPoints(points, height = 100) {
if (points instanceof Array && points.length >= 2) {
let points_c3 = [];
points.forEach(point => {
if (!point[2]) point[2] = height;
const c3 = SuperMap3D.Cartesian3.fromDegrees(point[0], point[1], point[2]);
points_c3.push(c3);
});
const boundingSphere = SuperMap3D.BoundingSphere.fromPoints(points_c3);
boundingSphere.radius = boundingSphere.radius * 1.5;
return boundingSphere;
}
}

// 基于观察点和距离计算目标点[longitude, latitude, height]
computedTargetPositionByDistance(position, distance = 300) {
const observerPosition_C3 = SuperMap3D.Cartesian3.fromDegrees(position[0], position[1], position[2])
const transform = SuperMap3D.Transforms.eastNorthUpToFixedFrame(observerPosition_C3, SuperMap3D.Ellipsoid.WGS84, new SuperMap3D.Matrix4)
const offset_C3 = new SuperMap3D.Cartesian3(0, Number(distance), 0)
const targetPosition_C3 = SuperMap3D.Matrix4.multiplyByPoint(transform, offset_C3, new SuperMap3D.Cartesian3);
return this.cartesiantoDegrees(targetPosition_C3)
}

// 销毁
destroy() {
this.clearExitAnalyses();
this.viewshedOptions = {};
this.skylineOptions = {};
this.shadowOptions = {};
this.updateViewShed3D_Bind = undefined;
this.updateSkyline_Bind = undefined;
this.updateShadowQuery_Bind = undefined;
this.updateSightLine_Bind = undefined;
}
}

export default AIFunction;
5 changes: 5 additions & 0 deletions SuperMap iEarth/src/views/viewer/viewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useLayerStore } from "@/store/layerStore/layer";
import EventManager from "@/tools/ScreenEventManage/EventManager.js";
import layerManagement from "@/tools/layerManagement";
import openScene from "./openScene";
import AIFunction from "@/lib/AIFunction";
// 导入配置
import getConfig from "@/tools/getConfig";
Expand Down Expand Up @@ -92,6 +93,10 @@ function initViewer() {
creditContainer: document.createElement("div"), //去掉底部logo
});
// iEarth打通AI,监听iFrame元素的postMessage事件
const aiFunction = new AIFunction(viewer);
aiFunction.startListenIFramePostMessage();
// 获取iportal中保存的场景模式:平面 or 三维
getIPortalSceneInfo().then((res) => {
if (window.iEarthConsole) console.log("场景模式:", res);
Expand Down

0 comments on commit 5287639

Please sign in to comment.