新增曲柄滑块批量仿真接口

This commit is contained in:
zhangshun
2026-06-16 11:17:25 +08:00
parent c9e76d0850
commit a66952e636
6 changed files with 310 additions and 73 deletions

View File

@@ -579,20 +579,24 @@
<input id="angleInput" type="number" step="1" />
</div>
<div class="field">
<label for="stepInput">扫描步长</label>
<input id="stepInput" type="number" min="1" max="90" step="1" />
<label for="stepInput">stepTime 步长时间</label>
<input id="stepInput" type="number" min="0.01" max="1" step="0.01" />
</div>
<div class="field">
<label for="scanEndInput">扫描终止角</label>
<input id="scanEndInput" type="number" min="1" max="720" step="1" />
</div>
<div class="field">
<label for="durationInput">duration 总时长</label>
<input id="durationInput" type="number" min="0.02" max="60" step="0.01" />
</div>
</div>
<div class="actions">
<button class="secondary" id="validButton" type="button">有效样例</button>
<button class="secondary" id="invalidButton" type="button">异常样例</button>
<button class="primary" id="runButton" type="button">调用接口</button>
<button class="primary" id="scanButton" type="button">角度扫描</button>
<button class="primary" id="scanButton" type="button">仿真扫描</button>
</div>
<div class="message" id="inputMessage" aria-live="polite"></div>
@@ -756,6 +760,7 @@
const angleInput = document.getElementById("angleInput");
const stepInput = document.getElementById("stepInput");
const scanEndInput = document.getElementById("scanEndInput");
const durationInput = document.getElementById("durationInput");
const requestOutput = document.getElementById("requestOutput");
const topSuccess = document.getElementById("topSuccess");
const businessSuccess = document.getElementById("businessSuccess");
@@ -813,6 +818,25 @@
};
}
// 按批量仿真接口格式组装曲柄滑块请求。
function buildSimulationRequest(input, sim, reqCode = `FOURBAR_SIM_${Date.now()}`) {
return {
msg: "fourbar crank slider simulate",
req_code: reqCode,
req_from: "fourbar_test_page",
req_cmd: "Cmd_FourBar_CrankSlider_Simulate",
req_param: {
L_AB: input.L_AB,
L_BS: input.L_BS,
S_OFS: input.S_OFS,
startAngleDeg: input.angleDeg,
endAngleDeg: sim.endAngleDeg,
duration: sim.duration,
stepTime: sim.stepTime,
},
};
}
// 将当前表单同步到请求 JSON 文本框。
function refreshRequestPreview() {
try {
@@ -828,8 +852,9 @@
lBsInput.value = sample.L_BS;
sOfsInput.value = sample.S_OFS;
angleInput.value = sample.angleDeg;
stepInput.value = stepInput.value || "10";
stepInput.value = stepInput.value || "0.02";
scanEndInput.value = scanEndInput.value || "360";
durationInput.value = durationInput.value || "2";
refreshRequestPreview();
}
@@ -1116,6 +1141,22 @@
}
}
// 调用曲柄滑块批量仿真接口并解析 JSON 响应。
async function callFourBarSimulation(input, sim) {
const module = await ensureWasm();
const payload = JSON.stringify(buildSimulationRequest(input, sim));
let requestPtr = 0;
let responsePtr = 0;
try {
requestPtr = allocString(module, payload);
responsePtr = module._func(requestPtr);
return JSON.parse(module.UTF8ToString(responsePtr));
} finally {
if (responsePtr) module._smart_free_string(responsePtr);
if (requestPtr) module._free(requestPtr);
}
}
// 计算前端几何校验值,用于和 WASM 返回点位对照。
function calculateLocalGeometry(input) {
const angle = (input.angleDeg * Math.PI) / 180;
@@ -1419,43 +1460,52 @@
}
}
// 多角度调用接口,生成轨迹和位移曲线。
// 调用批量仿真接口,生成轨迹和位移曲线。
async function runScan() {
try {
setMessage("");
const baseInput = readInput();
const step = Number(stepInput.value);
const stepTime = Number(stepInput.value);
const scanEnd = Number(scanEndInput.value);
if (!Number.isInteger(step) || step < 1 || step > 90) {
throw new Error("扫描步长必须是 1 到 90 之间的整数");
const duration = Number(durationInput.value);
if (!Number.isFinite(stepTime) || stepTime <= 0 || stepTime > 1) {
throw new Error("stepTime 必须是 0 到 1 秒之间的有效数字");
}
if (!Number.isFinite(scanEnd) || scanEnd <= 0 || scanEnd > 720) {
throw new Error("扫描终止角必须在 1 到 720 之间");
}
if (!Number.isFinite(duration) || duration <= 0 || duration > 60) {
throw new Error("duration 必须在 0 到 60 秒之间");
}
requestStatus.textContent = "扫描中";
requestStatus.className = "badge warn";
const rows = [];
for (let angle = 0; angle <= scanEnd + 0.000001; angle += step) {
const input = { ...baseInput, angleDeg: angle };
const response = await callFourBar(input, `FOURBAR_SCAN_${angle}`);
const data = response.res_data || {};
rows.push({
angle,
ok: response.success === true && data.success === true && !data.error,
B: data.points?.B,
S: data.points?.S,
error: data.error || response.msg || "",
});
const response = await callFourBarSimulation(baseInput, {
endAngleDeg: scanEnd,
duration,
stepTime,
});
const data = response.res_data || {};
if (response.success !== true || data.success !== true || data.error) {
throw new Error(data.error || response.msg || "批量仿真接口返回失败");
}
const rows = (data.frames || []).map((frame) => ({
frame: frame.frame,
time: frame.time,
angle: frame.angleDeg,
ok: Boolean(frame.points?.B && frame.points?.S),
B: frame.points?.B,
S: frame.points?.S,
error: "",
}));
latestScan = rows;
scanOutput.textContent = JSON.stringify(rows, null, 2);
scanOutput.textContent = JSON.stringify(response, null, 2);
renderScanCharts(rows);
scanAnimation.frame = 0;
requestStatus.textContent = "扫描完成";
requestStatus.className = "badge ok";
setMessage(`扫描完成:${rows.filter((row) => row.ok).length}/${rows.length} 个角度有效`, "is-ok");
setMessage(`仿真完成:${rows.filter((row) => row.ok).length}/${rows.length} 有效`, "is-ok");
} catch (error) {
requestStatus.textContent = "扫描失败";
requestStatus.className = "badge error";
@@ -1472,7 +1522,7 @@
scanOutput.classList.toggle("hidden", isResponse);
}
[lAbInput, lBsInput, sOfsInput, angleInput].forEach((input) => {
[lAbInput, lBsInput, sOfsInput, angleInput, stepInput, scanEndInput, durationInput].forEach((input) => {
input.addEventListener("input", refreshRequestPreview);
});
@@ -1495,8 +1545,9 @@
scanTab.addEventListener("click", () => setActiveTab("scan"));
loadSample(validSample);
stepInput.value = "10";
stepInput.value = "0.02";
scanEndInput.value = "360";
durationInput.value = "2";
refreshRequestPreview();
renderThreeMechanism(calculateLocalGeometry(validSample), validSample, {
title: "有效样例预览",