|
|
@@ -1,6 +1,7 @@
|
|
|
const puppeteer = require("puppeteer-core");
|
|
|
const fs = require("fs");
|
|
|
const path = require("path");
|
|
|
+const http = require("http");
|
|
|
|
|
|
const CHROME_DEFAULT =
|
|
|
"C:/Program Files/Google/Chrome/Application/chrome.exe";
|
|
|
@@ -20,10 +21,54 @@ async function renderScene(opts) {
|
|
|
params = {},
|
|
|
terrainUrl = "",
|
|
|
sceneUrl = "",
|
|
|
- iserverHost = "192.168.60.2:8090",
|
|
|
+ backendUrl = "",
|
|
|
+ iserverHost = "192.168.60.87:8090",
|
|
|
chromePath = CHROME_DEFAULT,
|
|
|
} = opts;
|
|
|
|
|
|
+ // 从后端 API 获取 DSM 地形 URL
|
|
|
+ async function fetchTerrainUrl() {
|
|
|
+ if (!backendUrl) return terrainUrl;
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ const postData = JSON.stringify({ id: 0, jscType: "t_zhd_server" });
|
|
|
+ const reqUrl = new URL(backendUrl + "/apply/jsc/QueryOne");
|
|
|
+ const headers = { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) };
|
|
|
+ if (token) headers["Admin-Token"] = token;
|
|
|
+ const options = {
|
|
|
+ hostname: reqUrl.hostname,
|
|
|
+ port: reqUrl.port,
|
|
|
+ path: reqUrl.pathname,
|
|
|
+ method: "POST",
|
|
|
+ headers,
|
|
|
+ };
|
|
|
+ const req = http.request(options, (res) => {
|
|
|
+ let data = "";
|
|
|
+ res.on("data", (chunk) => (data += chunk));
|
|
|
+ res.on("end", () => {
|
|
|
+ try {
|
|
|
+ const json = JSON.parse(data);
|
|
|
+ if (json.data && json.data.url) {
|
|
|
+ console.log("[renderer] DSM URL from API:", json.data.url);
|
|
|
+ resolve(json.data.url);
|
|
|
+ } else {
|
|
|
+ console.warn("[renderer] API 未返回 DSM URL,使用默认值");
|
|
|
+ resolve(terrainUrl);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.warn("[renderer] 解析 DSM API 响应失败:", e.message);
|
|
|
+ resolve(terrainUrl);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ req.on("error", (e) => {
|
|
|
+ console.warn("[renderer] 获取 DSM URL 失败:", e.message);
|
|
|
+ resolve(terrainUrl);
|
|
|
+ });
|
|
|
+ req.write(postData);
|
|
|
+ req.end();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
function evalTimeout(page, fn, ...args) {
|
|
|
return Promise.race([
|
|
|
page.evaluate(fn, ...args),
|
|
|
@@ -77,8 +122,8 @@ async function renderScene(opts) {
|
|
|
/* 画布 0 尺寸则走兜底截图 */
|
|
|
}
|
|
|
await new Promise((r) => setTimeout(r, 8000));
|
|
|
-
|
|
|
// 注入自动化钩子(仅天际线需要;日照的钩子在 SunlightAnalysis.vue mounted 中)
|
|
|
+ // 天际线:page-hooks.js 注入主页面(纯 Cesium,不需要 Vue 组件)
|
|
|
if (analysisType !== "sunlight") {
|
|
|
const hooksSource = fs.readFileSync(
|
|
|
path.join(__dirname, "page-hooks.js"),
|
|
|
@@ -163,9 +208,10 @@ async function renderScene(opts) {
|
|
|
await new Promise((r) => setTimeout(r, 5000));
|
|
|
}
|
|
|
|
|
|
- // 自己加载 DSM 高程
|
|
|
- if (terrainUrl) {
|
|
|
- console.log("[renderer] 加载 DSM 高程:", terrainUrl.slice(0, 90));
|
|
|
+ // 自己加载 DSM 高程(从后端 API 动态获取 URL)
|
|
|
+ const resolvedTerrainUrl = await fetchTerrainUrl();
|
|
|
+ if (resolvedTerrainUrl) {
|
|
|
+ console.log("[renderer] 加载 DSM 高程:", resolvedTerrainUrl.slice(0, 90));
|
|
|
try {
|
|
|
await evalTimeout(page, async (u) => {
|
|
|
if (typeof Cesium === "undefined" || !window.viewer) return;
|
|
|
@@ -185,7 +231,7 @@ async function renderScene(opts) {
|
|
|
} catch (e) {
|
|
|
console.warn("terrain ready error", e);
|
|
|
}
|
|
|
- }, terrainUrl);
|
|
|
+ }, resolvedTerrainUrl);
|
|
|
console.log("[renderer] 地形已加载");
|
|
|
} catch (e) {
|
|
|
console.warn("[renderer] 地形加载失败", e.message);
|
|
|
@@ -193,6 +239,21 @@ async function renderScene(opts) {
|
|
|
await new Promise((r) => setTimeout(r, 3000));
|
|
|
}
|
|
|
|
|
|
+ // 等待数据源 + 3D瓦片稳定,确保日照分析时模型已渲染(之前 poly=0 根因)
|
|
|
+ await evalTimeout(page, async () => {
|
|
|
+ var start = Date.now();
|
|
|
+ var lastDs = 0, stable = 0;
|
|
|
+ while (stable < 5 && Date.now() - start < 30000) {
|
|
|
+ var ds = window.viewer.dataSources ? window.viewer.dataSources.length : 0;
|
|
|
+ if (ds > 0 && ds === lastDs) { stable++; } else { stable = 0; lastDs = ds; }
|
|
|
+ await new Promise(r => setTimeout(r, 1000));
|
|
|
+ }
|
|
|
+ console.log("[renderer] 数据源稳定 ds=" + lastDs + " 用时=" + (Date.now() - start) + "ms");
|
|
|
+ // 额外等2秒让瓦片渲染
|
|
|
+ await new Promise(r => setTimeout(r, 2000));
|
|
|
+ });
|
|
|
+ console.log("[renderer] 瓦片就绪,开始分析");
|
|
|
+
|
|
|
if (range && hasHook) {
|
|
|
if (analysisType === "skyline") {
|
|
|
// 天际线:range 为 LineString(两点),调 __skylineRun({start,end,faceH,faceW})
|