@yangyongtao/gaea 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -67
- package/package.json +28 -7
- package/public/Gaea.apple-touch-icon.png +0 -0
- package/public/Gaea.apple-touch-icon.png.import +35 -0
- package/public/Gaea.audio.worklet.js +211 -0
- package/public/Gaea.html +245 -0
- package/public/Gaea.icon.png +0 -0
- package/public/Gaea.icon.png.import +35 -0
- package/public/Gaea.js +782 -0
- package/public/Gaea.png +0 -0
- package/public/Gaea.png.import +35 -0
- package/public/Gaea.worker.js +1 -0
- package/public/GaeaApp.html +275 -0
- package/public/GaeaMethods.js +4342 -0
- package/public/GaeaModule.html +276 -0
- package/public/config.js +76 -0
- package/public/constants.js +185 -0
- package/public/favicon.ico +0 -0
- package/public/image/1.png +0 -0
- package/public/image/12-min-min.gif +0 -0
- package/public/image/3.png +0 -0
- package/public/image/labelImg//345/217/263/350/276/271.png +0 -0
- package/public/image/labelImg//345/267/246/350/276/271.png +0 -0
- package/public/image/labelImg//346/260/264/344/275/215.png +0 -0
- package/public/image/screenIcon//345/205/266/344/273/226.png +0 -0
- package/public/image/screenIcon//345/256/211/345/205/250/347/233/221/346/265/213/350/201/232/345/220/210-/347/272/242.png +0 -0
- package/public/image/screenIcon//345/256/211/345/205/250/347/233/221/346/265/213/350/201/232/345/220/210-/347/273/277.png +0 -0
- package/public/image/screenIcon//346/212/242/351/231/251/345/215/225/344/275/215.png +0 -0
- package/public/image/screenIcon//346/226/255/351/235/242.png +0 -0
- package/public/image/screenIcon//346/227/240/344/272/272/346/234/272.png +0 -0
- package/public/image/screenIcon//346/227/240/344/272/272/346/234/272/345/237/272/345/234/260.png +0 -0
- package/public/image/screenIcon//346/260/264/345/272/223/347/253/231.png +0 -0
- package/public/image/screenIcon//346/260/264/346/226/207/346/265/213/347/253/231.png +0 -0
- package/public/image/screenIcon//346/260/264/351/227/270.png +0 -0
- package/public/image/screenIcon//346/262/263/351/201/223/347/253/231-/346/227/240/346/225/260/346/215/256.png +0 -0
- package/public/image/screenIcon//346/262/263/351/201/223/347/253/231-/346/255/243/345/270/270.png +0 -0
- package/public/image/screenIcon//346/262/263/351/201/223/347/253/231-/350/266/205/344/277/235.png +0 -0
- package/public/image/screenIcon//346/262/263/351/201/223/347/253/231-/350/266/205/350/255/246.png +0 -0
- package/public/image/screenIcon//346/263/265/347/253/231-/347/201/260.png +0 -0
- package/public/image/screenIcon//346/263/265/347/253/231-/347/273/277.png +0 -0
- package/public/image/screenIcon//346/265/201/351/207/217/346/265/213/347/253/231.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-1/347/272/247.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-2/347/272/247.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-3/347/272/247.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-4/347/272/247.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-5/347/272/247.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-/346/251/231.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-/347/272/242.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-/347/273/277.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-/350/247/204/346/250/241/344/273/245/344/270/213.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230-/351/273/204.png +0 -0
- package/public/image/screenIcon//346/265/267/345/241/230.png +0 -0
- package/public/image/screenIcon//346/275/256/344/275/215.png +0 -0
- package/public/image/screenIcon//346/275/256/344/275/215/347/253/231-/346/227/240/346/225/260/346/215/256.png +0 -0
- package/public/image/screenIcon//346/275/256/344/275/215/347/253/231-/346/255/243/345/270/270.png +0 -0
- package/public/image/screenIcon//346/275/256/344/275/215/347/253/231-/350/266/205/344/277/235.png +0 -0
- package/public/image/screenIcon//346/275/256/344/275/215/347/253/231-/350/266/205/350/255/246.png +0 -0
- package/public/image/screenIcon//347/211/251/350/265/204/344/273/223/345/272/223.png +0 -0
- package/public/image/screenIcon//347/220/203/346/234/272-/345/205/263.png +0 -0
- package/public/image/screenIcon//347/220/203/346/234/272-/345/274/200.png +0 -0
- package/public/image/screenIcon//347/220/203/346/234/272-/347/272/242.png +0 -0
- package/public/image/screenIcon//350/247/206/351/242/221/347/233/221/346/216/247.png +0 -0
- package/public/image/screenIcon//351/227/270/351/227/250-/347/201/260.png +0 -0
- package/public/image/screenIcon//351/227/270/351/227/250-/347/273/277.png +0 -0
- package/public/image/screenIcon//351/230/262/346/264/252/344/273/223/345/272/223.png +0 -0
- package/public/image/screenIcon//351/232/220/346/202/243.png +0 -0
- package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/346/265/205/350/223/235.png +0 -0
- package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/347/201/260.png +0 -0
- package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/347/262/211.png +0 -0
- package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/347/272/242.png +0 -0
- package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/347/273/277.png +0 -0
- package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/350/223/235.png +0 -0
- package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/351/273/204.png +0 -0
- package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/351/273/221.png +0 -0
- package/public/image/screenIcon//351/243/216/351/200/237.png +0 -0
- package/public/image/screenIcon//351/243/216/351/200/237/346/265/213/347/253/231.png +0 -0
- package/public/image//346/260/264/346/226/207.gif +0 -0
- package/public/image//350/211/262/345/270/246.png +0 -0
- package/public/index.html +22 -0
- package/public/index.js +185662 -0
- package/public/jsWebControl-1.0.0.min.js +31 -0
- package/public/jsencrypt.min.js +1 -0
- package/public/math/Box2.js +203 -0
- package/public/math/Box3.js +532 -0
- package/public/math/Color.js +605 -0
- package/public/math/ColorManagement.js +74 -0
- package/public/math/Cylindrical.js +61 -0
- package/public/math/EngineUtils.js +81 -0
- package/public/math/Euler.js +315 -0
- package/public/math/Frustum.js +162 -0
- package/public/math/Interpolant.js +241 -0
- package/public/math/Line3.js +115 -0
- package/public/math/MathUtils.js +345 -0
- package/public/math/Matrix3.js +365 -0
- package/public/math/Matrix4.js +858 -0
- package/public/math/Plane.js +205 -0
- package/public/math/Quaternion.js +724 -0
- package/public/math/Ray.js +493 -0
- package/public/math/Sphere.js +243 -0
- package/public/math/Spherical.js +86 -0
- package/public/math/SphericalHarmonics3.js +243 -0
- package/public/math/Triangle.js +299 -0
- package/public/math/Vector2.js +464 -0
- package/public/math/Vector3.js +715 -0
- package/public/math/Vector4.js +644 -0
- package/public/math/interpolants/CubicInterpolant.js +151 -0
- package/public/math/interpolants/DiscreteInterpolant.js +26 -0
- package/public/math/interpolants/LinearInterpolant.js +38 -0
- package/public/math/interpolants/QuaternionLinearInterpolant.js +39 -0
- package/public/static/Cloud.png +0 -0
- package/public/static/Global2.jpg +0 -0
- package/public/static/css/main.css +170 -0
- package/public/static/geojson//346/265/267/345/241/230.geojson +99 -0
- package/public/static/img/loading.gif +0 -0
- package/public/static/js/app.js +359 -0
- package/public/static/js/appcontroller.js +207 -0
- package/public/static/js/dist/game.dev.js +137 -0
- package/public/static/js/env.js +74 -0
- package/public/static/js/event/event.js +107 -0
- package/public/static/js/init.js +8 -0
- package/public/static/js/initcloudmorph.js +1 -0
- package/public/static/js/log.js +35 -0
- package/public/static/js/network/ajax.js +29 -0
- package/public/static/js/network/rtcp.js +172 -0
- package/public/static/js/network/socket.js +106 -0
- package/public/web-control.min.js +2 -0
- package/scripts/postinstall.mjs +127 -0
- package/src/GaeaMethods.js +68 -405
- package/src/components/FlyAlongRoute.vue +1 -0
- package/src/components/WeatherControl.vue +2 -0
- package/src/directives/vDrag.js +70 -0
- package/src/index.js +1 -8
- package/src/plugin.js +16 -0
- package/src/utils.js +10 -21
- package/src/vite-plugin.js +117 -0
- package/public/static/1111.res +0 -0
- package/src/config.js +0 -40
package/src/GaeaMethods.js
CHANGED
|
@@ -1,448 +1,111 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* gaea-3dview npm package
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* <script src="
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* setConfig({ serveUrl: '...', serveLocal: '...' });
|
|
10
|
-
*
|
|
11
|
-
* 使用 GaeaApp:
|
|
12
|
-
* import { GaeaApp } from '@your-scope/gaea-3dview';
|
|
13
|
-
* const app = new GaeaApp();
|
|
14
|
-
* await app.drawPointIcon({ lat: 27.22, lng: 120.45 });
|
|
3
|
+
*
|
|
4
|
+
* 初始化流程:
|
|
5
|
+
* 1. HTML 加载 <script src="/Gaea.js"> → window.Engine 可用
|
|
6
|
+
* 2. import Gaea from '../public/index.js' → window.InstanceMap / NativeCall 等全局变量
|
|
7
|
+
* 3. new window.Engine({...}).startGame({...}) → Godot WASM 启动
|
|
8
|
+
* 4. app.initDefaultEnvironment() → 环境初始化
|
|
15
9
|
*/
|
|
16
10
|
|
|
17
|
-
|
|
11
|
+
import Gaea from '../public/index.js';
|
|
18
12
|
|
|
19
|
-
/** 加载资源到 Gaea */
|
|
20
|
-
function loadResource(url, name) {
|
|
21
|
-
return new Promise((res, rej) => {
|
|
22
|
-
if (!window.Gaea || !window.Gaea.GaeaResourceLoader) {
|
|
23
|
-
rej(new Error('Gaea 未初始化,请先加载 Gaea CDN'));
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
window.Gaea.GaeaResourceLoader.Instance.LoadResourceFromUrl1(
|
|
27
|
-
url, name,
|
|
28
|
-
(code, msg) => {
|
|
29
|
-
if (code === 200) res(true);
|
|
30
|
-
else { console.warn(`加载资源失败: ${name}`, msg); rej(false); }
|
|
31
|
-
}
|
|
32
|
-
);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** 获取文件名 */
|
|
37
|
-
function getFileName(url) {
|
|
38
|
-
return url.split('/').pop().split('?')[0];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** RGB 字符串转 Gaea Color */
|
|
42
|
-
function rgbToGaeaColor(rgb) {
|
|
43
|
-
if (typeof rgb !== 'string') return null;
|
|
44
|
-
const match = rgb.match(/\((.+?)\)/);
|
|
45
|
-
if (!match) return null;
|
|
46
|
-
const arr = match[1].split(',').map(Number);
|
|
47
|
-
return new window.Gaea.Color(arr[0] / 255, arr[1] / 255, arr[2] / 255, 1);
|
|
48
|
-
}
|
|
49
13
|
|
|
14
|
+
// ==================== 配置 ====================
|
|
50
15
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
function checkGaea() {
|
|
54
|
-
const G = window.Gaea;
|
|
55
|
-
if (!G || !G.World || !G.World.Instance) {
|
|
56
|
-
console.warn('Gaea 尚未加载完毕,请先调用 await GaeaApp.waitForReady()');
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
return G;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 等待 Gaea 引擎初始化完毕(轮询 World.Instance)
|
|
64
|
-
* @param {number} timeout - 超时毫秒数,默认 30000
|
|
65
|
-
* @returns {Promise<boolean>}
|
|
66
|
-
*/
|
|
67
|
-
async function waitForGaea(timeout = 30000) {
|
|
68
|
-
if (window.Gaea && window.Gaea.World && window.Gaea.World.Instance) {
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
const start = Date.now();
|
|
72
|
-
return new Promise((resolve) => {
|
|
73
|
-
const timer = setInterval(() => {
|
|
74
|
-
if (window.Gaea && window.Gaea.World && window.Gaea.World.Instance) {
|
|
75
|
-
clearInterval(timer);
|
|
76
|
-
resolve(true);
|
|
77
|
-
} else if (Date.now() - start > timeout) {
|
|
78
|
-
clearInterval(timer);
|
|
79
|
-
console.error('Gaea 初始化超时');
|
|
80
|
-
resolve(false);
|
|
81
|
-
}
|
|
82
|
-
}, 200);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
16
|
+
const defaultConfig = { serveUrl: '', serveLocal: '' };
|
|
17
|
+
const _config = { ...defaultConfig };
|
|
85
18
|
|
|
19
|
+
export function setConfig(cfg) { Object.assign(_config, cfg); }
|
|
20
|
+
export function getConfig() { return _config; }
|
|
86
21
|
|
|
87
|
-
// ==================== GaeaApp 类 ====================
|
|
88
22
|
|
|
89
|
-
|
|
90
|
-
import config from './config.js';
|
|
23
|
+
// ==================== GaeaApp ====================
|
|
91
24
|
|
|
92
25
|
export class GaeaApp {
|
|
93
26
|
constructor(options = {}) {
|
|
94
|
-
this.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this._flyAnimation = null;
|
|
98
|
-
this._flyAnimationPlayer = null;
|
|
99
|
-
this._flyModelInstance = null;
|
|
100
|
-
this._flyEntityView = null;
|
|
101
|
-
|
|
102
|
-
// ---- 点标注相关 ----
|
|
103
|
-
this._pointIconElements = [];
|
|
104
|
-
this._pointIconLoaded = false;
|
|
105
|
-
|
|
106
|
-
// ---- 天气相关 ----
|
|
107
|
-
this._weatherInited = false;
|
|
108
|
-
this._fullScreenQuad = null;
|
|
109
|
-
this._sky = null;
|
|
110
|
-
this._sun = null;
|
|
111
|
-
this._environment = null;
|
|
112
|
-
this._defaultSkyMtl = null;
|
|
113
|
-
this._rainSkyMtl = null;
|
|
114
|
-
this._rainSkyTexture = null;
|
|
115
|
-
|
|
116
|
-
// ---- Tween 动画组 ----
|
|
117
|
-
this._tweenGroup = new Group();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* 静态方法:等待 Gaea 引擎就绪
|
|
122
|
-
* @example await GaeaApp.waitForReady(); // 30s 超时
|
|
123
|
-
* @example await GaeaApp.waitForReady(60000); // 自定义超时
|
|
124
|
-
*/
|
|
125
|
-
static waitForReady(timeout) {
|
|
126
|
-
return waitForGaea(timeout);
|
|
27
|
+
this._options = options;
|
|
28
|
+
this.layers = [];
|
|
29
|
+
this.tLayers = [];
|
|
127
30
|
}
|
|
128
31
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* 在指定经纬度放置图标标记
|
|
133
|
-
* @param {Object} opts - { lat, lng, alt?, iconSize?, enablePick? }
|
|
134
|
-
*/
|
|
135
|
-
async drawPointIcon(opts = {}) {
|
|
136
|
-
const { lat, lng, alt = 0, iconSize = 150, enablePick = true } = opts;
|
|
137
|
-
if (lat == null || lng == null) {
|
|
138
|
-
console.error('drawPointIcon: lat 和 lng 不能为空');
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const Gaea = checkGaea();
|
|
143
|
-
if (!Gaea) return null;
|
|
144
|
-
const resName = 'pointIcon.res';
|
|
145
|
-
|
|
146
|
-
if (!this._pointIconLoaded) {
|
|
147
|
-
const resUrl = `${this.config.serveLocal}/static/1111.res`;
|
|
148
|
-
const loaded = await loadResource(resUrl, resName);
|
|
149
|
-
if (!loaded) return null;
|
|
150
|
-
this._pointIconLoaded = true;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const texId = Gaea.GaeaResourceLoader.Instance.GetResource(resName);
|
|
154
|
-
const tex = new Gaea.Texture(false);
|
|
155
|
-
tex.InstanceID = texId + '';
|
|
32
|
+
get config() { return { ..._config, ...this._options }; }
|
|
156
33
|
|
|
157
|
-
|
|
158
|
-
|
|
34
|
+
async initDefaultEnvironment() {
|
|
35
|
+
window.Gaea = Gaea;
|
|
36
|
+
Gaea.World.Instance.Is3DTilesNeedCache = false;
|
|
37
|
+
Gaea.World.Instance.IsPyramidTileSetNeedCache = false;
|
|
159
38
|
|
|
160
|
-
const
|
|
161
|
-
|
|
39
|
+
const envRes = 'res://default_env.tres';
|
|
40
|
+
const fogEnv = Gaea.Environment.ConvertBy(Gaea.GaeaResourceLoader.Instance.LoadLoaclResource(envRes));
|
|
41
|
+
fogEnv.FogEnabled = false;
|
|
162
42
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
iconSymbol.Icon = tex;
|
|
166
|
-
element.Symbol = iconSymbol;
|
|
167
|
-
element.EnablePick = enablePick;
|
|
168
|
-
element.EnableEdit = false;
|
|
43
|
+
Gaea.World.Instance.EngineConfigString =
|
|
44
|
+
`[Engine]\nDefaultGlobalOverview="Global2.jpg"\nAssetHost="${this.config.serveLocal}"`;
|
|
169
45
|
|
|
170
|
-
Gaea.
|
|
171
|
-
|
|
172
|
-
return element;
|
|
173
|
-
}
|
|
46
|
+
const env = Gaea.Environment.ConvertBy(Gaea.GaeaResourceLoader.Instance.LoadLoaclResource(envRes));
|
|
47
|
+
env.BackgroundEnergy = 0.6;
|
|
174
48
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
* @param {Array} pointList - [{ lat, lng, alt?, iconSize? }]
|
|
178
|
-
*/
|
|
179
|
-
async drawPointIcons(pointList = []) {
|
|
180
|
-
const elements = [];
|
|
181
|
-
for (const p of pointList) {
|
|
182
|
-
const el = await this.drawPointIcon(p);
|
|
183
|
-
if (el) elements.push(el);
|
|
184
|
-
}
|
|
185
|
-
return elements;
|
|
186
|
-
}
|
|
49
|
+
const sun = Gaea.Sun.ConvertBy(Gaea.World.Instance.GetNode('Sun'));
|
|
50
|
+
sun.Power = 1.5;
|
|
187
51
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const Gaea = window.Gaea;
|
|
191
|
-
this._pointIconElements.forEach(el => {
|
|
192
|
-
Gaea.World.Instance.RenderableObjectList.Remove(el);
|
|
193
|
-
});
|
|
194
|
-
this._pointIconElements = [];
|
|
52
|
+
Gaea.World.Instance.ForceCloudVisalbe = true;
|
|
53
|
+
Gaea.World.Instance.CloudVisalbe = false;
|
|
195
54
|
}
|
|
196
55
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
* 沿路径飞行
|
|
201
|
-
* @param {Array} lineData - [{ x: lat, y: lng }, ...]
|
|
202
|
-
* @param {Object} opts - { height, step, duration, xrotation, lockEye, minZoom, maxZoom }
|
|
203
|
-
*/
|
|
204
|
-
async flyAlongPath(lineData, opts = {}) {
|
|
205
|
-
const Gaea = checkGaea();
|
|
206
|
-
if (!Gaea) return Promise.reject(new Error('Gaea 未加载'));
|
|
207
|
-
const {
|
|
208
|
-
height = 150, step = 1000, duration = 20,
|
|
209
|
-
xrotation = -30, lockEye = true, minZoom = 0, maxZoom = 400
|
|
210
|
-
} = opts;
|
|
211
|
-
|
|
212
|
-
if (!lineData || lineData.length < 2) {
|
|
213
|
-
return Promise.reject(new Error('至少需要2个路径点'));
|
|
214
|
-
}
|
|
215
|
-
|
|
56
|
+
async getAllServe() {
|
|
57
|
+
const cfg = this.config;
|
|
58
|
+
const url = `${cfg.serveUrl}htc/service/wmts?REQUEST=GetCapabilities`;
|
|
216
59
|
try {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
const ctrl = Gaea.GaeaMath.SphericalToCartesianDeg(
|
|
222
|
-
new Gaea.Vector3(lineData[i].x, lineData[i].y, height)
|
|
223
|
-
);
|
|
224
|
-
bezier.AddValue(i, ctrl);
|
|
225
|
-
}
|
|
226
|
-
bezier.Step = step;
|
|
227
|
-
bezier.Interpolate(true);
|
|
228
|
-
bezier.CalculateLengthAfterInterpolation();
|
|
229
|
-
|
|
230
|
-
const startPos = Gaea.GaeaMath.SphericalToCartesianDeg(
|
|
231
|
-
new Gaea.Vector3(lineData[0].x, lineData[0].y, height)
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
const mesh = new Gaea.CubeMesh();
|
|
235
|
-
mesh.Size = new Gaea.Vector3(1, 1, 1);
|
|
236
|
-
const mtl = new Gaea.SpatialMaterial();
|
|
237
|
-
mtl.AlbedoColor = new Gaea.Color(1, 0, 0, 1);
|
|
238
|
-
mesh.SurfaceSetMaterial(0, mtl);
|
|
239
|
-
|
|
240
|
-
this._flyModelInstance = new Gaea.MeshInstance();
|
|
241
|
-
this._flyModelInstance.Name = 'flyModel';
|
|
242
|
-
this._flyModelInstance.Visible = false;
|
|
243
|
-
this._flyModelInstance.Translation = startPos;
|
|
244
|
-
Gaea.World.Instance.AddChild(this._flyModelInstance, false);
|
|
245
|
-
|
|
246
|
-
this._flyEntityView = new Gaea.EntityView();
|
|
247
|
-
this._flyEntityView.Offset3D = new Gaea.Vector3(
|
|
248
|
-
-1, 0, Math.tan(xrotation / 180 * Math.PI)
|
|
249
|
-
);
|
|
250
|
-
this._flyEntityView.LockEye = lockEye;
|
|
251
|
-
this._flyEntityView.MinMaxZoom3D = new Gaea.Vector2(minZoom, maxZoom);
|
|
252
|
-
this._flyEntityView.Init(this._flyModelInstance);
|
|
253
|
-
Gaea.World.Instance.CameraController.LockedEntity = this._flyEntityView;
|
|
254
|
-
|
|
255
|
-
this._flyAnimation = bezier.ToAnimationByTime(
|
|
256
|
-
'flyAnim', true, duration, new Gaea.Vector3(1, 1, 1)
|
|
257
|
-
);
|
|
258
|
-
this._flyAnimation.TrackSetPath(0, '/root/World/flyModel');
|
|
259
|
-
|
|
260
|
-
this._flyAnimationPlayer = new Gaea.GaeaAnimationPlayer();
|
|
261
|
-
this._flyAnimationPlayer.AddAnimation('flyAnim', this._flyAnimation);
|
|
262
|
-
Gaea.World.Instance.AddChild(this._flyAnimationPlayer, false);
|
|
263
|
-
|
|
264
|
-
return new Promise((resolve) => {
|
|
265
|
-
this._flyAnimationPlayer.PlayWithCallback(
|
|
266
|
-
'flyAnim', Gaea.CallbackType.AnimatioFinished, () => resolve()
|
|
267
|
-
);
|
|
268
|
-
});
|
|
60
|
+
const xml = await (await fetch(url)).text();
|
|
61
|
+
const hostUrl = `${cfg.serveUrl}htc/service/wmts`;
|
|
62
|
+
const layers = Gaea.WMTSImageStore.ParserXml2Capabilities(hostUrl, xml);
|
|
63
|
+
this.layers = [...this.layers, ...(layers || [])];
|
|
269
64
|
} catch (e) {
|
|
270
|
-
|
|
271
|
-
return Promise.reject(e);
|
|
65
|
+
console.warn('getAllServe 失败:', e.message);
|
|
272
66
|
}
|
|
67
|
+
return this.layers;
|
|
273
68
|
}
|
|
274
69
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
this._flyAnimationPlayer.Stop('flyAnim');
|
|
280
|
-
}
|
|
281
|
-
} catch (e) { /* ignore */ }
|
|
282
|
-
this._cleanupFlyResources();
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
_cleanupFlyResources() {
|
|
286
|
-
const Gaea = window.Gaea;
|
|
287
|
-
try {
|
|
288
|
-
if (this._flyAnimationPlayer) {
|
|
289
|
-
Gaea.World.Instance.RemoveChild(this._flyAnimationPlayer);
|
|
290
|
-
this._flyAnimationPlayer = null;
|
|
291
|
-
}
|
|
292
|
-
this._flyEntityView = null;
|
|
293
|
-
if (this._flyModelInstance) {
|
|
294
|
-
Gaea.World.Instance.RemoveChild(this._flyModelInstance);
|
|
295
|
-
this._flyModelInstance = null;
|
|
296
|
-
}
|
|
297
|
-
Gaea.World.Instance.CameraController.LockedEntity = null;
|
|
298
|
-
this._flyAnimation = null;
|
|
299
|
-
} catch (e) { /* ignore */ }
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/** 重置相机视角 */
|
|
303
|
-
cameraReset() {
|
|
304
|
-
const Gaea = window.Gaea;
|
|
305
|
-
const camera = Gaea.World.Instance.DefaultCamera;
|
|
306
|
-
camera && camera.Reset();
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// ==================== 天气控制 ====================
|
|
310
|
-
|
|
311
|
-
_initWeather() {
|
|
312
|
-
if (this._weatherInited) return;
|
|
313
|
-
const Gaea = window.Gaea;
|
|
314
|
-
if (!Gaea || !Gaea.World || !Gaea.World.Instance) {
|
|
315
|
-
console.warn('Gaea 尚未加载完毕,无法初始化天气');
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
this._fullScreenQuad = Gaea.World.Instance.FullScreenQuad;
|
|
319
|
-
this._sky = Gaea.MeshInstance.ConvertBy(Gaea.World.Instance.GetNode('Sky'));
|
|
320
|
-
this._sun = Gaea.Sun.ConvertBy(Gaea.World.Instance.GetNode('Sun'));
|
|
321
|
-
this._environment = Gaea.Environment.ConvertBy(
|
|
322
|
-
Gaea.GaeaResourceLoader.Instance.LoadLoaclResource('res://default_env.tres')
|
|
323
|
-
);
|
|
324
|
-
this._defaultSkyMtl = this._sky.MaterialOverride;
|
|
325
|
-
this._weatherInited = true;
|
|
326
|
-
}
|
|
70
|
+
addLayer({ layerName, max, min, transparency, forMat = 'image/vnd.jpeg-png', inserIndex = null } = {}) {
|
|
71
|
+
const mime = ['image/jpeg','image/png','image/tga','image/webp','image/bmp','application/json;type=geojson','image/vnd.jpeg-png'];
|
|
72
|
+
const mimeIdx = mime.indexOf(forMat);
|
|
73
|
+
if (mimeIdx === -1) return console.warn('未知图层类型:', forMat);
|
|
327
74
|
|
|
328
|
-
|
|
329
|
-
enableRain(params = {}) {
|
|
330
|
-
this._initWeather();
|
|
331
|
-
const Gaea = window.Gaea;
|
|
332
|
-
const fsq = this._fullScreenQuad;
|
|
333
|
-
if (!fsq) return;
|
|
75
|
+
if (!this.layers?.length) return console.warn('图层列表为空,请先调用 getAllServe()');
|
|
334
76
|
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
} = params;
|
|
77
|
+
const capability = this.layers.find(i => i.Title === layerName);
|
|
78
|
+
if (!capability) return console.warn(`图层 "${layerName}" 未找到`);
|
|
338
79
|
|
|
339
|
-
|
|
340
|
-
|
|
80
|
+
const store = new Gaea.WMTSImageStore();
|
|
81
|
+
store.ImageExtension = mimeIdx;
|
|
82
|
+
store.CurrentCapabilitie = capability;
|
|
341
83
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
this._sun.LightEnergy = 0.05;
|
|
345
|
-
this._environment.BackgroundEnergy = 0.11;
|
|
346
|
-
this._environment.GlowBlendMode = 1;
|
|
84
|
+
if (max !== undefined) store.LevelRange = new Gaea.Vector2(min, max);
|
|
85
|
+
if (transparency !== undefined) store.ImageTransparency = transparency;
|
|
347
86
|
|
|
348
|
-
|
|
349
|
-
fsq.Speed = speed;
|
|
350
|
-
fsq.WindDirection = direction;
|
|
351
|
-
fsq.Rainy = true;
|
|
352
|
-
}
|
|
87
|
+
if (!store.CurrentCapabilitie.InstanceID) return console.error(`${layerName} 加载异常`);
|
|
353
88
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
if (!fsq) return;
|
|
359
|
-
if (params.direction !== undefined) fsq.WindDirection = params.direction;
|
|
360
|
-
if (params.speed !== undefined) fsq.Speed = params.speed;
|
|
361
|
-
if (params.count !== undefined) fsq.RainyCount = params.count;
|
|
89
|
+
const tileset = Gaea.World.Instance.DefaultPyramidTileSet;
|
|
90
|
+
inserIndex !== null ? tileset.InsertImageStore(store, inserIndex) : tileset.AddImageStore(store);
|
|
91
|
+
console.log(`影像 "${layerName}" 添加成功`);
|
|
92
|
+
return store;
|
|
362
93
|
}
|
|
363
94
|
|
|
364
|
-
/**
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const fsq = this._fullScreenQuad;
|
|
369
|
-
if (!fsq) return;
|
|
370
|
-
|
|
371
|
-
fsq.Rainy = false;
|
|
372
|
-
fsq.Visible = false;
|
|
373
|
-
fsq.NeedAtmosphere = false;
|
|
374
|
-
|
|
375
|
-
this._sun.TimeString = '2022-09-15 12:00:00';
|
|
376
|
-
this._sun.LightColor = new Gaea.Color(1, 226 / 255, 164 / 255, 1);
|
|
377
|
-
this._sun.LightEnergy = 3.5;
|
|
378
|
-
this._environment.BackgroundEnergy = 0.2;
|
|
379
|
-
this._environment.GlowBlendMode = 2;
|
|
380
|
-
|
|
381
|
-
if (this._defaultSkyMtl && this._sky) {
|
|
382
|
-
this._sky.MaterialOverride = this._defaultSkyMtl;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/** 初始化基础环境(关闭默认雾、设置默认光照等) */
|
|
387
|
-
async initDefaultEnvironment() {
|
|
388
|
-
// 等待 Gaea 就绪
|
|
389
|
-
const ready = await waitForGaea(15000);
|
|
390
|
-
if (!ready) {
|
|
391
|
-
console.error('Gaea 引擎初始化超时');
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const Gaea = window.Gaea;
|
|
396
|
-
|
|
397
|
-
// 关闭默认雾
|
|
398
|
-
const fogEnv = Gaea.Environment.ConvertBy(
|
|
399
|
-
Gaea.GaeaResourceLoader.Instance.LoadLoaclResource('res://default_env.tres')
|
|
400
|
-
);
|
|
401
|
-
fogEnv.FogEnabled = false;
|
|
402
|
-
|
|
403
|
-
// 基础环境光
|
|
404
|
-
const env = Gaea.Environment.ConvertBy(
|
|
405
|
-
Gaea.GaeaResourceLoader.Instance.LoadLoaclResource('res://default_env.tres')
|
|
406
|
-
);
|
|
407
|
-
env.BackgroundEnergy = 0.6;
|
|
408
|
-
|
|
409
|
-
const sun = Gaea.Sun.ConvertBy(Gaea.World.Instance.GetNode('Sun'));
|
|
410
|
-
sun.Power = 1.5;
|
|
411
|
-
|
|
412
|
-
Gaea.World.Instance.ForceCloudVisalbe = true;
|
|
413
|
-
Gaea.World.Instance.CloudVisalbe = false;
|
|
414
|
-
|
|
415
|
-
window.Gaea = Gaea;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/** 设置静止资源 Base URL */
|
|
419
|
-
setAssetHost(assetHost) {
|
|
420
|
-
const Gaea = window.Gaea;
|
|
421
|
-
const cfg = `[Engine]\nDefaultGlobalOverview="Global2.jpg"\nAssetHost="${assetHost}"`;
|
|
422
|
-
Gaea.World.Instance.EngineConfigString = cfg;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// ==================== 工具方法 ====================
|
|
426
|
-
|
|
427
|
-
/** 屏幕坐标 → 经纬度 */
|
|
428
|
-
screenToLatLng(event) {
|
|
429
|
-
const Gaea = window.Gaea;
|
|
430
|
-
if (!Gaea || !Gaea.GaeaMath) return null;
|
|
431
|
-
const result = Gaea.GaeaMath.ProjectPosition(
|
|
432
|
-
new Gaea.Vector2(event.offsetX, event.offsetY)
|
|
433
|
-
);
|
|
434
|
-
const lonlat = Gaea.GaeaMath.CartesianToSphericalDeg(result);
|
|
435
|
-
return { lat: lonlat.x, lng: lonlat.y, alt: lonlat.z };
|
|
95
|
+
/** 定位到指定视角(经纬度高程 + 相机参数) */
|
|
96
|
+
SetPosition(numStr) {
|
|
97
|
+
const arr = numStr.split(',').map(s => Number(s.trim()));
|
|
98
|
+
Gaea.World.Instance.DefaultCamera.SetPosition2(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]);
|
|
436
99
|
}
|
|
437
100
|
|
|
438
|
-
/**
|
|
439
|
-
|
|
440
|
-
return
|
|
101
|
+
/** 记录当前视角,返回 URI 字符串 */
|
|
102
|
+
favorite() {
|
|
103
|
+
return Gaea.GaeaCamera.ConvertBy(Gaea.World.Instance.DefaultCamera).Favorite();
|
|
441
104
|
}
|
|
442
105
|
|
|
443
|
-
/**
|
|
444
|
-
|
|
445
|
-
|
|
106
|
+
/** 定位到已记录的视角 URI */
|
|
107
|
+
favoritePosition(uri) {
|
|
108
|
+
Gaea.World.Instance.DefaultCamera.GotoFavorite(uri);
|
|
446
109
|
}
|
|
447
110
|
}
|
|
448
111
|
|
|
@@ -80,6 +80,8 @@
|
|
|
80
80
|
<script setup>
|
|
81
81
|
import { ref, onBeforeUnmount } from 'vue';
|
|
82
82
|
import { GaeaApp } from '../GaeaMethods.js';
|
|
83
|
+
// v-drag 指令:import 后自动在 template 中可用
|
|
84
|
+
import vDrag from '../directives/vDrag.js';
|
|
83
85
|
|
|
84
86
|
const props = defineProps({
|
|
85
87
|
appInstance: { type: Object, default: null }
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v-drag 指令 - 使元素可拖拽
|
|
3
|
+
* 用法:<div v-drag>...</div>
|
|
4
|
+
* 拖拽触发热区需要有 class "title"
|
|
5
|
+
*/
|
|
6
|
+
export default {
|
|
7
|
+
mounted(el) {
|
|
8
|
+
let dragging = false;
|
|
9
|
+
let startX = 0, startY = 0;
|
|
10
|
+
let initialLeft = 0, initialTop = 0;
|
|
11
|
+
const originalTransition = el.style.transition;
|
|
12
|
+
const minTop = 60;
|
|
13
|
+
let maxLeft = 0, maxTop = 0;
|
|
14
|
+
|
|
15
|
+
const clamp = (val, min, max) => Math.max(min, Math.min(val, max));
|
|
16
|
+
|
|
17
|
+
const init = () => {
|
|
18
|
+
maxLeft = window.innerWidth - el.offsetWidth;
|
|
19
|
+
maxTop = window.innerHeight - el.offsetHeight;
|
|
20
|
+
const rect = el.getBoundingClientRect();
|
|
21
|
+
el.style.left = `${clamp(rect.left, 0, maxLeft)}px`;
|
|
22
|
+
el.style.top = `${clamp(rect.top, minTop, maxTop)}px`;
|
|
23
|
+
el.style.userSelect = 'none';
|
|
24
|
+
el.style.pointerEvents = 'auto';
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
init();
|
|
28
|
+
|
|
29
|
+
el._vDragMouseDown = (event) => {
|
|
30
|
+
const isTitleBar = event.target.classList.contains('title')
|
|
31
|
+
|| event.target.closest('.title');
|
|
32
|
+
if (!isTitleBar) return;
|
|
33
|
+
|
|
34
|
+
event.preventDefault();
|
|
35
|
+
el.style.transition = 'none';
|
|
36
|
+
dragging = true;
|
|
37
|
+
startX = event.clientX;
|
|
38
|
+
startY = event.clientY;
|
|
39
|
+
const rect = el.getBoundingClientRect();
|
|
40
|
+
initialLeft = rect.left;
|
|
41
|
+
initialTop = rect.top;
|
|
42
|
+
|
|
43
|
+
window.addEventListener('mousemove', el._vDragMouseMove);
|
|
44
|
+
window.addEventListener('mouseup', el._vDragMouseUp);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
el._vDragMouseMove = (event) => {
|
|
48
|
+
if (!dragging) return;
|
|
49
|
+
const newLeft = initialLeft + (event.clientX - startX);
|
|
50
|
+
const newTop = initialTop + (event.clientY - startY);
|
|
51
|
+
el.style.left = `${clamp(newLeft, 0, maxLeft)}px`;
|
|
52
|
+
el.style.top = `${clamp(newTop, minTop, maxTop)}px`;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
el._vDragMouseUp = () => {
|
|
56
|
+
dragging = false;
|
|
57
|
+
el.style.transition = originalTransition;
|
|
58
|
+
window.removeEventListener('mousemove', el._vDragMouseMove);
|
|
59
|
+
window.removeEventListener('mouseup', el._vDragMouseUp);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
el.addEventListener('mousedown', el._vDragMouseDown);
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
unmounted(el) {
|
|
66
|
+
el.removeEventListener('mousedown', el._vDragMouseDown);
|
|
67
|
+
window.removeEventListener('mousemove', el._vDragMouseMove);
|
|
68
|
+
window.removeEventListener('mouseup', el._vDragMouseUp);
|
|
69
|
+
}
|
|
70
|
+
};
|
package/src/index.js
CHANGED
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
* gaea-3dview 主入口
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
export { setConfig, getConfig } from './config.js';
|
|
7
|
-
export { default as config } from './config.js';
|
|
8
|
-
|
|
9
|
-
// 核心类
|
|
5
|
+
export { setConfig, getConfig } from './GaeaMethods.js';
|
|
10
6
|
export { GaeaApp } from './GaeaMethods.js';
|
|
11
7
|
export { default } from './GaeaMethods.js';
|
|
12
|
-
|
|
13
|
-
// 工具函数
|
|
14
|
-
export { screenToLatLng, loadResource } from './utils.js';
|
package/src/plugin.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gaea 3DView Vue 插件
|
|
3
|
+
* 自动注册 v-drag 指令
|
|
4
|
+
*/
|
|
5
|
+
import vDrag from './directives/vDrag.js';
|
|
6
|
+
|
|
7
|
+
const GaeaPlugin = {
|
|
8
|
+
install(app) {
|
|
9
|
+
app.directive('drag', vDrag);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default GaeaPlugin;
|
|
14
|
+
|
|
15
|
+
// 同时导出 Vite 插件
|
|
16
|
+
export { default as gaeaVitePlugin } from './vite-plugin.js';
|
package/src/utils.js
CHANGED
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
* 工具函数
|
|
3
|
-
*/
|
|
1
|
+
import Gaea from '../public/index.js';
|
|
4
2
|
|
|
5
3
|
/** 从URL加载资源到Gaea */
|
|
6
4
|
export function loadResource(url, name) {
|
|
7
5
|
return new Promise((res, rej) => {
|
|
8
|
-
if (!
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
window.Gaea.GaeaResourceLoader.Instance.LoadResourceFromUrl1(
|
|
13
|
-
url, name,
|
|
14
|
-
(code, msg) => {
|
|
15
|
-
if (code === 200) res(true);
|
|
16
|
-
else rej(new Error(msg));
|
|
17
|
-
}
|
|
6
|
+
if (!Gaea?.GaeaResourceLoader) return rej(new Error('Gaea 未初始化'));
|
|
7
|
+
Gaea.GaeaResourceLoader.Instance.LoadResourceFromUrl1(url, name,
|
|
8
|
+
(code, msg) => code === 200 ? res(true) : rej(new Error(msg))
|
|
18
9
|
);
|
|
19
10
|
});
|
|
20
11
|
}
|
|
21
12
|
|
|
22
|
-
/** 屏幕坐标 → 经纬度
|
|
23
|
-
export function screenToLatLng(
|
|
24
|
-
if (!
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const lonlat = window.Gaea.GaeaMath.CartesianToSphericalDeg(result);
|
|
29
|
-
return { lat: lonlat.x, lng: lonlat.y, alt: lonlat.z };
|
|
13
|
+
/** 屏幕坐标 → 经纬度 */
|
|
14
|
+
export function screenToLatLng(e) {
|
|
15
|
+
if (!Gaea?.GaeaMath) return null;
|
|
16
|
+
const r = Gaea.GaeaMath.ProjectPosition(new Gaea.Vector2(e.offsetX, e.offsetY));
|
|
17
|
+
const ll = Gaea.GaeaMath.CartesianToSphericalDeg(r);
|
|
18
|
+
return { lat: ll.x, lng: ll.y, alt: ll.z };
|
|
30
19
|
}
|