Compare commits
93
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88e47fc39a | ||
|
|
cd16ea28a6 | ||
|
|
45019f8952 | ||
|
|
af1e530162 | ||
|
|
e10b96b546 | ||
|
|
a2c3385062 | ||
|
|
7fcfecd063 | ||
|
|
7a3b0b84d0 | ||
|
|
e1c3e7e90a | ||
|
|
14877b6683 | ||
|
|
0848cefc89 | ||
|
|
722e60e5ef | ||
|
|
c4c2392c79 | ||
|
|
30080c51aa | ||
|
|
67e6ae98e2 | ||
|
|
57204b3b0b | ||
|
|
7594c71dd1 | ||
|
|
92aa796c9d | ||
|
|
7c0fd81b2f | ||
|
|
95a1ef5057 | ||
|
|
c8593207d3 | ||
|
|
7aeea4ed81 | ||
|
|
bf76304e00 | ||
|
|
b70dc4298a | ||
|
|
f153d671d3 | ||
|
|
7720594790 | ||
|
|
296cf610cd | ||
|
|
46cef8df17 | ||
|
|
d722b0f82b | ||
|
|
40c850b167 | ||
|
|
6544d9e918 | ||
|
|
67d5d6fa05 | ||
|
|
941fb89616 | ||
|
|
989a3ce28c | ||
|
|
28d5297237 | ||
|
|
b0738438d4 | ||
|
|
67578f4ce1 | ||
|
|
83ef98e9e5 | ||
|
|
316f0d7f85 | ||
|
|
2e7abbc56b | ||
|
|
b445745d27 | ||
|
|
1cc87e1836 | ||
|
|
aed59030b4 | ||
|
|
2e20ca7777 | ||
|
|
ae13ca5946 | ||
|
|
1b6131904a | ||
|
|
7fa2bfe52d | ||
|
|
1696b4742b | ||
|
|
ac1dc7d930 | ||
|
|
a98ad929d9 | ||
|
|
5a9738d6aa | ||
|
|
30227b661f | ||
|
|
4bcc35c1a0 | ||
|
|
a65ae9c285 | ||
|
|
5e97fa293f | ||
|
|
aba06086ac | ||
|
|
424374263e | ||
|
|
906a6ce37b | ||
|
|
1496184167 | ||
|
|
9561a068ab | ||
|
|
9e686b3311 | ||
|
|
936ee479ed | ||
|
|
b82a97fe8b | ||
|
|
90bdc27785 | ||
|
|
0b01bb7775 | ||
|
|
b688347778 | ||
|
|
252cbc8495 | ||
|
|
048716b3b3 | ||
|
|
343ddeac2d | ||
|
|
5983883ffe | ||
|
|
6290c75210 | ||
|
|
3c81c39a1c | ||
|
|
932c5216dc | ||
|
|
f9a76fed0e | ||
|
|
c05db1fbe0 | ||
|
|
385082c8ca | ||
|
|
cb1e1494af | ||
|
|
d943ec853c | ||
|
|
b111406cf8 | ||
|
|
28effdde23 | ||
|
|
2920fc7579 | ||
|
|
147a623df9 | ||
|
|
62c8ed421a | ||
|
|
be079bf18f | ||
|
|
73fbfddf6c | ||
|
|
3ff3b9b587 | ||
|
|
9a956c318a | ||
|
|
209d0bfc26 | ||
|
|
f50e0077c5 | ||
|
|
fb5bf943c9 | ||
|
|
bab0bb2df2 | ||
|
|
e21332b9e1 | ||
|
|
078b8421a6 |
@@ -189,6 +189,13 @@ sealed Current/Patchwork++ comparison rejected Patchwork++ for navigation:
|
||||
despite much lower latency and a small Ground-IoU gain, obstacle non-ground
|
||||
recall regressed from `80.46%` to `69.70%`.
|
||||
|
||||
Operator review of the later M4.8R3 LOW-STEP replay rejected its connected-
|
||||
component camera boxes as the product representation for general static
|
||||
obstacles. The replacement evaluation is terrain-relative and sequential:
|
||||
GSeg3D plus Nav2 Ground Consistency first, TRAVEL as the class-free challenger,
|
||||
and nvblox only as a separately measured occupancy/ESDF candidate. See the
|
||||
[traversability and static-obstacle stack decision](docs/23_TRAVERSABILITY_AND_STATIC_OBSTACLE_STACK_DECISION.md).
|
||||
|
||||
See [the Dataset Gateway plan](docs/14_LIDAR_DATASET_GATEWAY.md),
|
||||
[the laboratory run canon](docs/15_LABORATORY_RUN_CANON.md) and
|
||||
[ADR 0021](docs/adr/0021-dataset-gateway-representation-boundary.md).
|
||||
|
||||
Generated
+21
-2
@@ -16,6 +16,8 @@
|
||||
"@nodedc/ui-core": "file:../../../NODEDC_DESIGN_GUIDELINE/packages/ui-core",
|
||||
"@nodedc/ui-react": "file:../../../NODEDC_DESIGN_GUIDELINE/packages/ui-react",
|
||||
"@rerun-io/web-viewer": "0.34.1",
|
||||
"meshoptimizer": "1.1.1",
|
||||
"playcanvas": "2.21.4",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"three": "0.185.1"
|
||||
@@ -1375,7 +1377,6 @@
|
||||
"version": "0.5.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz",
|
||||
"integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
@@ -1399,6 +1400,12 @@
|
||||
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@webgpu/types": {
|
||||
"version": "0.1.72",
|
||||
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.72.tgz",
|
||||
"integrity": "sha512-0cF7RFM2edNoiIS1ODJp0/Gzv4/xSXhwoR0YCza+OWpJWtn4wmo9DvK91aLlH9+uUnwIriP7ZiC3WitmyhuzBw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.43",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz",
|
||||
@@ -1655,7 +1662,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.1.1.tgz",
|
||||
"integrity": "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ms": {
|
||||
@@ -1714,6 +1720,19 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/playcanvas": {
|
||||
"version": "2.21.4",
|
||||
"resolved": "https://registry.npmjs.org/playcanvas/-/playcanvas-2.21.4.tgz",
|
||||
"integrity": "sha512-L4UGy3z/YT8AaNBEY4ITsZup548UFMabF7loh0YQ0DRwQLdjIW8grmZPoQ1+B83+N6sejRS0/XlXV2Vfb11+fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/webxr": "^0.5.24",
|
||||
"@webgpu/types": "^0.1.70"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.19",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.19.tgz",
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
"@nodedc/ui-core": "file:../../../NODEDC_DESIGN_GUIDELINE/packages/ui-core",
|
||||
"@nodedc/ui-react": "file:../../../NODEDC_DESIGN_GUIDELINE/packages/ui-react",
|
||||
"@rerun-io/web-viewer": "0.34.1",
|
||||
"meshoptimizer": "1.1.1",
|
||||
"playcanvas": "2.21.4",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"three": "0.185.1"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# PlayCanvas Ammo runtime
|
||||
|
||||
- Source: `https://developer.playcanvas.com/assets/modules/ammo/ammo.wasm.js`
|
||||
- Source: `https://developer.playcanvas.com/assets/modules/ammo/ammo.wasm.wasm`
|
||||
- Retrieved: 2026-08-27
|
||||
- `ammo.wasm.js`: 442459 bytes, SHA-256 `9b765569bce6993e781cd95d548c3711b119f355b512b25722e86a27d6ea8857`
|
||||
- `ammo.wasm.wasm`: 747690 bytes, SHA-256 `a73b547ed4289aa174bf3424b14b3cb8addc7fe708cd2636d306b72880d6ad13`
|
||||
|
||||
The control station loads these pinned same-origin assets before constructing the PlayCanvas application so the rigid-body systems bind to the expected Ammo instance.
|
||||
@@ -0,0 +1,921 @@
|
||||
// This is ammo.js, a port of Bullet Physics to JavaScript. zlib licensed.
|
||||
|
||||
var Ammo = (() => {
|
||||
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
|
||||
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
|
||||
return (
|
||||
function(Ammo = {}) {
|
||||
|
||||
var b;b||(b=typeof Ammo !== 'undefined' ? Ammo : {});var aa,ba;b.ready=new Promise(function(a,c){aa=a;ba=c});var ca=Object.assign({},b),da="object"==typeof window,ea="function"==typeof importScripts,fa="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,ha="",ia,ja,ka;
|
||||
if(fa){var fs=require("fs"),la=require("path");ha=ea?la.dirname(ha)+"/":__dirname+"/";ia=(a,c)=>{a=a.startsWith("file://")?new URL(a):la.normalize(a);return fs.readFileSync(a,c?void 0:"utf8")};ka=a=>{a=ia(a,!0);a.buffer||(a=new Uint8Array(a));return a};ja=(a,c,d)=>{a=a.startsWith("file://")?new URL(a):la.normalize(a);fs.readFile(a,function(e,g){e?d(e):c(g.buffer)})};1<process.argv.length&&process.argv[1].replace(/\\/g,"/");process.argv.slice(2);b.inspect=function(){return"[Emscripten Module object]"}}else if(da||
|
||||
ea)ea?ha=self.location.href:"undefined"!=typeof document&&document.currentScript&&(ha=document.currentScript.src),_scriptDir&&(ha=_scriptDir),ha=0!==ha.indexOf("blob:")?ha.substr(0,ha.replace(/[?#].*/,"").lastIndexOf("/")+1):"",ia=a=>{var c=new XMLHttpRequest;c.open("GET",a,!1);c.send(null);return c.responseText},ea&&(ka=a=>{var c=new XMLHttpRequest;c.open("GET",a,!1);c.responseType="arraybuffer";c.send(null);return new Uint8Array(c.response)}),ja=(a,c,d)=>{var e=new XMLHttpRequest;e.open("GET",a,
|
||||
!0);e.responseType="arraybuffer";e.onload=()=>{200==e.status||0==e.status&&e.response?c(e.response):d()};e.onerror=d;e.send(null)};b.print||console.log.bind(console);var ma=b.printErr||console.warn.bind(console);Object.assign(b,ca);ca=null;var na;b.wasmBinary&&(na=b.wasmBinary);var noExitRuntime=b.noExitRuntime||!0;"object"!=typeof WebAssembly&&oa("no native wasm support detected");var pa,qa=!1,ra="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0;
|
||||
function sa(a,c){if(a){var d=ta,e=a+c;for(c=a;d[c]&&!(c>=e);)++c;if(16<c-a&&d.buffer&&ra)a=ra.decode(d.subarray(a,c));else{for(e="";a<c;){var g=d[a++];if(g&128){var n=d[a++]&63;if(192==(g&224))e+=String.fromCharCode((g&31)<<6|n);else{var z=d[a++]&63;g=224==(g&240)?(g&15)<<12|n<<6|z:(g&7)<<18|n<<12|z<<6|d[a++]&63;65536>g?e+=String.fromCharCode(g):(g-=65536,e+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else e+=String.fromCharCode(g)}a=e}}else a="";return a}
|
||||
var ua,ta,va,wa,xa,ya,za=[],Aa=[],Ba=[],Ca=!1;function Ea(){var a=b.preRun.shift();za.unshift(a)}var Fa=0,Ga=null,Ha=null;function oa(a){if(b.onAbort)b.onAbort(a);a="Aborted("+a+")";ma(a);qa=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ba(a);throw a;}function Ia(a){return a.startsWith("data:application/octet-stream;base64,")}var Ja;Ja="ammo.wasm.wasm";if(!Ia(Ja)){var Ka=Ja;Ja=b.locateFile?b.locateFile(Ka,ha):ha+Ka}
|
||||
function La(a){try{if(a==Ja&&na)return new Uint8Array(na);if(ka)return ka(a);throw"both async and sync fetching of the wasm failed";}catch(c){oa(c)}}
|
||||
function Ma(a){if(!na&&(da||ea)){if("function"==typeof fetch&&!a.startsWith("file://"))return fetch(a,{credentials:"same-origin"}).then(function(c){if(!c.ok)throw"failed to load wasm binary file at '"+a+"'";return c.arrayBuffer()}).catch(function(){return La(a)});if(ja)return new Promise(function(c,d){ja(a,function(e){c(new Uint8Array(e))},d)})}return Promise.resolve().then(function(){return La(a)})}
|
||||
function Na(a,c,d){return Ma(a).then(function(e){return WebAssembly.instantiate(e,c)}).then(function(e){return e}).then(d,function(e){ma("failed to asynchronously prepare wasm: "+e);oa(e)})}
|
||||
function Oa(a,c){var d=Ja;return na||"function"!=typeof WebAssembly.instantiateStreaming||Ia(d)||d.startsWith("file://")||fa||"function"!=typeof fetch?Na(d,a,c):fetch(d,{credentials:"same-origin"}).then(function(e){return WebAssembly.instantiateStreaming(e,a).then(c,function(g){ma("wasm streaming compile failed: "+g);ma("falling back to ArrayBuffer instantiation");return Na(d,a,c)})})}
|
||||
var Pa={27338:(a,c,d,e)=>{a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("drawLine"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::drawLine.";a.drawLine(c,d,e)},27558:(a,c,d,e,g,n)=>{a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("drawContactPoint"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::drawContactPoint.";a.drawContactPoint(c,d,e,g,n)},27808:(a,c)=>{a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("reportErrorWarning"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::reportErrorWarning.";
|
||||
a.reportErrorWarning(c)},28052:(a,c,d)=>{a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("draw3dText"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::draw3dText.";a.draw3dText(c,d)},28275:(a,c)=>{a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("setDebugMode"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::setDebugMode.";a.setDebugMode(c)},28501:a=>{a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("getDebugMode"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::getDebugMode.";
|
||||
return a.getDebugMode()},28732:(a,c)=>{a=b.getCache(b.MotionState)[a];if(!a.hasOwnProperty("getWorldTransform"))throw"a JSImplementation must implement all functions, you forgot MotionState::getWorldTransform.";a.getWorldTransform(c)},28973:(a,c)=>{a=b.getCache(b.MotionState)[a];if(!a.hasOwnProperty("setWorldTransform"))throw"a JSImplementation must implement all functions, you forgot MotionState::setWorldTransform.";a.setWorldTransform(c)},29214:(a,c,d,e,g,n,z,T)=>{a=b.getCache(b.ConcreteContactResultCallback)[a];
|
||||
if(!a.hasOwnProperty("addSingleResult"))throw"a JSImplementation must implement all functions, you forgot ConcreteContactResultCallback::addSingleResult.";return a.addSingleResult(c,d,e,g,n,z,T)}};function Qa(a){for(;0<a.length;)a.shift()(b)}var Ra=[];function Sa(a,c,d){Ra.length=0;var e;for(d>>=2;e=ta[c++];)d+=105!=e&d,Ra.push(105==e?va[d]:xa[d++>>1]),++d;return Pa[a].apply(null,Ra)}
|
||||
var Ta=[],Ua=void 0,Va=[],Wa={b:function(){oa("")},f:function(a,c,d){return Sa(a,c,d)},a:function(a,c,d){return Sa(a,c,d)},d:function(){return Date.now()},e:function(a,c,d){ta.copyWithin(a,c,c+d)},c:function(){oa("OOM")}};
|
||||
(function(){function a(d){d=d.exports;b.asm=d;pa=b.asm.g;var e=pa.buffer;b.HEAP8=ua=new Int8Array(e);b.HEAP16=new Int16Array(e);b.HEAP32=va=new Int32Array(e);b.HEAPU8=ta=new Uint8Array(e);b.HEAPU16=new Uint16Array(e);b.HEAPU32=new Uint32Array(e);b.HEAPF32=wa=new Float32Array(e);b.HEAPF64=xa=new Float64Array(e);ya=b.asm.iB;Aa.unshift(b.asm.h);Fa--;b.monitorRunDependencies&&b.monitorRunDependencies(Fa);0==Fa&&(null!==Ga&&(clearInterval(Ga),Ga=null),Ha&&(e=Ha,Ha=null,e()));return d}var c={a:Wa};Fa++;
|
||||
b.monitorRunDependencies&&b.monitorRunDependencies(Fa);if(b.instantiateWasm)try{return b.instantiateWasm(c,a)}catch(d){ma("Module.instantiateWasm callback failed with error: "+d),ba(d)}Oa(c,function(d){a(d.instance)}).catch(ba);return{}})();
|
||||
var Xa=b._emscripten_bind_btCollisionShape_setLocalScaling_1=function(){return(Xa=b._emscripten_bind_btCollisionShape_setLocalScaling_1=b.asm.i).apply(null,arguments)},Ya=b._emscripten_bind_btCollisionShape_getLocalScaling_0=function(){return(Ya=b._emscripten_bind_btCollisionShape_getLocalScaling_0=b.asm.j).apply(null,arguments)},Za=b._emscripten_bind_btCollisionShape_calculateLocalInertia_2=function(){return(Za=b._emscripten_bind_btCollisionShape_calculateLocalInertia_2=b.asm.k).apply(null,arguments)},
|
||||
$a=b._emscripten_bind_btCollisionShape_setMargin_1=function(){return($a=b._emscripten_bind_btCollisionShape_setMargin_1=b.asm.l).apply(null,arguments)},ab=b._emscripten_bind_btCollisionShape_getMargin_0=function(){return(ab=b._emscripten_bind_btCollisionShape_getMargin_0=b.asm.m).apply(null,arguments)},bb=b._emscripten_bind_btCollisionShape___destroy___0=function(){return(bb=b._emscripten_bind_btCollisionShape___destroy___0=b.asm.n).apply(null,arguments)},cb=b._emscripten_bind_btCollisionWorld_getDispatcher_0=
|
||||
function(){return(cb=b._emscripten_bind_btCollisionWorld_getDispatcher_0=b.asm.o).apply(null,arguments)},db=b._emscripten_bind_btCollisionWorld_rayTest_3=function(){return(db=b._emscripten_bind_btCollisionWorld_rayTest_3=b.asm.p).apply(null,arguments)},eb=b._emscripten_bind_btCollisionWorld_getPairCache_0=function(){return(eb=b._emscripten_bind_btCollisionWorld_getPairCache_0=b.asm.q).apply(null,arguments)},fb=b._emscripten_bind_btCollisionWorld_getDispatchInfo_0=function(){return(fb=b._emscripten_bind_btCollisionWorld_getDispatchInfo_0=
|
||||
b.asm.r).apply(null,arguments)},gb=b._emscripten_bind_btCollisionWorld_addCollisionObject_1=function(){return(gb=b._emscripten_bind_btCollisionWorld_addCollisionObject_1=b.asm.s).apply(null,arguments)},hb=b._emscripten_bind_btCollisionWorld_addCollisionObject_2=function(){return(hb=b._emscripten_bind_btCollisionWorld_addCollisionObject_2=b.asm.t).apply(null,arguments)},ib=b._emscripten_bind_btCollisionWorld_addCollisionObject_3=function(){return(ib=b._emscripten_bind_btCollisionWorld_addCollisionObject_3=
|
||||
b.asm.u).apply(null,arguments)},jb=b._emscripten_bind_btCollisionWorld_removeCollisionObject_1=function(){return(jb=b._emscripten_bind_btCollisionWorld_removeCollisionObject_1=b.asm.v).apply(null,arguments)},kb=b._emscripten_bind_btCollisionWorld_getBroadphase_0=function(){return(kb=b._emscripten_bind_btCollisionWorld_getBroadphase_0=b.asm.w).apply(null,arguments)},lb=b._emscripten_bind_btCollisionWorld_convexSweepTest_5=function(){return(lb=b._emscripten_bind_btCollisionWorld_convexSweepTest_5=b.asm.x).apply(null,
|
||||
arguments)},mb=b._emscripten_bind_btCollisionWorld_contactPairTest_3=function(){return(mb=b._emscripten_bind_btCollisionWorld_contactPairTest_3=b.asm.y).apply(null,arguments)},nb=b._emscripten_bind_btCollisionWorld_contactTest_2=function(){return(nb=b._emscripten_bind_btCollisionWorld_contactTest_2=b.asm.z).apply(null,arguments)},ob=b._emscripten_bind_btCollisionWorld_updateSingleAabb_1=function(){return(ob=b._emscripten_bind_btCollisionWorld_updateSingleAabb_1=b.asm.A).apply(null,arguments)},pb=
|
||||
b._emscripten_bind_btCollisionWorld_setDebugDrawer_1=function(){return(pb=b._emscripten_bind_btCollisionWorld_setDebugDrawer_1=b.asm.B).apply(null,arguments)},qb=b._emscripten_bind_btCollisionWorld_getDebugDrawer_0=function(){return(qb=b._emscripten_bind_btCollisionWorld_getDebugDrawer_0=b.asm.C).apply(null,arguments)},rb=b._emscripten_bind_btCollisionWorld_debugDrawWorld_0=function(){return(rb=b._emscripten_bind_btCollisionWorld_debugDrawWorld_0=b.asm.D).apply(null,arguments)},sb=b._emscripten_bind_btCollisionWorld_debugDrawObject_3=
|
||||
function(){return(sb=b._emscripten_bind_btCollisionWorld_debugDrawObject_3=b.asm.E).apply(null,arguments)},tb=b._emscripten_bind_btCollisionWorld___destroy___0=function(){return(tb=b._emscripten_bind_btCollisionWorld___destroy___0=b.asm.F).apply(null,arguments)},ub=b._emscripten_bind_btCollisionObject_setAnisotropicFriction_2=function(){return(ub=b._emscripten_bind_btCollisionObject_setAnisotropicFriction_2=b.asm.G).apply(null,arguments)},vb=b._emscripten_bind_btCollisionObject_getCollisionShape_0=
|
||||
function(){return(vb=b._emscripten_bind_btCollisionObject_getCollisionShape_0=b.asm.H).apply(null,arguments)},wb=b._emscripten_bind_btCollisionObject_setContactProcessingThreshold_1=function(){return(wb=b._emscripten_bind_btCollisionObject_setContactProcessingThreshold_1=b.asm.I).apply(null,arguments)},xb=b._emscripten_bind_btCollisionObject_setActivationState_1=function(){return(xb=b._emscripten_bind_btCollisionObject_setActivationState_1=b.asm.J).apply(null,arguments)},yb=b._emscripten_bind_btCollisionObject_forceActivationState_1=
|
||||
function(){return(yb=b._emscripten_bind_btCollisionObject_forceActivationState_1=b.asm.K).apply(null,arguments)},zb=b._emscripten_bind_btCollisionObject_activate_0=function(){return(zb=b._emscripten_bind_btCollisionObject_activate_0=b.asm.L).apply(null,arguments)},Ab=b._emscripten_bind_btCollisionObject_activate_1=function(){return(Ab=b._emscripten_bind_btCollisionObject_activate_1=b.asm.M).apply(null,arguments)},Bb=b._emscripten_bind_btCollisionObject_isActive_0=function(){return(Bb=b._emscripten_bind_btCollisionObject_isActive_0=
|
||||
b.asm.N).apply(null,arguments)},Cb=b._emscripten_bind_btCollisionObject_isKinematicObject_0=function(){return(Cb=b._emscripten_bind_btCollisionObject_isKinematicObject_0=b.asm.O).apply(null,arguments)},Db=b._emscripten_bind_btCollisionObject_isStaticObject_0=function(){return(Db=b._emscripten_bind_btCollisionObject_isStaticObject_0=b.asm.P).apply(null,arguments)},Eb=b._emscripten_bind_btCollisionObject_isStaticOrKinematicObject_0=function(){return(Eb=b._emscripten_bind_btCollisionObject_isStaticOrKinematicObject_0=
|
||||
b.asm.Q).apply(null,arguments)},Fb=b._emscripten_bind_btCollisionObject_getRestitution_0=function(){return(Fb=b._emscripten_bind_btCollisionObject_getRestitution_0=b.asm.R).apply(null,arguments)},Gb=b._emscripten_bind_btCollisionObject_getFriction_0=function(){return(Gb=b._emscripten_bind_btCollisionObject_getFriction_0=b.asm.S).apply(null,arguments)},Hb=b._emscripten_bind_btCollisionObject_getRollingFriction_0=function(){return(Hb=b._emscripten_bind_btCollisionObject_getRollingFriction_0=b.asm.T).apply(null,
|
||||
arguments)},Ib=b._emscripten_bind_btCollisionObject_setRestitution_1=function(){return(Ib=b._emscripten_bind_btCollisionObject_setRestitution_1=b.asm.U).apply(null,arguments)},Jb=b._emscripten_bind_btCollisionObject_setFriction_1=function(){return(Jb=b._emscripten_bind_btCollisionObject_setFriction_1=b.asm.V).apply(null,arguments)},Kb=b._emscripten_bind_btCollisionObject_setRollingFriction_1=function(){return(Kb=b._emscripten_bind_btCollisionObject_setRollingFriction_1=b.asm.W).apply(null,arguments)},
|
||||
Lb=b._emscripten_bind_btCollisionObject_getWorldTransform_0=function(){return(Lb=b._emscripten_bind_btCollisionObject_getWorldTransform_0=b.asm.X).apply(null,arguments)},Mb=b._emscripten_bind_btCollisionObject_getCollisionFlags_0=function(){return(Mb=b._emscripten_bind_btCollisionObject_getCollisionFlags_0=b.asm.Y).apply(null,arguments)},Nb=b._emscripten_bind_btCollisionObject_setCollisionFlags_1=function(){return(Nb=b._emscripten_bind_btCollisionObject_setCollisionFlags_1=b.asm.Z).apply(null,arguments)},
|
||||
Ob=b._emscripten_bind_btCollisionObject_setWorldTransform_1=function(){return(Ob=b._emscripten_bind_btCollisionObject_setWorldTransform_1=b.asm._).apply(null,arguments)},Pb=b._emscripten_bind_btCollisionObject_setCollisionShape_1=function(){return(Pb=b._emscripten_bind_btCollisionObject_setCollisionShape_1=b.asm.$).apply(null,arguments)},Qb=b._emscripten_bind_btCollisionObject_setCcdMotionThreshold_1=function(){return(Qb=b._emscripten_bind_btCollisionObject_setCcdMotionThreshold_1=b.asm.aa).apply(null,
|
||||
arguments)},Rb=b._emscripten_bind_btCollisionObject_setCcdSweptSphereRadius_1=function(){return(Rb=b._emscripten_bind_btCollisionObject_setCcdSweptSphereRadius_1=b.asm.ba).apply(null,arguments)},Sb=b._emscripten_bind_btCollisionObject_getUserIndex_0=function(){return(Sb=b._emscripten_bind_btCollisionObject_getUserIndex_0=b.asm.ca).apply(null,arguments)},Tb=b._emscripten_bind_btCollisionObject_setUserIndex_1=function(){return(Tb=b._emscripten_bind_btCollisionObject_setUserIndex_1=b.asm.da).apply(null,
|
||||
arguments)},Ub=b._emscripten_bind_btCollisionObject_getUserPointer_0=function(){return(Ub=b._emscripten_bind_btCollisionObject_getUserPointer_0=b.asm.ea).apply(null,arguments)},Vb=b._emscripten_bind_btCollisionObject_setUserPointer_1=function(){return(Vb=b._emscripten_bind_btCollisionObject_setUserPointer_1=b.asm.fa).apply(null,arguments)},Wb=b._emscripten_bind_btCollisionObject_getBroadphaseHandle_0=function(){return(Wb=b._emscripten_bind_btCollisionObject_getBroadphaseHandle_0=b.asm.ga).apply(null,
|
||||
arguments)},Xb=b._emscripten_bind_btCollisionObject___destroy___0=function(){return(Xb=b._emscripten_bind_btCollisionObject___destroy___0=b.asm.ha).apply(null,arguments)},Yb=b._emscripten_bind_btConcaveShape_setLocalScaling_1=function(){return(Yb=b._emscripten_bind_btConcaveShape_setLocalScaling_1=b.asm.ia).apply(null,arguments)},Zb=b._emscripten_bind_btConcaveShape_getLocalScaling_0=function(){return(Zb=b._emscripten_bind_btConcaveShape_getLocalScaling_0=b.asm.ja).apply(null,arguments)},$b=b._emscripten_bind_btConcaveShape_calculateLocalInertia_2=
|
||||
function(){return($b=b._emscripten_bind_btConcaveShape_calculateLocalInertia_2=b.asm.ka).apply(null,arguments)},ac=b._emscripten_bind_btConcaveShape___destroy___0=function(){return(ac=b._emscripten_bind_btConcaveShape___destroy___0=b.asm.la).apply(null,arguments)},bc=b._emscripten_bind_btCollisionAlgorithm___destroy___0=function(){return(bc=b._emscripten_bind_btCollisionAlgorithm___destroy___0=b.asm.ma).apply(null,arguments)},cc=b._emscripten_bind_btTypedConstraint_enableFeedback_1=function(){return(cc=
|
||||
b._emscripten_bind_btTypedConstraint_enableFeedback_1=b.asm.na).apply(null,arguments)},ec=b._emscripten_bind_btTypedConstraint_getBreakingImpulseThreshold_0=function(){return(ec=b._emscripten_bind_btTypedConstraint_getBreakingImpulseThreshold_0=b.asm.oa).apply(null,arguments)},fc=b._emscripten_bind_btTypedConstraint_setBreakingImpulseThreshold_1=function(){return(fc=b._emscripten_bind_btTypedConstraint_setBreakingImpulseThreshold_1=b.asm.pa).apply(null,arguments)},gc=b._emscripten_bind_btTypedConstraint_getParam_2=
|
||||
function(){return(gc=b._emscripten_bind_btTypedConstraint_getParam_2=b.asm.qa).apply(null,arguments)},hc=b._emscripten_bind_btTypedConstraint_setParam_3=function(){return(hc=b._emscripten_bind_btTypedConstraint_setParam_3=b.asm.ra).apply(null,arguments)},ic=b._emscripten_bind_btTypedConstraint___destroy___0=function(){return(ic=b._emscripten_bind_btTypedConstraint___destroy___0=b.asm.sa).apply(null,arguments)},jc=b._emscripten_bind_btDynamicsWorld_addAction_1=function(){return(jc=b._emscripten_bind_btDynamicsWorld_addAction_1=
|
||||
b.asm.ta).apply(null,arguments)},kc=b._emscripten_bind_btDynamicsWorld_removeAction_1=function(){return(kc=b._emscripten_bind_btDynamicsWorld_removeAction_1=b.asm.ua).apply(null,arguments)},lc=b._emscripten_bind_btDynamicsWorld_getSolverInfo_0=function(){return(lc=b._emscripten_bind_btDynamicsWorld_getSolverInfo_0=b.asm.va).apply(null,arguments)},mc=b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_1=function(){return(mc=b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_1=b.asm.wa).apply(null,
|
||||
arguments)},nc=b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_2=function(){return(nc=b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_2=b.asm.xa).apply(null,arguments)},oc=b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_3=function(){return(oc=b._emscripten_bind_btDynamicsWorld_setInternalTickCallback_3=b.asm.ya).apply(null,arguments)},pc=b._emscripten_bind_btDynamicsWorld_getDispatcher_0=function(){return(pc=b._emscripten_bind_btDynamicsWorld_getDispatcher_0=b.asm.za).apply(null,
|
||||
arguments)},qc=b._emscripten_bind_btDynamicsWorld_rayTest_3=function(){return(qc=b._emscripten_bind_btDynamicsWorld_rayTest_3=b.asm.Aa).apply(null,arguments)},rc=b._emscripten_bind_btDynamicsWorld_getPairCache_0=function(){return(rc=b._emscripten_bind_btDynamicsWorld_getPairCache_0=b.asm.Ba).apply(null,arguments)},sc=b._emscripten_bind_btDynamicsWorld_getDispatchInfo_0=function(){return(sc=b._emscripten_bind_btDynamicsWorld_getDispatchInfo_0=b.asm.Ca).apply(null,arguments)},tc=b._emscripten_bind_btDynamicsWorld_addCollisionObject_1=
|
||||
function(){return(tc=b._emscripten_bind_btDynamicsWorld_addCollisionObject_1=b.asm.Da).apply(null,arguments)},uc=b._emscripten_bind_btDynamicsWorld_addCollisionObject_2=function(){return(uc=b._emscripten_bind_btDynamicsWorld_addCollisionObject_2=b.asm.Ea).apply(null,arguments)},vc=b._emscripten_bind_btDynamicsWorld_addCollisionObject_3=function(){return(vc=b._emscripten_bind_btDynamicsWorld_addCollisionObject_3=b.asm.Fa).apply(null,arguments)},wc=b._emscripten_bind_btDynamicsWorld_removeCollisionObject_1=
|
||||
function(){return(wc=b._emscripten_bind_btDynamicsWorld_removeCollisionObject_1=b.asm.Ga).apply(null,arguments)},xc=b._emscripten_bind_btDynamicsWorld_getBroadphase_0=function(){return(xc=b._emscripten_bind_btDynamicsWorld_getBroadphase_0=b.asm.Ha).apply(null,arguments)},yc=b._emscripten_bind_btDynamicsWorld_convexSweepTest_5=function(){return(yc=b._emscripten_bind_btDynamicsWorld_convexSweepTest_5=b.asm.Ia).apply(null,arguments)},zc=b._emscripten_bind_btDynamicsWorld_contactPairTest_3=function(){return(zc=
|
||||
b._emscripten_bind_btDynamicsWorld_contactPairTest_3=b.asm.Ja).apply(null,arguments)},Ac=b._emscripten_bind_btDynamicsWorld_contactTest_2=function(){return(Ac=b._emscripten_bind_btDynamicsWorld_contactTest_2=b.asm.Ka).apply(null,arguments)},Bc=b._emscripten_bind_btDynamicsWorld_updateSingleAabb_1=function(){return(Bc=b._emscripten_bind_btDynamicsWorld_updateSingleAabb_1=b.asm.La).apply(null,arguments)},Cc=b._emscripten_bind_btDynamicsWorld_setDebugDrawer_1=function(){return(Cc=b._emscripten_bind_btDynamicsWorld_setDebugDrawer_1=
|
||||
b.asm.Ma).apply(null,arguments)},Dc=b._emscripten_bind_btDynamicsWorld_getDebugDrawer_0=function(){return(Dc=b._emscripten_bind_btDynamicsWorld_getDebugDrawer_0=b.asm.Na).apply(null,arguments)},Ec=b._emscripten_bind_btDynamicsWorld_debugDrawWorld_0=function(){return(Ec=b._emscripten_bind_btDynamicsWorld_debugDrawWorld_0=b.asm.Oa).apply(null,arguments)},Fc=b._emscripten_bind_btDynamicsWorld_debugDrawObject_3=function(){return(Fc=b._emscripten_bind_btDynamicsWorld_debugDrawObject_3=b.asm.Pa).apply(null,
|
||||
arguments)},Gc=b._emscripten_bind_btDynamicsWorld___destroy___0=function(){return(Gc=b._emscripten_bind_btDynamicsWorld___destroy___0=b.asm.Qa).apply(null,arguments)},Hc=b._emscripten_bind_btIDebugDraw_drawLine_3=function(){return(Hc=b._emscripten_bind_btIDebugDraw_drawLine_3=b.asm.Ra).apply(null,arguments)},Ic=b._emscripten_bind_btIDebugDraw_drawContactPoint_5=function(){return(Ic=b._emscripten_bind_btIDebugDraw_drawContactPoint_5=b.asm.Sa).apply(null,arguments)},Jc=b._emscripten_bind_btIDebugDraw_reportErrorWarning_1=
|
||||
function(){return(Jc=b._emscripten_bind_btIDebugDraw_reportErrorWarning_1=b.asm.Ta).apply(null,arguments)},Kc=b._emscripten_bind_btIDebugDraw_draw3dText_2=function(){return(Kc=b._emscripten_bind_btIDebugDraw_draw3dText_2=b.asm.Ua).apply(null,arguments)},Lc=b._emscripten_bind_btIDebugDraw_setDebugMode_1=function(){return(Lc=b._emscripten_bind_btIDebugDraw_setDebugMode_1=b.asm.Va).apply(null,arguments)},Mc=b._emscripten_bind_btIDebugDraw_getDebugMode_0=function(){return(Mc=b._emscripten_bind_btIDebugDraw_getDebugMode_0=
|
||||
b.asm.Wa).apply(null,arguments)},Nc=b._emscripten_bind_btIDebugDraw___destroy___0=function(){return(Nc=b._emscripten_bind_btIDebugDraw___destroy___0=b.asm.Xa).apply(null,arguments)},Oc=b._emscripten_bind_btVector3_btVector3_0=function(){return(Oc=b._emscripten_bind_btVector3_btVector3_0=b.asm.Ya).apply(null,arguments)},Pc=b._emscripten_bind_btVector3_btVector3_3=function(){return(Pc=b._emscripten_bind_btVector3_btVector3_3=b.asm.Za).apply(null,arguments)},Qc=b._emscripten_bind_btVector3_length_0=
|
||||
function(){return(Qc=b._emscripten_bind_btVector3_length_0=b.asm._a).apply(null,arguments)},Rc=b._emscripten_bind_btVector3_x_0=function(){return(Rc=b._emscripten_bind_btVector3_x_0=b.asm.$a).apply(null,arguments)},Sc=b._emscripten_bind_btVector3_y_0=function(){return(Sc=b._emscripten_bind_btVector3_y_0=b.asm.ab).apply(null,arguments)},Tc=b._emscripten_bind_btVector3_z_0=function(){return(Tc=b._emscripten_bind_btVector3_z_0=b.asm.bb).apply(null,arguments)},Uc=b._emscripten_bind_btVector3_setX_1=function(){return(Uc=
|
||||
b._emscripten_bind_btVector3_setX_1=b.asm.cb).apply(null,arguments)},Vc=b._emscripten_bind_btVector3_setY_1=function(){return(Vc=b._emscripten_bind_btVector3_setY_1=b.asm.db).apply(null,arguments)},Wc=b._emscripten_bind_btVector3_setZ_1=function(){return(Wc=b._emscripten_bind_btVector3_setZ_1=b.asm.eb).apply(null,arguments)},Xc=b._emscripten_bind_btVector3_setValue_3=function(){return(Xc=b._emscripten_bind_btVector3_setValue_3=b.asm.fb).apply(null,arguments)},Yc=b._emscripten_bind_btVector3_normalize_0=
|
||||
function(){return(Yc=b._emscripten_bind_btVector3_normalize_0=b.asm.gb).apply(null,arguments)},Zc=b._emscripten_bind_btVector3_rotate_2=function(){return(Zc=b._emscripten_bind_btVector3_rotate_2=b.asm.hb).apply(null,arguments)},$c=b._emscripten_bind_btVector3_dot_1=function(){return($c=b._emscripten_bind_btVector3_dot_1=b.asm.ib).apply(null,arguments)},ad=b._emscripten_bind_btVector3_op_mul_1=function(){return(ad=b._emscripten_bind_btVector3_op_mul_1=b.asm.jb).apply(null,arguments)},bd=b._emscripten_bind_btVector3_op_add_1=
|
||||
function(){return(bd=b._emscripten_bind_btVector3_op_add_1=b.asm.kb).apply(null,arguments)},cd=b._emscripten_bind_btVector3_op_sub_1=function(){return(cd=b._emscripten_bind_btVector3_op_sub_1=b.asm.lb).apply(null,arguments)},dd=b._emscripten_bind_btVector3___destroy___0=function(){return(dd=b._emscripten_bind_btVector3___destroy___0=b.asm.mb).apply(null,arguments)},ed=b._emscripten_bind_btQuadWord_x_0=function(){return(ed=b._emscripten_bind_btQuadWord_x_0=b.asm.nb).apply(null,arguments)},fd=b._emscripten_bind_btQuadWord_y_0=
|
||||
function(){return(fd=b._emscripten_bind_btQuadWord_y_0=b.asm.ob).apply(null,arguments)},gd=b._emscripten_bind_btQuadWord_z_0=function(){return(gd=b._emscripten_bind_btQuadWord_z_0=b.asm.pb).apply(null,arguments)},hd=b._emscripten_bind_btQuadWord_w_0=function(){return(hd=b._emscripten_bind_btQuadWord_w_0=b.asm.qb).apply(null,arguments)},jd=b._emscripten_bind_btQuadWord_setX_1=function(){return(jd=b._emscripten_bind_btQuadWord_setX_1=b.asm.rb).apply(null,arguments)},kd=b._emscripten_bind_btQuadWord_setY_1=
|
||||
function(){return(kd=b._emscripten_bind_btQuadWord_setY_1=b.asm.sb).apply(null,arguments)},ld=b._emscripten_bind_btQuadWord_setZ_1=function(){return(ld=b._emscripten_bind_btQuadWord_setZ_1=b.asm.tb).apply(null,arguments)},md=b._emscripten_bind_btQuadWord_setW_1=function(){return(md=b._emscripten_bind_btQuadWord_setW_1=b.asm.ub).apply(null,arguments)},nd=b._emscripten_bind_btQuadWord___destroy___0=function(){return(nd=b._emscripten_bind_btQuadWord___destroy___0=b.asm.vb).apply(null,arguments)},od=
|
||||
b._emscripten_bind_btMotionState_getWorldTransform_1=function(){return(od=b._emscripten_bind_btMotionState_getWorldTransform_1=b.asm.wb).apply(null,arguments)},pd=b._emscripten_bind_btMotionState_setWorldTransform_1=function(){return(pd=b._emscripten_bind_btMotionState_setWorldTransform_1=b.asm.xb).apply(null,arguments)},qd=b._emscripten_bind_btMotionState___destroy___0=function(){return(qd=b._emscripten_bind_btMotionState___destroy___0=b.asm.yb).apply(null,arguments)},rd=b._emscripten_bind_RayResultCallback_hasHit_0=
|
||||
function(){return(rd=b._emscripten_bind_RayResultCallback_hasHit_0=b.asm.zb).apply(null,arguments)},sd=b._emscripten_bind_RayResultCallback_get_m_collisionFilterGroup_0=function(){return(sd=b._emscripten_bind_RayResultCallback_get_m_collisionFilterGroup_0=b.asm.Ab).apply(null,arguments)},td=b._emscripten_bind_RayResultCallback_set_m_collisionFilterGroup_1=function(){return(td=b._emscripten_bind_RayResultCallback_set_m_collisionFilterGroup_1=b.asm.Bb).apply(null,arguments)},ud=b._emscripten_bind_RayResultCallback_get_m_collisionFilterMask_0=
|
||||
function(){return(ud=b._emscripten_bind_RayResultCallback_get_m_collisionFilterMask_0=b.asm.Cb).apply(null,arguments)},vd=b._emscripten_bind_RayResultCallback_set_m_collisionFilterMask_1=function(){return(vd=b._emscripten_bind_RayResultCallback_set_m_collisionFilterMask_1=b.asm.Db).apply(null,arguments)},wd=b._emscripten_bind_RayResultCallback_get_m_closestHitFraction_0=function(){return(wd=b._emscripten_bind_RayResultCallback_get_m_closestHitFraction_0=b.asm.Eb).apply(null,arguments)},xd=b._emscripten_bind_RayResultCallback_set_m_closestHitFraction_1=
|
||||
function(){return(xd=b._emscripten_bind_RayResultCallback_set_m_closestHitFraction_1=b.asm.Fb).apply(null,arguments)},yd=b._emscripten_bind_RayResultCallback_get_m_collisionObject_0=function(){return(yd=b._emscripten_bind_RayResultCallback_get_m_collisionObject_0=b.asm.Gb).apply(null,arguments)},zd=b._emscripten_bind_RayResultCallback_set_m_collisionObject_1=function(){return(zd=b._emscripten_bind_RayResultCallback_set_m_collisionObject_1=b.asm.Hb).apply(null,arguments)},Ad=b._emscripten_bind_RayResultCallback_get_m_flags_0=
|
||||
function(){return(Ad=b._emscripten_bind_RayResultCallback_get_m_flags_0=b.asm.Ib).apply(null,arguments)},Bd=b._emscripten_bind_RayResultCallback_set_m_flags_1=function(){return(Bd=b._emscripten_bind_RayResultCallback_set_m_flags_1=b.asm.Jb).apply(null,arguments)},Cd=b._emscripten_bind_RayResultCallback___destroy___0=function(){return(Cd=b._emscripten_bind_RayResultCallback___destroy___0=b.asm.Kb).apply(null,arguments)},Dd=b._emscripten_bind_ContactResultCallback_addSingleResult_7=function(){return(Dd=
|
||||
b._emscripten_bind_ContactResultCallback_addSingleResult_7=b.asm.Lb).apply(null,arguments)},Ed=b._emscripten_bind_ContactResultCallback___destroy___0=function(){return(Ed=b._emscripten_bind_ContactResultCallback___destroy___0=b.asm.Mb).apply(null,arguments)},Fd=b._emscripten_bind_ConvexResultCallback_hasHit_0=function(){return(Fd=b._emscripten_bind_ConvexResultCallback_hasHit_0=b.asm.Nb).apply(null,arguments)},Gd=b._emscripten_bind_ConvexResultCallback_get_m_collisionFilterGroup_0=function(){return(Gd=
|
||||
b._emscripten_bind_ConvexResultCallback_get_m_collisionFilterGroup_0=b.asm.Ob).apply(null,arguments)},Hd=b._emscripten_bind_ConvexResultCallback_set_m_collisionFilterGroup_1=function(){return(Hd=b._emscripten_bind_ConvexResultCallback_set_m_collisionFilterGroup_1=b.asm.Pb).apply(null,arguments)},Id=b._emscripten_bind_ConvexResultCallback_get_m_collisionFilterMask_0=function(){return(Id=b._emscripten_bind_ConvexResultCallback_get_m_collisionFilterMask_0=b.asm.Qb).apply(null,arguments)},Jd=b._emscripten_bind_ConvexResultCallback_set_m_collisionFilterMask_1=
|
||||
function(){return(Jd=b._emscripten_bind_ConvexResultCallback_set_m_collisionFilterMask_1=b.asm.Rb).apply(null,arguments)},Kd=b._emscripten_bind_ConvexResultCallback_get_m_closestHitFraction_0=function(){return(Kd=b._emscripten_bind_ConvexResultCallback_get_m_closestHitFraction_0=b.asm.Sb).apply(null,arguments)},Ld=b._emscripten_bind_ConvexResultCallback_set_m_closestHitFraction_1=function(){return(Ld=b._emscripten_bind_ConvexResultCallback_set_m_closestHitFraction_1=b.asm.Tb).apply(null,arguments)},
|
||||
Md=b._emscripten_bind_ConvexResultCallback___destroy___0=function(){return(Md=b._emscripten_bind_ConvexResultCallback___destroy___0=b.asm.Ub).apply(null,arguments)},Nd=b._emscripten_bind_btConvexShape_setLocalScaling_1=function(){return(Nd=b._emscripten_bind_btConvexShape_setLocalScaling_1=b.asm.Vb).apply(null,arguments)},Od=b._emscripten_bind_btConvexShape_getLocalScaling_0=function(){return(Od=b._emscripten_bind_btConvexShape_getLocalScaling_0=b.asm.Wb).apply(null,arguments)},Pd=b._emscripten_bind_btConvexShape_calculateLocalInertia_2=
|
||||
function(){return(Pd=b._emscripten_bind_btConvexShape_calculateLocalInertia_2=b.asm.Xb).apply(null,arguments)},Qd=b._emscripten_bind_btConvexShape_setMargin_1=function(){return(Qd=b._emscripten_bind_btConvexShape_setMargin_1=b.asm.Yb).apply(null,arguments)},Rd=b._emscripten_bind_btConvexShape_getMargin_0=function(){return(Rd=b._emscripten_bind_btConvexShape_getMargin_0=b.asm.Zb).apply(null,arguments)},Sd=b._emscripten_bind_btConvexShape___destroy___0=function(){return(Sd=b._emscripten_bind_btConvexShape___destroy___0=
|
||||
b.asm._b).apply(null,arguments)},Td=b._emscripten_bind_btCapsuleShape_btCapsuleShape_2=function(){return(Td=b._emscripten_bind_btCapsuleShape_btCapsuleShape_2=b.asm.$b).apply(null,arguments)},Ud=b._emscripten_bind_btCapsuleShape_setMargin_1=function(){return(Ud=b._emscripten_bind_btCapsuleShape_setMargin_1=b.asm.ac).apply(null,arguments)},Vd=b._emscripten_bind_btCapsuleShape_getMargin_0=function(){return(Vd=b._emscripten_bind_btCapsuleShape_getMargin_0=b.asm.bc).apply(null,arguments)},Wd=b._emscripten_bind_btCapsuleShape_getUpAxis_0=
|
||||
function(){return(Wd=b._emscripten_bind_btCapsuleShape_getUpAxis_0=b.asm.cc).apply(null,arguments)},Xd=b._emscripten_bind_btCapsuleShape_getRadius_0=function(){return(Xd=b._emscripten_bind_btCapsuleShape_getRadius_0=b.asm.dc).apply(null,arguments)},Yd=b._emscripten_bind_btCapsuleShape_getHalfHeight_0=function(){return(Yd=b._emscripten_bind_btCapsuleShape_getHalfHeight_0=b.asm.ec).apply(null,arguments)},Zd=b._emscripten_bind_btCapsuleShape_setLocalScaling_1=function(){return(Zd=b._emscripten_bind_btCapsuleShape_setLocalScaling_1=
|
||||
b.asm.fc).apply(null,arguments)},$d=b._emscripten_bind_btCapsuleShape_getLocalScaling_0=function(){return($d=b._emscripten_bind_btCapsuleShape_getLocalScaling_0=b.asm.gc).apply(null,arguments)},ae=b._emscripten_bind_btCapsuleShape_calculateLocalInertia_2=function(){return(ae=b._emscripten_bind_btCapsuleShape_calculateLocalInertia_2=b.asm.hc).apply(null,arguments)},be=b._emscripten_bind_btCapsuleShape___destroy___0=function(){return(be=b._emscripten_bind_btCapsuleShape___destroy___0=b.asm.ic).apply(null,
|
||||
arguments)},ce=b._emscripten_bind_btCylinderShape_btCylinderShape_1=function(){return(ce=b._emscripten_bind_btCylinderShape_btCylinderShape_1=b.asm.jc).apply(null,arguments)},de=b._emscripten_bind_btCylinderShape_setMargin_1=function(){return(de=b._emscripten_bind_btCylinderShape_setMargin_1=b.asm.kc).apply(null,arguments)},ee=b._emscripten_bind_btCylinderShape_getMargin_0=function(){return(ee=b._emscripten_bind_btCylinderShape_getMargin_0=b.asm.lc).apply(null,arguments)},fe=b._emscripten_bind_btCylinderShape_setLocalScaling_1=
|
||||
function(){return(fe=b._emscripten_bind_btCylinderShape_setLocalScaling_1=b.asm.mc).apply(null,arguments)},ge=b._emscripten_bind_btCylinderShape_getLocalScaling_0=function(){return(ge=b._emscripten_bind_btCylinderShape_getLocalScaling_0=b.asm.nc).apply(null,arguments)},he=b._emscripten_bind_btCylinderShape_calculateLocalInertia_2=function(){return(he=b._emscripten_bind_btCylinderShape_calculateLocalInertia_2=b.asm.oc).apply(null,arguments)},ie=b._emscripten_bind_btCylinderShape___destroy___0=function(){return(ie=
|
||||
b._emscripten_bind_btCylinderShape___destroy___0=b.asm.pc).apply(null,arguments)},je=b._emscripten_bind_btConeShape_btConeShape_2=function(){return(je=b._emscripten_bind_btConeShape_btConeShape_2=b.asm.qc).apply(null,arguments)},ke=b._emscripten_bind_btConeShape_setLocalScaling_1=function(){return(ke=b._emscripten_bind_btConeShape_setLocalScaling_1=b.asm.rc).apply(null,arguments)},le=b._emscripten_bind_btConeShape_getLocalScaling_0=function(){return(le=b._emscripten_bind_btConeShape_getLocalScaling_0=
|
||||
b.asm.sc).apply(null,arguments)},me=b._emscripten_bind_btConeShape_calculateLocalInertia_2=function(){return(me=b._emscripten_bind_btConeShape_calculateLocalInertia_2=b.asm.tc).apply(null,arguments)},ne=b._emscripten_bind_btConeShape___destroy___0=function(){return(ne=b._emscripten_bind_btConeShape___destroy___0=b.asm.uc).apply(null,arguments)},oe=b._emscripten_bind_btStridingMeshInterface_setScaling_1=function(){return(oe=b._emscripten_bind_btStridingMeshInterface_setScaling_1=b.asm.vc).apply(null,
|
||||
arguments)},pe=b._emscripten_bind_btStridingMeshInterface___destroy___0=function(){return(pe=b._emscripten_bind_btStridingMeshInterface___destroy___0=b.asm.wc).apply(null,arguments)},qe=b._emscripten_bind_btTriangleMeshShape_setLocalScaling_1=function(){return(qe=b._emscripten_bind_btTriangleMeshShape_setLocalScaling_1=b.asm.xc).apply(null,arguments)},re=b._emscripten_bind_btTriangleMeshShape_getLocalScaling_0=function(){return(re=b._emscripten_bind_btTriangleMeshShape_getLocalScaling_0=b.asm.yc).apply(null,
|
||||
arguments)},se=b._emscripten_bind_btTriangleMeshShape_calculateLocalInertia_2=function(){return(se=b._emscripten_bind_btTriangleMeshShape_calculateLocalInertia_2=b.asm.zc).apply(null,arguments)},te=b._emscripten_bind_btTriangleMeshShape___destroy___0=function(){return(te=b._emscripten_bind_btTriangleMeshShape___destroy___0=b.asm.Ac).apply(null,arguments)},ue=b._emscripten_bind_btPrimitiveManagerBase_is_trimesh_0=function(){return(ue=b._emscripten_bind_btPrimitiveManagerBase_is_trimesh_0=b.asm.Bc).apply(null,
|
||||
arguments)},ve=b._emscripten_bind_btPrimitiveManagerBase_get_primitive_count_0=function(){return(ve=b._emscripten_bind_btPrimitiveManagerBase_get_primitive_count_0=b.asm.Cc).apply(null,arguments)},we=b._emscripten_bind_btPrimitiveManagerBase_get_primitive_box_2=function(){return(we=b._emscripten_bind_btPrimitiveManagerBase_get_primitive_box_2=b.asm.Dc).apply(null,arguments)},xe=b._emscripten_bind_btPrimitiveManagerBase_get_primitive_triangle_2=function(){return(xe=b._emscripten_bind_btPrimitiveManagerBase_get_primitive_triangle_2=
|
||||
b.asm.Ec).apply(null,arguments)},ye=b._emscripten_bind_btPrimitiveManagerBase___destroy___0=function(){return(ye=b._emscripten_bind_btPrimitiveManagerBase___destroy___0=b.asm.Fc).apply(null,arguments)},ze=b._emscripten_bind_btGImpactShapeInterface_updateBound_0=function(){return(ze=b._emscripten_bind_btGImpactShapeInterface_updateBound_0=b.asm.Gc).apply(null,arguments)},Ae=b._emscripten_bind_btGImpactShapeInterface_postUpdate_0=function(){return(Ae=b._emscripten_bind_btGImpactShapeInterface_postUpdate_0=
|
||||
b.asm.Hc).apply(null,arguments)},Be=b._emscripten_bind_btGImpactShapeInterface_getShapeType_0=function(){return(Be=b._emscripten_bind_btGImpactShapeInterface_getShapeType_0=b.asm.Ic).apply(null,arguments)},Ce=b._emscripten_bind_btGImpactShapeInterface_getName_0=function(){return(Ce=b._emscripten_bind_btGImpactShapeInterface_getName_0=b.asm.Jc).apply(null,arguments)},De=b._emscripten_bind_btGImpactShapeInterface_getGImpactShapeType_0=function(){return(De=b._emscripten_bind_btGImpactShapeInterface_getGImpactShapeType_0=
|
||||
b.asm.Kc).apply(null,arguments)},Ee=b._emscripten_bind_btGImpactShapeInterface_getPrimitiveManager_0=function(){return(Ee=b._emscripten_bind_btGImpactShapeInterface_getPrimitiveManager_0=b.asm.Lc).apply(null,arguments)},Fe=b._emscripten_bind_btGImpactShapeInterface_getNumChildShapes_0=function(){return(Fe=b._emscripten_bind_btGImpactShapeInterface_getNumChildShapes_0=b.asm.Mc).apply(null,arguments)},Ge=b._emscripten_bind_btGImpactShapeInterface_childrenHasTransform_0=function(){return(Ge=b._emscripten_bind_btGImpactShapeInterface_childrenHasTransform_0=
|
||||
b.asm.Nc).apply(null,arguments)},He=b._emscripten_bind_btGImpactShapeInterface_needsRetrieveTriangles_0=function(){return(He=b._emscripten_bind_btGImpactShapeInterface_needsRetrieveTriangles_0=b.asm.Oc).apply(null,arguments)},Ie=b._emscripten_bind_btGImpactShapeInterface_needsRetrieveTetrahedrons_0=function(){return(Ie=b._emscripten_bind_btGImpactShapeInterface_needsRetrieveTetrahedrons_0=b.asm.Pc).apply(null,arguments)},Je=b._emscripten_bind_btGImpactShapeInterface_getBulletTriangle_2=function(){return(Je=
|
||||
b._emscripten_bind_btGImpactShapeInterface_getBulletTriangle_2=b.asm.Qc).apply(null,arguments)},Ke=b._emscripten_bind_btGImpactShapeInterface_getBulletTetrahedron_2=function(){return(Ke=b._emscripten_bind_btGImpactShapeInterface_getBulletTetrahedron_2=b.asm.Rc).apply(null,arguments)},Le=b._emscripten_bind_btGImpactShapeInterface_getChildShape_1=function(){return(Le=b._emscripten_bind_btGImpactShapeInterface_getChildShape_1=b.asm.Sc).apply(null,arguments)},Me=b._emscripten_bind_btGImpactShapeInterface_getChildTransform_1=
|
||||
function(){return(Me=b._emscripten_bind_btGImpactShapeInterface_getChildTransform_1=b.asm.Tc).apply(null,arguments)},Ne=b._emscripten_bind_btGImpactShapeInterface_setChildTransform_2=function(){return(Ne=b._emscripten_bind_btGImpactShapeInterface_setChildTransform_2=b.asm.Uc).apply(null,arguments)},Oe=b._emscripten_bind_btGImpactShapeInterface_setLocalScaling_1=function(){return(Oe=b._emscripten_bind_btGImpactShapeInterface_setLocalScaling_1=b.asm.Vc).apply(null,arguments)},Pe=b._emscripten_bind_btGImpactShapeInterface_getLocalScaling_0=
|
||||
function(){return(Pe=b._emscripten_bind_btGImpactShapeInterface_getLocalScaling_0=b.asm.Wc).apply(null,arguments)},Qe=b._emscripten_bind_btGImpactShapeInterface_calculateLocalInertia_2=function(){return(Qe=b._emscripten_bind_btGImpactShapeInterface_calculateLocalInertia_2=b.asm.Xc).apply(null,arguments)},Re=b._emscripten_bind_btGImpactShapeInterface___destroy___0=function(){return(Re=b._emscripten_bind_btGImpactShapeInterface___destroy___0=b.asm.Yc).apply(null,arguments)},Se=b._emscripten_bind_btActivatingCollisionAlgorithm___destroy___0=
|
||||
function(){return(Se=b._emscripten_bind_btActivatingCollisionAlgorithm___destroy___0=b.asm.Zc).apply(null,arguments)},Te=b._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_0=function(){return(Te=b._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_0=b.asm._c).apply(null,arguments)},Ue=b._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_1=function(){return(Ue=b._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_1=
|
||||
b.asm.$c).apply(null,arguments)},Ve=b._emscripten_bind_btDefaultCollisionConfiguration___destroy___0=function(){return(Ve=b._emscripten_bind_btDefaultCollisionConfiguration___destroy___0=b.asm.ad).apply(null,arguments)},We=b._emscripten_bind_btDispatcher_getNumManifolds_0=function(){return(We=b._emscripten_bind_btDispatcher_getNumManifolds_0=b.asm.bd).apply(null,arguments)},Xe=b._emscripten_bind_btDispatcher_getManifoldByIndexInternal_1=function(){return(Xe=b._emscripten_bind_btDispatcher_getManifoldByIndexInternal_1=
|
||||
b.asm.cd).apply(null,arguments)},Ye=b._emscripten_bind_btDispatcher___destroy___0=function(){return(Ye=b._emscripten_bind_btDispatcher___destroy___0=b.asm.dd).apply(null,arguments)},Ze=b._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_3=function(){return(Ze=b._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_3=b.asm.ed).apply(null,arguments)},$e=b._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_5=function(){return($e=b._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_5=
|
||||
b.asm.fd).apply(null,arguments)},af=b._emscripten_bind_btGeneric6DofConstraint_setLinearLowerLimit_1=function(){return(af=b._emscripten_bind_btGeneric6DofConstraint_setLinearLowerLimit_1=b.asm.gd).apply(null,arguments)},bf=b._emscripten_bind_btGeneric6DofConstraint_setLinearUpperLimit_1=function(){return(bf=b._emscripten_bind_btGeneric6DofConstraint_setLinearUpperLimit_1=b.asm.hd).apply(null,arguments)},cf=b._emscripten_bind_btGeneric6DofConstraint_setAngularLowerLimit_1=function(){return(cf=b._emscripten_bind_btGeneric6DofConstraint_setAngularLowerLimit_1=
|
||||
b.asm.id).apply(null,arguments)},df=b._emscripten_bind_btGeneric6DofConstraint_setAngularUpperLimit_1=function(){return(df=b._emscripten_bind_btGeneric6DofConstraint_setAngularUpperLimit_1=b.asm.jd).apply(null,arguments)},ef=b._emscripten_bind_btGeneric6DofConstraint_getFrameOffsetA_0=function(){return(ef=b._emscripten_bind_btGeneric6DofConstraint_getFrameOffsetA_0=b.asm.kd).apply(null,arguments)},ff=b._emscripten_bind_btGeneric6DofConstraint_enableFeedback_1=function(){return(ff=b._emscripten_bind_btGeneric6DofConstraint_enableFeedback_1=
|
||||
b.asm.ld).apply(null,arguments)},gf=b._emscripten_bind_btGeneric6DofConstraint_getBreakingImpulseThreshold_0=function(){return(gf=b._emscripten_bind_btGeneric6DofConstraint_getBreakingImpulseThreshold_0=b.asm.md).apply(null,arguments)},hf=b._emscripten_bind_btGeneric6DofConstraint_setBreakingImpulseThreshold_1=function(){return(hf=b._emscripten_bind_btGeneric6DofConstraint_setBreakingImpulseThreshold_1=b.asm.nd).apply(null,arguments)},jf=b._emscripten_bind_btGeneric6DofConstraint_getParam_2=function(){return(jf=
|
||||
b._emscripten_bind_btGeneric6DofConstraint_getParam_2=b.asm.od).apply(null,arguments)},kf=b._emscripten_bind_btGeneric6DofConstraint_setParam_3=function(){return(kf=b._emscripten_bind_btGeneric6DofConstraint_setParam_3=b.asm.pd).apply(null,arguments)},lf=b._emscripten_bind_btGeneric6DofConstraint___destroy___0=function(){return(lf=b._emscripten_bind_btGeneric6DofConstraint___destroy___0=b.asm.qd).apply(null,arguments)},mf=b._emscripten_bind_btDiscreteDynamicsWorld_btDiscreteDynamicsWorld_4=function(){return(mf=
|
||||
b._emscripten_bind_btDiscreteDynamicsWorld_btDiscreteDynamicsWorld_4=b.asm.rd).apply(null,arguments)},nf=b._emscripten_bind_btDiscreteDynamicsWorld_setGravity_1=function(){return(nf=b._emscripten_bind_btDiscreteDynamicsWorld_setGravity_1=b.asm.sd).apply(null,arguments)},of=b._emscripten_bind_btDiscreteDynamicsWorld_getGravity_0=function(){return(of=b._emscripten_bind_btDiscreteDynamicsWorld_getGravity_0=b.asm.td).apply(null,arguments)},pf=b._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_1=
|
||||
function(){return(pf=b._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_1=b.asm.ud).apply(null,arguments)},qf=b._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_3=function(){return(qf=b._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_3=b.asm.vd).apply(null,arguments)},rf=b._emscripten_bind_btDiscreteDynamicsWorld_removeRigidBody_1=function(){return(rf=b._emscripten_bind_btDiscreteDynamicsWorld_removeRigidBody_1=b.asm.wd).apply(null,arguments)},sf=b._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_1=
|
||||
function(){return(sf=b._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_1=b.asm.xd).apply(null,arguments)},tf=b._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_2=function(){return(tf=b._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_2=b.asm.yd).apply(null,arguments)},uf=b._emscripten_bind_btDiscreteDynamicsWorld_removeConstraint_1=function(){return(uf=b._emscripten_bind_btDiscreteDynamicsWorld_removeConstraint_1=b.asm.zd).apply(null,arguments)},vf=b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_1=
|
||||
function(){return(vf=b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_1=b.asm.Ad).apply(null,arguments)},wf=b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_2=function(){return(wf=b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_2=b.asm.Bd).apply(null,arguments)},xf=b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_3=function(){return(xf=b._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_3=b.asm.Cd).apply(null,arguments)},yf=b._emscripten_bind_btDiscreteDynamicsWorld_setContactAddedCallback_1=
|
||||
function(){return(yf=b._emscripten_bind_btDiscreteDynamicsWorld_setContactAddedCallback_1=b.asm.Dd).apply(null,arguments)},zf=b._emscripten_bind_btDiscreteDynamicsWorld_setContactProcessedCallback_1=function(){return(zf=b._emscripten_bind_btDiscreteDynamicsWorld_setContactProcessedCallback_1=b.asm.Ed).apply(null,arguments)},Af=b._emscripten_bind_btDiscreteDynamicsWorld_setContactDestroyedCallback_1=function(){return(Af=b._emscripten_bind_btDiscreteDynamicsWorld_setContactDestroyedCallback_1=b.asm.Fd).apply(null,
|
||||
arguments)},Bf=b._emscripten_bind_btDiscreteDynamicsWorld_getDispatcher_0=function(){return(Bf=b._emscripten_bind_btDiscreteDynamicsWorld_getDispatcher_0=b.asm.Gd).apply(null,arguments)},Cf=b._emscripten_bind_btDiscreteDynamicsWorld_rayTest_3=function(){return(Cf=b._emscripten_bind_btDiscreteDynamicsWorld_rayTest_3=b.asm.Hd).apply(null,arguments)},Df=b._emscripten_bind_btDiscreteDynamicsWorld_getPairCache_0=function(){return(Df=b._emscripten_bind_btDiscreteDynamicsWorld_getPairCache_0=b.asm.Id).apply(null,
|
||||
arguments)},Ef=b._emscripten_bind_btDiscreteDynamicsWorld_getDispatchInfo_0=function(){return(Ef=b._emscripten_bind_btDiscreteDynamicsWorld_getDispatchInfo_0=b.asm.Jd).apply(null,arguments)},Ff=b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_1=function(){return(Ff=b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_1=b.asm.Kd).apply(null,arguments)},Gf=b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_2=function(){return(Gf=b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_2=
|
||||
b.asm.Ld).apply(null,arguments)},Hf=b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_3=function(){return(Hf=b._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_3=b.asm.Md).apply(null,arguments)},If=b._emscripten_bind_btDiscreteDynamicsWorld_removeCollisionObject_1=function(){return(If=b._emscripten_bind_btDiscreteDynamicsWorld_removeCollisionObject_1=b.asm.Nd).apply(null,arguments)},Jf=b._emscripten_bind_btDiscreteDynamicsWorld_getBroadphase_0=function(){return(Jf=b._emscripten_bind_btDiscreteDynamicsWorld_getBroadphase_0=
|
||||
b.asm.Od).apply(null,arguments)},Kf=b._emscripten_bind_btDiscreteDynamicsWorld_convexSweepTest_5=function(){return(Kf=b._emscripten_bind_btDiscreteDynamicsWorld_convexSweepTest_5=b.asm.Pd).apply(null,arguments)},Lf=b._emscripten_bind_btDiscreteDynamicsWorld_contactPairTest_3=function(){return(Lf=b._emscripten_bind_btDiscreteDynamicsWorld_contactPairTest_3=b.asm.Qd).apply(null,arguments)},Mf=b._emscripten_bind_btDiscreteDynamicsWorld_contactTest_2=function(){return(Mf=b._emscripten_bind_btDiscreteDynamicsWorld_contactTest_2=
|
||||
b.asm.Rd).apply(null,arguments)},Nf=b._emscripten_bind_btDiscreteDynamicsWorld_updateSingleAabb_1=function(){return(Nf=b._emscripten_bind_btDiscreteDynamicsWorld_updateSingleAabb_1=b.asm.Sd).apply(null,arguments)},Of=b._emscripten_bind_btDiscreteDynamicsWorld_setDebugDrawer_1=function(){return(Of=b._emscripten_bind_btDiscreteDynamicsWorld_setDebugDrawer_1=b.asm.Td).apply(null,arguments)},Pf=b._emscripten_bind_btDiscreteDynamicsWorld_getDebugDrawer_0=function(){return(Pf=b._emscripten_bind_btDiscreteDynamicsWorld_getDebugDrawer_0=
|
||||
b.asm.Ud).apply(null,arguments)},Qf=b._emscripten_bind_btDiscreteDynamicsWorld_debugDrawWorld_0=function(){return(Qf=b._emscripten_bind_btDiscreteDynamicsWorld_debugDrawWorld_0=b.asm.Vd).apply(null,arguments)},Rf=b._emscripten_bind_btDiscreteDynamicsWorld_debugDrawObject_3=function(){return(Rf=b._emscripten_bind_btDiscreteDynamicsWorld_debugDrawObject_3=b.asm.Wd).apply(null,arguments)},Sf=b._emscripten_bind_btDiscreteDynamicsWorld_addAction_1=function(){return(Sf=b._emscripten_bind_btDiscreteDynamicsWorld_addAction_1=
|
||||
b.asm.Xd).apply(null,arguments)},Tf=b._emscripten_bind_btDiscreteDynamicsWorld_removeAction_1=function(){return(Tf=b._emscripten_bind_btDiscreteDynamicsWorld_removeAction_1=b.asm.Yd).apply(null,arguments)},Uf=b._emscripten_bind_btDiscreteDynamicsWorld_getSolverInfo_0=function(){return(Uf=b._emscripten_bind_btDiscreteDynamicsWorld_getSolverInfo_0=b.asm.Zd).apply(null,arguments)},Vf=b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_1=function(){return(Vf=b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_1=
|
||||
b.asm._d).apply(null,arguments)},Wf=b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_2=function(){return(Wf=b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_2=b.asm.$d).apply(null,arguments)},Xf=b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_3=function(){return(Xf=b._emscripten_bind_btDiscreteDynamicsWorld_setInternalTickCallback_3=b.asm.ae).apply(null,arguments)},Yf=b._emscripten_bind_btDiscreteDynamicsWorld___destroy___0=function(){return(Yf=
|
||||
b._emscripten_bind_btDiscreteDynamicsWorld___destroy___0=b.asm.be).apply(null,arguments)},Zf=b._emscripten_bind_btVehicleRaycaster_castRay_3=function(){return(Zf=b._emscripten_bind_btVehicleRaycaster_castRay_3=b.asm.ce).apply(null,arguments)},$f=b._emscripten_bind_btVehicleRaycaster___destroy___0=function(){return($f=b._emscripten_bind_btVehicleRaycaster___destroy___0=b.asm.de).apply(null,arguments)},ag=b._emscripten_bind_btActionInterface_updateAction_2=function(){return(ag=b._emscripten_bind_btActionInterface_updateAction_2=
|
||||
b.asm.ee).apply(null,arguments)},bg=b._emscripten_bind_btActionInterface___destroy___0=function(){return(bg=b._emscripten_bind_btActionInterface___destroy___0=b.asm.fe).apply(null,arguments)},cg=b._emscripten_bind_btGhostObject_btGhostObject_0=function(){return(cg=b._emscripten_bind_btGhostObject_btGhostObject_0=b.asm.ge).apply(null,arguments)},dg=b._emscripten_bind_btGhostObject_getNumOverlappingObjects_0=function(){return(dg=b._emscripten_bind_btGhostObject_getNumOverlappingObjects_0=b.asm.he).apply(null,
|
||||
arguments)},eg=b._emscripten_bind_btGhostObject_getOverlappingObject_1=function(){return(eg=b._emscripten_bind_btGhostObject_getOverlappingObject_1=b.asm.ie).apply(null,arguments)},fg=b._emscripten_bind_btGhostObject_setAnisotropicFriction_2=function(){return(fg=b._emscripten_bind_btGhostObject_setAnisotropicFriction_2=b.asm.je).apply(null,arguments)},gg=b._emscripten_bind_btGhostObject_getCollisionShape_0=function(){return(gg=b._emscripten_bind_btGhostObject_getCollisionShape_0=b.asm.ke).apply(null,
|
||||
arguments)},hg=b._emscripten_bind_btGhostObject_setContactProcessingThreshold_1=function(){return(hg=b._emscripten_bind_btGhostObject_setContactProcessingThreshold_1=b.asm.le).apply(null,arguments)},ig=b._emscripten_bind_btGhostObject_setActivationState_1=function(){return(ig=b._emscripten_bind_btGhostObject_setActivationState_1=b.asm.me).apply(null,arguments)},jg=b._emscripten_bind_btGhostObject_forceActivationState_1=function(){return(jg=b._emscripten_bind_btGhostObject_forceActivationState_1=b.asm.ne).apply(null,
|
||||
arguments)},kg=b._emscripten_bind_btGhostObject_activate_0=function(){return(kg=b._emscripten_bind_btGhostObject_activate_0=b.asm.oe).apply(null,arguments)},lg=b._emscripten_bind_btGhostObject_activate_1=function(){return(lg=b._emscripten_bind_btGhostObject_activate_1=b.asm.pe).apply(null,arguments)},mg=b._emscripten_bind_btGhostObject_isActive_0=function(){return(mg=b._emscripten_bind_btGhostObject_isActive_0=b.asm.qe).apply(null,arguments)},ng=b._emscripten_bind_btGhostObject_isKinematicObject_0=
|
||||
function(){return(ng=b._emscripten_bind_btGhostObject_isKinematicObject_0=b.asm.re).apply(null,arguments)},og=b._emscripten_bind_btGhostObject_isStaticObject_0=function(){return(og=b._emscripten_bind_btGhostObject_isStaticObject_0=b.asm.se).apply(null,arguments)},pg=b._emscripten_bind_btGhostObject_isStaticOrKinematicObject_0=function(){return(pg=b._emscripten_bind_btGhostObject_isStaticOrKinematicObject_0=b.asm.te).apply(null,arguments)},qg=b._emscripten_bind_btGhostObject_getRestitution_0=function(){return(qg=
|
||||
b._emscripten_bind_btGhostObject_getRestitution_0=b.asm.ue).apply(null,arguments)},rg=b._emscripten_bind_btGhostObject_getFriction_0=function(){return(rg=b._emscripten_bind_btGhostObject_getFriction_0=b.asm.ve).apply(null,arguments)},sg=b._emscripten_bind_btGhostObject_getRollingFriction_0=function(){return(sg=b._emscripten_bind_btGhostObject_getRollingFriction_0=b.asm.we).apply(null,arguments)},tg=b._emscripten_bind_btGhostObject_setRestitution_1=function(){return(tg=b._emscripten_bind_btGhostObject_setRestitution_1=
|
||||
b.asm.xe).apply(null,arguments)},ug=b._emscripten_bind_btGhostObject_setFriction_1=function(){return(ug=b._emscripten_bind_btGhostObject_setFriction_1=b.asm.ye).apply(null,arguments)},vg=b._emscripten_bind_btGhostObject_setRollingFriction_1=function(){return(vg=b._emscripten_bind_btGhostObject_setRollingFriction_1=b.asm.ze).apply(null,arguments)},wg=b._emscripten_bind_btGhostObject_getWorldTransform_0=function(){return(wg=b._emscripten_bind_btGhostObject_getWorldTransform_0=b.asm.Ae).apply(null,arguments)},
|
||||
xg=b._emscripten_bind_btGhostObject_getCollisionFlags_0=function(){return(xg=b._emscripten_bind_btGhostObject_getCollisionFlags_0=b.asm.Be).apply(null,arguments)},yg=b._emscripten_bind_btGhostObject_setCollisionFlags_1=function(){return(yg=b._emscripten_bind_btGhostObject_setCollisionFlags_1=b.asm.Ce).apply(null,arguments)},zg=b._emscripten_bind_btGhostObject_setWorldTransform_1=function(){return(zg=b._emscripten_bind_btGhostObject_setWorldTransform_1=b.asm.De).apply(null,arguments)},Ag=b._emscripten_bind_btGhostObject_setCollisionShape_1=
|
||||
function(){return(Ag=b._emscripten_bind_btGhostObject_setCollisionShape_1=b.asm.Ee).apply(null,arguments)},Bg=b._emscripten_bind_btGhostObject_setCcdMotionThreshold_1=function(){return(Bg=b._emscripten_bind_btGhostObject_setCcdMotionThreshold_1=b.asm.Fe).apply(null,arguments)},Cg=b._emscripten_bind_btGhostObject_setCcdSweptSphereRadius_1=function(){return(Cg=b._emscripten_bind_btGhostObject_setCcdSweptSphereRadius_1=b.asm.Ge).apply(null,arguments)},Dg=b._emscripten_bind_btGhostObject_getUserIndex_0=
|
||||
function(){return(Dg=b._emscripten_bind_btGhostObject_getUserIndex_0=b.asm.He).apply(null,arguments)},Eg=b._emscripten_bind_btGhostObject_setUserIndex_1=function(){return(Eg=b._emscripten_bind_btGhostObject_setUserIndex_1=b.asm.Ie).apply(null,arguments)},Fg=b._emscripten_bind_btGhostObject_getUserPointer_0=function(){return(Fg=b._emscripten_bind_btGhostObject_getUserPointer_0=b.asm.Je).apply(null,arguments)},Gg=b._emscripten_bind_btGhostObject_setUserPointer_1=function(){return(Gg=b._emscripten_bind_btGhostObject_setUserPointer_1=
|
||||
b.asm.Ke).apply(null,arguments)},Hg=b._emscripten_bind_btGhostObject_getBroadphaseHandle_0=function(){return(Hg=b._emscripten_bind_btGhostObject_getBroadphaseHandle_0=b.asm.Le).apply(null,arguments)},Ig=b._emscripten_bind_btGhostObject___destroy___0=function(){return(Ig=b._emscripten_bind_btGhostObject___destroy___0=b.asm.Me).apply(null,arguments)},Jg=b._emscripten_bind_btSoftBodySolver___destroy___0=function(){return(Jg=b._emscripten_bind_btSoftBodySolver___destroy___0=b.asm.Ne).apply(null,arguments)},
|
||||
Kg=b._emscripten_bind_VoidPtr___destroy___0=function(){return(Kg=b._emscripten_bind_VoidPtr___destroy___0=b.asm.Oe).apply(null,arguments)},Lg=b._emscripten_bind_DebugDrawer_DebugDrawer_0=function(){return(Lg=b._emscripten_bind_DebugDrawer_DebugDrawer_0=b.asm.Pe).apply(null,arguments)},Mg=b._emscripten_bind_DebugDrawer_drawLine_3=function(){return(Mg=b._emscripten_bind_DebugDrawer_drawLine_3=b.asm.Qe).apply(null,arguments)},Ng=b._emscripten_bind_DebugDrawer_drawContactPoint_5=function(){return(Ng=
|
||||
b._emscripten_bind_DebugDrawer_drawContactPoint_5=b.asm.Re).apply(null,arguments)},Og=b._emscripten_bind_DebugDrawer_reportErrorWarning_1=function(){return(Og=b._emscripten_bind_DebugDrawer_reportErrorWarning_1=b.asm.Se).apply(null,arguments)},Pg=b._emscripten_bind_DebugDrawer_draw3dText_2=function(){return(Pg=b._emscripten_bind_DebugDrawer_draw3dText_2=b.asm.Te).apply(null,arguments)},Qg=b._emscripten_bind_DebugDrawer_setDebugMode_1=function(){return(Qg=b._emscripten_bind_DebugDrawer_setDebugMode_1=
|
||||
b.asm.Ue).apply(null,arguments)},Rg=b._emscripten_bind_DebugDrawer_getDebugMode_0=function(){return(Rg=b._emscripten_bind_DebugDrawer_getDebugMode_0=b.asm.Ve).apply(null,arguments)},Sg=b._emscripten_bind_DebugDrawer___destroy___0=function(){return(Sg=b._emscripten_bind_DebugDrawer___destroy___0=b.asm.We).apply(null,arguments)},Tg=b._emscripten_bind_btVector4_btVector4_0=function(){return(Tg=b._emscripten_bind_btVector4_btVector4_0=b.asm.Xe).apply(null,arguments)},Ug=b._emscripten_bind_btVector4_btVector4_4=
|
||||
function(){return(Ug=b._emscripten_bind_btVector4_btVector4_4=b.asm.Ye).apply(null,arguments)},Vg=b._emscripten_bind_btVector4_w_0=function(){return(Vg=b._emscripten_bind_btVector4_w_0=b.asm.Ze).apply(null,arguments)},Wg=b._emscripten_bind_btVector4_setValue_4=function(){return(Wg=b._emscripten_bind_btVector4_setValue_4=b.asm._e).apply(null,arguments)},Xg=b._emscripten_bind_btVector4_length_0=function(){return(Xg=b._emscripten_bind_btVector4_length_0=b.asm.$e).apply(null,arguments)},Yg=b._emscripten_bind_btVector4_x_0=
|
||||
function(){return(Yg=b._emscripten_bind_btVector4_x_0=b.asm.af).apply(null,arguments)},Zg=b._emscripten_bind_btVector4_y_0=function(){return(Zg=b._emscripten_bind_btVector4_y_0=b.asm.bf).apply(null,arguments)},$g=b._emscripten_bind_btVector4_z_0=function(){return($g=b._emscripten_bind_btVector4_z_0=b.asm.cf).apply(null,arguments)},ah=b._emscripten_bind_btVector4_setX_1=function(){return(ah=b._emscripten_bind_btVector4_setX_1=b.asm.df).apply(null,arguments)},bh=b._emscripten_bind_btVector4_setY_1=
|
||||
function(){return(bh=b._emscripten_bind_btVector4_setY_1=b.asm.ef).apply(null,arguments)},ch=b._emscripten_bind_btVector4_setZ_1=function(){return(ch=b._emscripten_bind_btVector4_setZ_1=b.asm.ff).apply(null,arguments)},dh=b._emscripten_bind_btVector4_normalize_0=function(){return(dh=b._emscripten_bind_btVector4_normalize_0=b.asm.gf).apply(null,arguments)},eh=b._emscripten_bind_btVector4_rotate_2=function(){return(eh=b._emscripten_bind_btVector4_rotate_2=b.asm.hf).apply(null,arguments)},fh=b._emscripten_bind_btVector4_dot_1=
|
||||
function(){return(fh=b._emscripten_bind_btVector4_dot_1=b.asm.jf).apply(null,arguments)},gh=b._emscripten_bind_btVector4_op_mul_1=function(){return(gh=b._emscripten_bind_btVector4_op_mul_1=b.asm.kf).apply(null,arguments)},hh=b._emscripten_bind_btVector4_op_add_1=function(){return(hh=b._emscripten_bind_btVector4_op_add_1=b.asm.lf).apply(null,arguments)},ih=b._emscripten_bind_btVector4_op_sub_1=function(){return(ih=b._emscripten_bind_btVector4_op_sub_1=b.asm.mf).apply(null,arguments)},jh=b._emscripten_bind_btVector4___destroy___0=
|
||||
function(){return(jh=b._emscripten_bind_btVector4___destroy___0=b.asm.nf).apply(null,arguments)},kh=b._emscripten_bind_btQuaternion_btQuaternion_4=function(){return(kh=b._emscripten_bind_btQuaternion_btQuaternion_4=b.asm.of).apply(null,arguments)},lh=b._emscripten_bind_btQuaternion_setValue_4=function(){return(lh=b._emscripten_bind_btQuaternion_setValue_4=b.asm.pf).apply(null,arguments)},mh=b._emscripten_bind_btQuaternion_setEulerZYX_3=function(){return(mh=b._emscripten_bind_btQuaternion_setEulerZYX_3=
|
||||
b.asm.qf).apply(null,arguments)},nh=b._emscripten_bind_btQuaternion_setRotation_2=function(){return(nh=b._emscripten_bind_btQuaternion_setRotation_2=b.asm.rf).apply(null,arguments)},oh=b._emscripten_bind_btQuaternion_normalize_0=function(){return(oh=b._emscripten_bind_btQuaternion_normalize_0=b.asm.sf).apply(null,arguments)},ph=b._emscripten_bind_btQuaternion_length2_0=function(){return(ph=b._emscripten_bind_btQuaternion_length2_0=b.asm.tf).apply(null,arguments)},qh=b._emscripten_bind_btQuaternion_length_0=
|
||||
function(){return(qh=b._emscripten_bind_btQuaternion_length_0=b.asm.uf).apply(null,arguments)},rh=b._emscripten_bind_btQuaternion_dot_1=function(){return(rh=b._emscripten_bind_btQuaternion_dot_1=b.asm.vf).apply(null,arguments)},sh=b._emscripten_bind_btQuaternion_normalized_0=function(){return(sh=b._emscripten_bind_btQuaternion_normalized_0=b.asm.wf).apply(null,arguments)},th=b._emscripten_bind_btQuaternion_getAxis_0=function(){return(th=b._emscripten_bind_btQuaternion_getAxis_0=b.asm.xf).apply(null,
|
||||
arguments)},uh=b._emscripten_bind_btQuaternion_inverse_0=function(){return(uh=b._emscripten_bind_btQuaternion_inverse_0=b.asm.yf).apply(null,arguments)},vh=b._emscripten_bind_btQuaternion_getAngle_0=function(){return(vh=b._emscripten_bind_btQuaternion_getAngle_0=b.asm.zf).apply(null,arguments)},wh=b._emscripten_bind_btQuaternion_getAngleShortestPath_0=function(){return(wh=b._emscripten_bind_btQuaternion_getAngleShortestPath_0=b.asm.Af).apply(null,arguments)},xh=b._emscripten_bind_btQuaternion_angle_1=
|
||||
function(){return(xh=b._emscripten_bind_btQuaternion_angle_1=b.asm.Bf).apply(null,arguments)},yh=b._emscripten_bind_btQuaternion_angleShortestPath_1=function(){return(yh=b._emscripten_bind_btQuaternion_angleShortestPath_1=b.asm.Cf).apply(null,arguments)},zh=b._emscripten_bind_btQuaternion_op_add_1=function(){return(zh=b._emscripten_bind_btQuaternion_op_add_1=b.asm.Df).apply(null,arguments)},Ah=b._emscripten_bind_btQuaternion_op_sub_1=function(){return(Ah=b._emscripten_bind_btQuaternion_op_sub_1=b.asm.Ef).apply(null,
|
||||
arguments)},Bh=b._emscripten_bind_btQuaternion_op_mul_1=function(){return(Bh=b._emscripten_bind_btQuaternion_op_mul_1=b.asm.Ff).apply(null,arguments)},Ch=b._emscripten_bind_btQuaternion_op_mulq_1=function(){return(Ch=b._emscripten_bind_btQuaternion_op_mulq_1=b.asm.Gf).apply(null,arguments)},Dh=b._emscripten_bind_btQuaternion_op_div_1=function(){return(Dh=b._emscripten_bind_btQuaternion_op_div_1=b.asm.Hf).apply(null,arguments)},Eh=b._emscripten_bind_btQuaternion_x_0=function(){return(Eh=b._emscripten_bind_btQuaternion_x_0=
|
||||
b.asm.If).apply(null,arguments)},Fh=b._emscripten_bind_btQuaternion_y_0=function(){return(Fh=b._emscripten_bind_btQuaternion_y_0=b.asm.Jf).apply(null,arguments)},Gh=b._emscripten_bind_btQuaternion_z_0=function(){return(Gh=b._emscripten_bind_btQuaternion_z_0=b.asm.Kf).apply(null,arguments)},Hh=b._emscripten_bind_btQuaternion_w_0=function(){return(Hh=b._emscripten_bind_btQuaternion_w_0=b.asm.Lf).apply(null,arguments)},Ih=b._emscripten_bind_btQuaternion_setX_1=function(){return(Ih=b._emscripten_bind_btQuaternion_setX_1=
|
||||
b.asm.Mf).apply(null,arguments)},Jh=b._emscripten_bind_btQuaternion_setY_1=function(){return(Jh=b._emscripten_bind_btQuaternion_setY_1=b.asm.Nf).apply(null,arguments)},Kh=b._emscripten_bind_btQuaternion_setZ_1=function(){return(Kh=b._emscripten_bind_btQuaternion_setZ_1=b.asm.Of).apply(null,arguments)},Lh=b._emscripten_bind_btQuaternion_setW_1=function(){return(Lh=b._emscripten_bind_btQuaternion_setW_1=b.asm.Pf).apply(null,arguments)},Mh=b._emscripten_bind_btQuaternion___destroy___0=function(){return(Mh=
|
||||
b._emscripten_bind_btQuaternion___destroy___0=b.asm.Qf).apply(null,arguments)},Nh=b._emscripten_bind_btMatrix3x3_setEulerZYX_3=function(){return(Nh=b._emscripten_bind_btMatrix3x3_setEulerZYX_3=b.asm.Rf).apply(null,arguments)},Oh=b._emscripten_bind_btMatrix3x3_getRotation_1=function(){return(Oh=b._emscripten_bind_btMatrix3x3_getRotation_1=b.asm.Sf).apply(null,arguments)},Ph=b._emscripten_bind_btMatrix3x3_getRow_1=function(){return(Ph=b._emscripten_bind_btMatrix3x3_getRow_1=b.asm.Tf).apply(null,arguments)},
|
||||
Qh=b._emscripten_bind_btMatrix3x3___destroy___0=function(){return(Qh=b._emscripten_bind_btMatrix3x3___destroy___0=b.asm.Uf).apply(null,arguments)},Rh=b._emscripten_bind_btTransform_btTransform_0=function(){return(Rh=b._emscripten_bind_btTransform_btTransform_0=b.asm.Vf).apply(null,arguments)},Sh=b._emscripten_bind_btTransform_btTransform_2=function(){return(Sh=b._emscripten_bind_btTransform_btTransform_2=b.asm.Wf).apply(null,arguments)},Th=b._emscripten_bind_btTransform_setIdentity_0=function(){return(Th=
|
||||
b._emscripten_bind_btTransform_setIdentity_0=b.asm.Xf).apply(null,arguments)},Uh=b._emscripten_bind_btTransform_setOrigin_1=function(){return(Uh=b._emscripten_bind_btTransform_setOrigin_1=b.asm.Yf).apply(null,arguments)},Vh=b._emscripten_bind_btTransform_setRotation_1=function(){return(Vh=b._emscripten_bind_btTransform_setRotation_1=b.asm.Zf).apply(null,arguments)},Wh=b._emscripten_bind_btTransform_getOrigin_0=function(){return(Wh=b._emscripten_bind_btTransform_getOrigin_0=b.asm._f).apply(null,arguments)},
|
||||
Xh=b._emscripten_bind_btTransform_getRotation_0=function(){return(Xh=b._emscripten_bind_btTransform_getRotation_0=b.asm.$f).apply(null,arguments)},Yh=b._emscripten_bind_btTransform_getBasis_0=function(){return(Yh=b._emscripten_bind_btTransform_getBasis_0=b.asm.ag).apply(null,arguments)},Zh=b._emscripten_bind_btTransform_setFromOpenGLMatrix_1=function(){return(Zh=b._emscripten_bind_btTransform_setFromOpenGLMatrix_1=b.asm.bg).apply(null,arguments)},$h=b._emscripten_bind_btTransform_inverse_0=function(){return($h=
|
||||
b._emscripten_bind_btTransform_inverse_0=b.asm.cg).apply(null,arguments)},ai=b._emscripten_bind_btTransform_op_mul_1=function(){return(ai=b._emscripten_bind_btTransform_op_mul_1=b.asm.dg).apply(null,arguments)},bi=b._emscripten_bind_btTransform___destroy___0=function(){return(bi=b._emscripten_bind_btTransform___destroy___0=b.asm.eg).apply(null,arguments)},ci=b._emscripten_bind_MotionState_MotionState_0=function(){return(ci=b._emscripten_bind_MotionState_MotionState_0=b.asm.fg).apply(null,arguments)},
|
||||
di=b._emscripten_bind_MotionState_getWorldTransform_1=function(){return(di=b._emscripten_bind_MotionState_getWorldTransform_1=b.asm.gg).apply(null,arguments)},ei=b._emscripten_bind_MotionState_setWorldTransform_1=function(){return(ei=b._emscripten_bind_MotionState_setWorldTransform_1=b.asm.hg).apply(null,arguments)},fi=b._emscripten_bind_MotionState___destroy___0=function(){return(fi=b._emscripten_bind_MotionState___destroy___0=b.asm.ig).apply(null,arguments)},gi=b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_0=
|
||||
function(){return(gi=b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_0=b.asm.jg).apply(null,arguments)},hi=b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_1=function(){return(hi=b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_1=b.asm.kg).apply(null,arguments)},ii=b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_2=function(){return(ii=b._emscripten_bind_btDefaultMotionState_btDefaultMotionState_2=b.asm.lg).apply(null,arguments)},ji=b._emscripten_bind_btDefaultMotionState_getWorldTransform_1=
|
||||
function(){return(ji=b._emscripten_bind_btDefaultMotionState_getWorldTransform_1=b.asm.mg).apply(null,arguments)},ki=b._emscripten_bind_btDefaultMotionState_setWorldTransform_1=function(){return(ki=b._emscripten_bind_btDefaultMotionState_setWorldTransform_1=b.asm.ng).apply(null,arguments)},li=b._emscripten_bind_btDefaultMotionState_get_m_graphicsWorldTrans_0=function(){return(li=b._emscripten_bind_btDefaultMotionState_get_m_graphicsWorldTrans_0=b.asm.og).apply(null,arguments)},mi=b._emscripten_bind_btDefaultMotionState_set_m_graphicsWorldTrans_1=
|
||||
function(){return(mi=b._emscripten_bind_btDefaultMotionState_set_m_graphicsWorldTrans_1=b.asm.pg).apply(null,arguments)},ni=b._emscripten_bind_btDefaultMotionState___destroy___0=function(){return(ni=b._emscripten_bind_btDefaultMotionState___destroy___0=b.asm.qg).apply(null,arguments)},oi=b._emscripten_bind_btCollisionObjectWrapper_getWorldTransform_0=function(){return(oi=b._emscripten_bind_btCollisionObjectWrapper_getWorldTransform_0=b.asm.rg).apply(null,arguments)},pi=b._emscripten_bind_btCollisionObjectWrapper_getCollisionObject_0=
|
||||
function(){return(pi=b._emscripten_bind_btCollisionObjectWrapper_getCollisionObject_0=b.asm.sg).apply(null,arguments)},qi=b._emscripten_bind_btCollisionObjectWrapper_getCollisionShape_0=function(){return(qi=b._emscripten_bind_btCollisionObjectWrapper_getCollisionShape_0=b.asm.tg).apply(null,arguments)},ri=b._emscripten_bind_ClosestRayResultCallback_ClosestRayResultCallback_2=function(){return(ri=b._emscripten_bind_ClosestRayResultCallback_ClosestRayResultCallback_2=b.asm.ug).apply(null,arguments)},
|
||||
si=b._emscripten_bind_ClosestRayResultCallback_hasHit_0=function(){return(si=b._emscripten_bind_ClosestRayResultCallback_hasHit_0=b.asm.vg).apply(null,arguments)},ti=b._emscripten_bind_ClosestRayResultCallback_get_m_rayFromWorld_0=function(){return(ti=b._emscripten_bind_ClosestRayResultCallback_get_m_rayFromWorld_0=b.asm.wg).apply(null,arguments)},ui=b._emscripten_bind_ClosestRayResultCallback_set_m_rayFromWorld_1=function(){return(ui=b._emscripten_bind_ClosestRayResultCallback_set_m_rayFromWorld_1=
|
||||
b.asm.xg).apply(null,arguments)},vi=b._emscripten_bind_ClosestRayResultCallback_get_m_rayToWorld_0=function(){return(vi=b._emscripten_bind_ClosestRayResultCallback_get_m_rayToWorld_0=b.asm.yg).apply(null,arguments)},wi=b._emscripten_bind_ClosestRayResultCallback_set_m_rayToWorld_1=function(){return(wi=b._emscripten_bind_ClosestRayResultCallback_set_m_rayToWorld_1=b.asm.zg).apply(null,arguments)},xi=b._emscripten_bind_ClosestRayResultCallback_get_m_hitNormalWorld_0=function(){return(xi=b._emscripten_bind_ClosestRayResultCallback_get_m_hitNormalWorld_0=
|
||||
b.asm.Ag).apply(null,arguments)},yi=b._emscripten_bind_ClosestRayResultCallback_set_m_hitNormalWorld_1=function(){return(yi=b._emscripten_bind_ClosestRayResultCallback_set_m_hitNormalWorld_1=b.asm.Bg).apply(null,arguments)},zi=b._emscripten_bind_ClosestRayResultCallback_get_m_hitPointWorld_0=function(){return(zi=b._emscripten_bind_ClosestRayResultCallback_get_m_hitPointWorld_0=b.asm.Cg).apply(null,arguments)},Ai=b._emscripten_bind_ClosestRayResultCallback_set_m_hitPointWorld_1=function(){return(Ai=
|
||||
b._emscripten_bind_ClosestRayResultCallback_set_m_hitPointWorld_1=b.asm.Dg).apply(null,arguments)},Bi=b._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterGroup_0=function(){return(Bi=b._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterGroup_0=b.asm.Eg).apply(null,arguments)},Ci=b._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterGroup_1=function(){return(Ci=b._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterGroup_1=b.asm.Fg).apply(null,arguments)},
|
||||
Di=b._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterMask_0=function(){return(Di=b._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterMask_0=b.asm.Gg).apply(null,arguments)},Ei=b._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterMask_1=function(){return(Ei=b._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterMask_1=b.asm.Hg).apply(null,arguments)},Fi=b._emscripten_bind_ClosestRayResultCallback_get_m_closestHitFraction_0=function(){return(Fi=b._emscripten_bind_ClosestRayResultCallback_get_m_closestHitFraction_0=
|
||||
b.asm.Ig).apply(null,arguments)},Gi=b._emscripten_bind_ClosestRayResultCallback_set_m_closestHitFraction_1=function(){return(Gi=b._emscripten_bind_ClosestRayResultCallback_set_m_closestHitFraction_1=b.asm.Jg).apply(null,arguments)},Hi=b._emscripten_bind_ClosestRayResultCallback_get_m_collisionObject_0=function(){return(Hi=b._emscripten_bind_ClosestRayResultCallback_get_m_collisionObject_0=b.asm.Kg).apply(null,arguments)},Ii=b._emscripten_bind_ClosestRayResultCallback_set_m_collisionObject_1=function(){return(Ii=
|
||||
b._emscripten_bind_ClosestRayResultCallback_set_m_collisionObject_1=b.asm.Lg).apply(null,arguments)},Ji=b._emscripten_bind_ClosestRayResultCallback_get_m_flags_0=function(){return(Ji=b._emscripten_bind_ClosestRayResultCallback_get_m_flags_0=b.asm.Mg).apply(null,arguments)},Ki=b._emscripten_bind_ClosestRayResultCallback_set_m_flags_1=function(){return(Ki=b._emscripten_bind_ClosestRayResultCallback_set_m_flags_1=b.asm.Ng).apply(null,arguments)},Li=b._emscripten_bind_ClosestRayResultCallback___destroy___0=
|
||||
function(){return(Li=b._emscripten_bind_ClosestRayResultCallback___destroy___0=b.asm.Og).apply(null,arguments)},Mi=b._emscripten_bind_btConstCollisionObjectArray_size_0=function(){return(Mi=b._emscripten_bind_btConstCollisionObjectArray_size_0=b.asm.Pg).apply(null,arguments)},Ni=b._emscripten_bind_btConstCollisionObjectArray_at_1=function(){return(Ni=b._emscripten_bind_btConstCollisionObjectArray_at_1=b.asm.Qg).apply(null,arguments)},Oi=b._emscripten_bind_btConstCollisionObjectArray___destroy___0=
|
||||
function(){return(Oi=b._emscripten_bind_btConstCollisionObjectArray___destroy___0=b.asm.Rg).apply(null,arguments)},Pi=b._emscripten_bind_btScalarArray_size_0=function(){return(Pi=b._emscripten_bind_btScalarArray_size_0=b.asm.Sg).apply(null,arguments)},Qi=b._emscripten_bind_btScalarArray_at_1=function(){return(Qi=b._emscripten_bind_btScalarArray_at_1=b.asm.Tg).apply(null,arguments)},Ri=b._emscripten_bind_btScalarArray___destroy___0=function(){return(Ri=b._emscripten_bind_btScalarArray___destroy___0=
|
||||
b.asm.Ug).apply(null,arguments)},Si=b._emscripten_bind_AllHitsRayResultCallback_AllHitsRayResultCallback_2=function(){return(Si=b._emscripten_bind_AllHitsRayResultCallback_AllHitsRayResultCallback_2=b.asm.Vg).apply(null,arguments)},Ti=b._emscripten_bind_AllHitsRayResultCallback_hasHit_0=function(){return(Ti=b._emscripten_bind_AllHitsRayResultCallback_hasHit_0=b.asm.Wg).apply(null,arguments)},Ui=b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionObjects_0=function(){return(Ui=b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionObjects_0=
|
||||
b.asm.Xg).apply(null,arguments)},Vi=b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionObjects_1=function(){return(Vi=b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionObjects_1=b.asm.Yg).apply(null,arguments)},Wi=b._emscripten_bind_AllHitsRayResultCallback_get_m_rayFromWorld_0=function(){return(Wi=b._emscripten_bind_AllHitsRayResultCallback_get_m_rayFromWorld_0=b.asm.Zg).apply(null,arguments)},Xi=b._emscripten_bind_AllHitsRayResultCallback_set_m_rayFromWorld_1=function(){return(Xi=
|
||||
b._emscripten_bind_AllHitsRayResultCallback_set_m_rayFromWorld_1=b.asm._g).apply(null,arguments)},Yi=b._emscripten_bind_AllHitsRayResultCallback_get_m_rayToWorld_0=function(){return(Yi=b._emscripten_bind_AllHitsRayResultCallback_get_m_rayToWorld_0=b.asm.$g).apply(null,arguments)},Zi=b._emscripten_bind_AllHitsRayResultCallback_set_m_rayToWorld_1=function(){return(Zi=b._emscripten_bind_AllHitsRayResultCallback_set_m_rayToWorld_1=b.asm.ah).apply(null,arguments)},$i=b._emscripten_bind_AllHitsRayResultCallback_get_m_hitNormalWorld_0=
|
||||
function(){return($i=b._emscripten_bind_AllHitsRayResultCallback_get_m_hitNormalWorld_0=b.asm.bh).apply(null,arguments)},aj=b._emscripten_bind_AllHitsRayResultCallback_set_m_hitNormalWorld_1=function(){return(aj=b._emscripten_bind_AllHitsRayResultCallback_set_m_hitNormalWorld_1=b.asm.ch).apply(null,arguments)},bj=b._emscripten_bind_AllHitsRayResultCallback_get_m_hitPointWorld_0=function(){return(bj=b._emscripten_bind_AllHitsRayResultCallback_get_m_hitPointWorld_0=b.asm.dh).apply(null,arguments)},
|
||||
cj=b._emscripten_bind_AllHitsRayResultCallback_set_m_hitPointWorld_1=function(){return(cj=b._emscripten_bind_AllHitsRayResultCallback_set_m_hitPointWorld_1=b.asm.eh).apply(null,arguments)},dj=b._emscripten_bind_AllHitsRayResultCallback_get_m_hitFractions_0=function(){return(dj=b._emscripten_bind_AllHitsRayResultCallback_get_m_hitFractions_0=b.asm.fh).apply(null,arguments)},ej=b._emscripten_bind_AllHitsRayResultCallback_set_m_hitFractions_1=function(){return(ej=b._emscripten_bind_AllHitsRayResultCallback_set_m_hitFractions_1=
|
||||
b.asm.gh).apply(null,arguments)},fj=b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionFilterGroup_0=function(){return(fj=b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionFilterGroup_0=b.asm.hh).apply(null,arguments)},gj=b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionFilterGroup_1=function(){return(gj=b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionFilterGroup_1=b.asm.ih).apply(null,arguments)},hj=b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionFilterMask_0=
|
||||
function(){return(hj=b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionFilterMask_0=b.asm.jh).apply(null,arguments)},ij=b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionFilterMask_1=function(){return(ij=b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionFilterMask_1=b.asm.kh).apply(null,arguments)},jj=b._emscripten_bind_AllHitsRayResultCallback_get_m_closestHitFraction_0=function(){return(jj=b._emscripten_bind_AllHitsRayResultCallback_get_m_closestHitFraction_0=b.asm.lh).apply(null,
|
||||
arguments)},kj=b._emscripten_bind_AllHitsRayResultCallback_set_m_closestHitFraction_1=function(){return(kj=b._emscripten_bind_AllHitsRayResultCallback_set_m_closestHitFraction_1=b.asm.mh).apply(null,arguments)},lj=b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionObject_0=function(){return(lj=b._emscripten_bind_AllHitsRayResultCallback_get_m_collisionObject_0=b.asm.nh).apply(null,arguments)},mj=b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionObject_1=function(){return(mj=b._emscripten_bind_AllHitsRayResultCallback_set_m_collisionObject_1=
|
||||
b.asm.oh).apply(null,arguments)},nj=b._emscripten_bind_AllHitsRayResultCallback_get_m_flags_0=function(){return(nj=b._emscripten_bind_AllHitsRayResultCallback_get_m_flags_0=b.asm.ph).apply(null,arguments)},oj=b._emscripten_bind_AllHitsRayResultCallback_set_m_flags_1=function(){return(oj=b._emscripten_bind_AllHitsRayResultCallback_set_m_flags_1=b.asm.qh).apply(null,arguments)},pj=b._emscripten_bind_AllHitsRayResultCallback___destroy___0=function(){return(pj=b._emscripten_bind_AllHitsRayResultCallback___destroy___0=
|
||||
b.asm.rh).apply(null,arguments)},qj=b._emscripten_bind_btManifoldPoint_getPositionWorldOnA_0=function(){return(qj=b._emscripten_bind_btManifoldPoint_getPositionWorldOnA_0=b.asm.sh).apply(null,arguments)},rj=b._emscripten_bind_btManifoldPoint_getPositionWorldOnB_0=function(){return(rj=b._emscripten_bind_btManifoldPoint_getPositionWorldOnB_0=b.asm.th).apply(null,arguments)},sj=b._emscripten_bind_btManifoldPoint_getAppliedImpulse_0=function(){return(sj=b._emscripten_bind_btManifoldPoint_getAppliedImpulse_0=
|
||||
b.asm.uh).apply(null,arguments)},tj=b._emscripten_bind_btManifoldPoint_getDistance_0=function(){return(tj=b._emscripten_bind_btManifoldPoint_getDistance_0=b.asm.vh).apply(null,arguments)},uj=b._emscripten_bind_btManifoldPoint_get_m_localPointA_0=function(){return(uj=b._emscripten_bind_btManifoldPoint_get_m_localPointA_0=b.asm.wh).apply(null,arguments)},vj=b._emscripten_bind_btManifoldPoint_set_m_localPointA_1=function(){return(vj=b._emscripten_bind_btManifoldPoint_set_m_localPointA_1=b.asm.xh).apply(null,
|
||||
arguments)},wj=b._emscripten_bind_btManifoldPoint_get_m_localPointB_0=function(){return(wj=b._emscripten_bind_btManifoldPoint_get_m_localPointB_0=b.asm.yh).apply(null,arguments)},xj=b._emscripten_bind_btManifoldPoint_set_m_localPointB_1=function(){return(xj=b._emscripten_bind_btManifoldPoint_set_m_localPointB_1=b.asm.zh).apply(null,arguments)},yj=b._emscripten_bind_btManifoldPoint_get_m_positionWorldOnB_0=function(){return(yj=b._emscripten_bind_btManifoldPoint_get_m_positionWorldOnB_0=b.asm.Ah).apply(null,
|
||||
arguments)},zj=b._emscripten_bind_btManifoldPoint_set_m_positionWorldOnB_1=function(){return(zj=b._emscripten_bind_btManifoldPoint_set_m_positionWorldOnB_1=b.asm.Bh).apply(null,arguments)},Aj=b._emscripten_bind_btManifoldPoint_get_m_positionWorldOnA_0=function(){return(Aj=b._emscripten_bind_btManifoldPoint_get_m_positionWorldOnA_0=b.asm.Ch).apply(null,arguments)},Bj=b._emscripten_bind_btManifoldPoint_set_m_positionWorldOnA_1=function(){return(Bj=b._emscripten_bind_btManifoldPoint_set_m_positionWorldOnA_1=
|
||||
b.asm.Dh).apply(null,arguments)},Cj=b._emscripten_bind_btManifoldPoint_get_m_normalWorldOnB_0=function(){return(Cj=b._emscripten_bind_btManifoldPoint_get_m_normalWorldOnB_0=b.asm.Eh).apply(null,arguments)},Dj=b._emscripten_bind_btManifoldPoint_set_m_normalWorldOnB_1=function(){return(Dj=b._emscripten_bind_btManifoldPoint_set_m_normalWorldOnB_1=b.asm.Fh).apply(null,arguments)},Ej=b._emscripten_bind_btManifoldPoint_get_m_userPersistentData_0=function(){return(Ej=b._emscripten_bind_btManifoldPoint_get_m_userPersistentData_0=
|
||||
b.asm.Gh).apply(null,arguments)},Fj=b._emscripten_bind_btManifoldPoint_set_m_userPersistentData_1=function(){return(Fj=b._emscripten_bind_btManifoldPoint_set_m_userPersistentData_1=b.asm.Hh).apply(null,arguments)},Gj=b._emscripten_bind_btManifoldPoint___destroy___0=function(){return(Gj=b._emscripten_bind_btManifoldPoint___destroy___0=b.asm.Ih).apply(null,arguments)},Hj=b._emscripten_bind_ConcreteContactResultCallback_ConcreteContactResultCallback_0=function(){return(Hj=b._emscripten_bind_ConcreteContactResultCallback_ConcreteContactResultCallback_0=
|
||||
b.asm.Jh).apply(null,arguments)},Ij=b._emscripten_bind_ConcreteContactResultCallback_addSingleResult_7=function(){return(Ij=b._emscripten_bind_ConcreteContactResultCallback_addSingleResult_7=b.asm.Kh).apply(null,arguments)},Jj=b._emscripten_bind_ConcreteContactResultCallback___destroy___0=function(){return(Jj=b._emscripten_bind_ConcreteContactResultCallback___destroy___0=b.asm.Lh).apply(null,arguments)},Kj=b._emscripten_bind_LocalShapeInfo_get_m_shapePart_0=function(){return(Kj=b._emscripten_bind_LocalShapeInfo_get_m_shapePart_0=
|
||||
b.asm.Mh).apply(null,arguments)},Lj=b._emscripten_bind_LocalShapeInfo_set_m_shapePart_1=function(){return(Lj=b._emscripten_bind_LocalShapeInfo_set_m_shapePart_1=b.asm.Nh).apply(null,arguments)},Mj=b._emscripten_bind_LocalShapeInfo_get_m_triangleIndex_0=function(){return(Mj=b._emscripten_bind_LocalShapeInfo_get_m_triangleIndex_0=b.asm.Oh).apply(null,arguments)},Nj=b._emscripten_bind_LocalShapeInfo_set_m_triangleIndex_1=function(){return(Nj=b._emscripten_bind_LocalShapeInfo_set_m_triangleIndex_1=b.asm.Ph).apply(null,
|
||||
arguments)},Oj=b._emscripten_bind_LocalShapeInfo___destroy___0=function(){return(Oj=b._emscripten_bind_LocalShapeInfo___destroy___0=b.asm.Qh).apply(null,arguments)},Pj=b._emscripten_bind_LocalConvexResult_LocalConvexResult_5=function(){return(Pj=b._emscripten_bind_LocalConvexResult_LocalConvexResult_5=b.asm.Rh).apply(null,arguments)},Qj=b._emscripten_bind_LocalConvexResult_get_m_hitCollisionObject_0=function(){return(Qj=b._emscripten_bind_LocalConvexResult_get_m_hitCollisionObject_0=b.asm.Sh).apply(null,
|
||||
arguments)},Rj=b._emscripten_bind_LocalConvexResult_set_m_hitCollisionObject_1=function(){return(Rj=b._emscripten_bind_LocalConvexResult_set_m_hitCollisionObject_1=b.asm.Th).apply(null,arguments)},Sj=b._emscripten_bind_LocalConvexResult_get_m_localShapeInfo_0=function(){return(Sj=b._emscripten_bind_LocalConvexResult_get_m_localShapeInfo_0=b.asm.Uh).apply(null,arguments)},Tj=b._emscripten_bind_LocalConvexResult_set_m_localShapeInfo_1=function(){return(Tj=b._emscripten_bind_LocalConvexResult_set_m_localShapeInfo_1=
|
||||
b.asm.Vh).apply(null,arguments)},Uj=b._emscripten_bind_LocalConvexResult_get_m_hitNormalLocal_0=function(){return(Uj=b._emscripten_bind_LocalConvexResult_get_m_hitNormalLocal_0=b.asm.Wh).apply(null,arguments)},Vj=b._emscripten_bind_LocalConvexResult_set_m_hitNormalLocal_1=function(){return(Vj=b._emscripten_bind_LocalConvexResult_set_m_hitNormalLocal_1=b.asm.Xh).apply(null,arguments)},Wj=b._emscripten_bind_LocalConvexResult_get_m_hitPointLocal_0=function(){return(Wj=b._emscripten_bind_LocalConvexResult_get_m_hitPointLocal_0=
|
||||
b.asm.Yh).apply(null,arguments)},Xj=b._emscripten_bind_LocalConvexResult_set_m_hitPointLocal_1=function(){return(Xj=b._emscripten_bind_LocalConvexResult_set_m_hitPointLocal_1=b.asm.Zh).apply(null,arguments)},Yj=b._emscripten_bind_LocalConvexResult_get_m_hitFraction_0=function(){return(Yj=b._emscripten_bind_LocalConvexResult_get_m_hitFraction_0=b.asm._h).apply(null,arguments)},Zj=b._emscripten_bind_LocalConvexResult_set_m_hitFraction_1=function(){return(Zj=b._emscripten_bind_LocalConvexResult_set_m_hitFraction_1=
|
||||
b.asm.$h).apply(null,arguments)},ak=b._emscripten_bind_LocalConvexResult___destroy___0=function(){return(ak=b._emscripten_bind_LocalConvexResult___destroy___0=b.asm.ai).apply(null,arguments)},bk=b._emscripten_bind_ClosestConvexResultCallback_ClosestConvexResultCallback_2=function(){return(bk=b._emscripten_bind_ClosestConvexResultCallback_ClosestConvexResultCallback_2=b.asm.bi).apply(null,arguments)},ck=b._emscripten_bind_ClosestConvexResultCallback_hasHit_0=function(){return(ck=b._emscripten_bind_ClosestConvexResultCallback_hasHit_0=
|
||||
b.asm.ci).apply(null,arguments)},dk=b._emscripten_bind_ClosestConvexResultCallback_get_m_hitCollisionObject_0=function(){return(dk=b._emscripten_bind_ClosestConvexResultCallback_get_m_hitCollisionObject_0=b.asm.di).apply(null,arguments)},ek=b._emscripten_bind_ClosestConvexResultCallback_set_m_hitCollisionObject_1=function(){return(ek=b._emscripten_bind_ClosestConvexResultCallback_set_m_hitCollisionObject_1=b.asm.ei).apply(null,arguments)},fk=b._emscripten_bind_ClosestConvexResultCallback_get_m_convexFromWorld_0=
|
||||
function(){return(fk=b._emscripten_bind_ClosestConvexResultCallback_get_m_convexFromWorld_0=b.asm.fi).apply(null,arguments)},gk=b._emscripten_bind_ClosestConvexResultCallback_set_m_convexFromWorld_1=function(){return(gk=b._emscripten_bind_ClosestConvexResultCallback_set_m_convexFromWorld_1=b.asm.gi).apply(null,arguments)},hk=b._emscripten_bind_ClosestConvexResultCallback_get_m_convexToWorld_0=function(){return(hk=b._emscripten_bind_ClosestConvexResultCallback_get_m_convexToWorld_0=b.asm.hi).apply(null,
|
||||
arguments)},ik=b._emscripten_bind_ClosestConvexResultCallback_set_m_convexToWorld_1=function(){return(ik=b._emscripten_bind_ClosestConvexResultCallback_set_m_convexToWorld_1=b.asm.ii).apply(null,arguments)},jk=b._emscripten_bind_ClosestConvexResultCallback_get_m_hitNormalWorld_0=function(){return(jk=b._emscripten_bind_ClosestConvexResultCallback_get_m_hitNormalWorld_0=b.asm.ji).apply(null,arguments)},kk=b._emscripten_bind_ClosestConvexResultCallback_set_m_hitNormalWorld_1=function(){return(kk=b._emscripten_bind_ClosestConvexResultCallback_set_m_hitNormalWorld_1=
|
||||
b.asm.ki).apply(null,arguments)},lk=b._emscripten_bind_ClosestConvexResultCallback_get_m_hitPointWorld_0=function(){return(lk=b._emscripten_bind_ClosestConvexResultCallback_get_m_hitPointWorld_0=b.asm.li).apply(null,arguments)},mk=b._emscripten_bind_ClosestConvexResultCallback_set_m_hitPointWorld_1=function(){return(mk=b._emscripten_bind_ClosestConvexResultCallback_set_m_hitPointWorld_1=b.asm.mi).apply(null,arguments)},nk=b._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterGroup_0=
|
||||
function(){return(nk=b._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterGroup_0=b.asm.ni).apply(null,arguments)},ok=b._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterGroup_1=function(){return(ok=b._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterGroup_1=b.asm.oi).apply(null,arguments)},pk=b._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterMask_0=function(){return(pk=b._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterMask_0=
|
||||
b.asm.pi).apply(null,arguments)},qk=b._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterMask_1=function(){return(qk=b._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterMask_1=b.asm.qi).apply(null,arguments)},rk=b._emscripten_bind_ClosestConvexResultCallback_get_m_closestHitFraction_0=function(){return(rk=b._emscripten_bind_ClosestConvexResultCallback_get_m_closestHitFraction_0=b.asm.ri).apply(null,arguments)},sk=b._emscripten_bind_ClosestConvexResultCallback_set_m_closestHitFraction_1=
|
||||
function(){return(sk=b._emscripten_bind_ClosestConvexResultCallback_set_m_closestHitFraction_1=b.asm.si).apply(null,arguments)},tk=b._emscripten_bind_ClosestConvexResultCallback___destroy___0=function(){return(tk=b._emscripten_bind_ClosestConvexResultCallback___destroy___0=b.asm.ti).apply(null,arguments)},uk=b._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_1=function(){return(uk=b._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_1=b.asm.ui).apply(null,arguments)},
|
||||
vk=b._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_2=function(){return(vk=b._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_2=b.asm.vi).apply(null,arguments)},wk=b._emscripten_bind_btConvexTriangleMeshShape_setLocalScaling_1=function(){return(wk=b._emscripten_bind_btConvexTriangleMeshShape_setLocalScaling_1=b.asm.wi).apply(null,arguments)},xk=b._emscripten_bind_btConvexTriangleMeshShape_getLocalScaling_0=function(){return(xk=b._emscripten_bind_btConvexTriangleMeshShape_getLocalScaling_0=
|
||||
b.asm.xi).apply(null,arguments)},yk=b._emscripten_bind_btConvexTriangleMeshShape_calculateLocalInertia_2=function(){return(yk=b._emscripten_bind_btConvexTriangleMeshShape_calculateLocalInertia_2=b.asm.yi).apply(null,arguments)},zk=b._emscripten_bind_btConvexTriangleMeshShape_setMargin_1=function(){return(zk=b._emscripten_bind_btConvexTriangleMeshShape_setMargin_1=b.asm.zi).apply(null,arguments)},Ak=b._emscripten_bind_btConvexTriangleMeshShape_getMargin_0=function(){return(Ak=b._emscripten_bind_btConvexTriangleMeshShape_getMargin_0=
|
||||
b.asm.Ai).apply(null,arguments)},Bk=b._emscripten_bind_btConvexTriangleMeshShape___destroy___0=function(){return(Bk=b._emscripten_bind_btConvexTriangleMeshShape___destroy___0=b.asm.Bi).apply(null,arguments)},Ck=b._emscripten_bind_btBoxShape_btBoxShape_1=function(){return(Ck=b._emscripten_bind_btBoxShape_btBoxShape_1=b.asm.Ci).apply(null,arguments)},Dk=b._emscripten_bind_btBoxShape_setMargin_1=function(){return(Dk=b._emscripten_bind_btBoxShape_setMargin_1=b.asm.Di).apply(null,arguments)},Ek=b._emscripten_bind_btBoxShape_getMargin_0=
|
||||
function(){return(Ek=b._emscripten_bind_btBoxShape_getMargin_0=b.asm.Ei).apply(null,arguments)},Fk=b._emscripten_bind_btBoxShape_setLocalScaling_1=function(){return(Fk=b._emscripten_bind_btBoxShape_setLocalScaling_1=b.asm.Fi).apply(null,arguments)},Gk=b._emscripten_bind_btBoxShape_getLocalScaling_0=function(){return(Gk=b._emscripten_bind_btBoxShape_getLocalScaling_0=b.asm.Gi).apply(null,arguments)},Hk=b._emscripten_bind_btBoxShape_calculateLocalInertia_2=function(){return(Hk=b._emscripten_bind_btBoxShape_calculateLocalInertia_2=
|
||||
b.asm.Hi).apply(null,arguments)},Ik=b._emscripten_bind_btBoxShape___destroy___0=function(){return(Ik=b._emscripten_bind_btBoxShape___destroy___0=b.asm.Ii).apply(null,arguments)},Jk=b._emscripten_bind_btCapsuleShapeX_btCapsuleShapeX_2=function(){return(Jk=b._emscripten_bind_btCapsuleShapeX_btCapsuleShapeX_2=b.asm.Ji).apply(null,arguments)},Kk=b._emscripten_bind_btCapsuleShapeX_setMargin_1=function(){return(Kk=b._emscripten_bind_btCapsuleShapeX_setMargin_1=b.asm.Ki).apply(null,arguments)},Lk=b._emscripten_bind_btCapsuleShapeX_getMargin_0=
|
||||
function(){return(Lk=b._emscripten_bind_btCapsuleShapeX_getMargin_0=b.asm.Li).apply(null,arguments)},Mk=b._emscripten_bind_btCapsuleShapeX_getUpAxis_0=function(){return(Mk=b._emscripten_bind_btCapsuleShapeX_getUpAxis_0=b.asm.Mi).apply(null,arguments)},Nk=b._emscripten_bind_btCapsuleShapeX_getRadius_0=function(){return(Nk=b._emscripten_bind_btCapsuleShapeX_getRadius_0=b.asm.Ni).apply(null,arguments)},Ok=b._emscripten_bind_btCapsuleShapeX_getHalfHeight_0=function(){return(Ok=b._emscripten_bind_btCapsuleShapeX_getHalfHeight_0=
|
||||
b.asm.Oi).apply(null,arguments)},Pk=b._emscripten_bind_btCapsuleShapeX_setLocalScaling_1=function(){return(Pk=b._emscripten_bind_btCapsuleShapeX_setLocalScaling_1=b.asm.Pi).apply(null,arguments)},Qk=b._emscripten_bind_btCapsuleShapeX_getLocalScaling_0=function(){return(Qk=b._emscripten_bind_btCapsuleShapeX_getLocalScaling_0=b.asm.Qi).apply(null,arguments)},Rk=b._emscripten_bind_btCapsuleShapeX_calculateLocalInertia_2=function(){return(Rk=b._emscripten_bind_btCapsuleShapeX_calculateLocalInertia_2=
|
||||
b.asm.Ri).apply(null,arguments)},Sk=b._emscripten_bind_btCapsuleShapeX___destroy___0=function(){return(Sk=b._emscripten_bind_btCapsuleShapeX___destroy___0=b.asm.Si).apply(null,arguments)},Tk=b._emscripten_bind_btCapsuleShapeZ_btCapsuleShapeZ_2=function(){return(Tk=b._emscripten_bind_btCapsuleShapeZ_btCapsuleShapeZ_2=b.asm.Ti).apply(null,arguments)},Uk=b._emscripten_bind_btCapsuleShapeZ_setMargin_1=function(){return(Uk=b._emscripten_bind_btCapsuleShapeZ_setMargin_1=b.asm.Ui).apply(null,arguments)},
|
||||
Vk=b._emscripten_bind_btCapsuleShapeZ_getMargin_0=function(){return(Vk=b._emscripten_bind_btCapsuleShapeZ_getMargin_0=b.asm.Vi).apply(null,arguments)},Wk=b._emscripten_bind_btCapsuleShapeZ_getUpAxis_0=function(){return(Wk=b._emscripten_bind_btCapsuleShapeZ_getUpAxis_0=b.asm.Wi).apply(null,arguments)},Xk=b._emscripten_bind_btCapsuleShapeZ_getRadius_0=function(){return(Xk=b._emscripten_bind_btCapsuleShapeZ_getRadius_0=b.asm.Xi).apply(null,arguments)},Yk=b._emscripten_bind_btCapsuleShapeZ_getHalfHeight_0=
|
||||
function(){return(Yk=b._emscripten_bind_btCapsuleShapeZ_getHalfHeight_0=b.asm.Yi).apply(null,arguments)},Zk=b._emscripten_bind_btCapsuleShapeZ_setLocalScaling_1=function(){return(Zk=b._emscripten_bind_btCapsuleShapeZ_setLocalScaling_1=b.asm.Zi).apply(null,arguments)},$k=b._emscripten_bind_btCapsuleShapeZ_getLocalScaling_0=function(){return($k=b._emscripten_bind_btCapsuleShapeZ_getLocalScaling_0=b.asm._i).apply(null,arguments)},al=b._emscripten_bind_btCapsuleShapeZ_calculateLocalInertia_2=function(){return(al=
|
||||
b._emscripten_bind_btCapsuleShapeZ_calculateLocalInertia_2=b.asm.$i).apply(null,arguments)},bl=b._emscripten_bind_btCapsuleShapeZ___destroy___0=function(){return(bl=b._emscripten_bind_btCapsuleShapeZ___destroy___0=b.asm.aj).apply(null,arguments)},cl=b._emscripten_bind_btCylinderShapeX_btCylinderShapeX_1=function(){return(cl=b._emscripten_bind_btCylinderShapeX_btCylinderShapeX_1=b.asm.bj).apply(null,arguments)},dl=b._emscripten_bind_btCylinderShapeX_setMargin_1=function(){return(dl=b._emscripten_bind_btCylinderShapeX_setMargin_1=
|
||||
b.asm.cj).apply(null,arguments)},el=b._emscripten_bind_btCylinderShapeX_getMargin_0=function(){return(el=b._emscripten_bind_btCylinderShapeX_getMargin_0=b.asm.dj).apply(null,arguments)},fl=b._emscripten_bind_btCylinderShapeX_setLocalScaling_1=function(){return(fl=b._emscripten_bind_btCylinderShapeX_setLocalScaling_1=b.asm.ej).apply(null,arguments)},gl=b._emscripten_bind_btCylinderShapeX_getLocalScaling_0=function(){return(gl=b._emscripten_bind_btCylinderShapeX_getLocalScaling_0=b.asm.fj).apply(null,
|
||||
arguments)},hl=b._emscripten_bind_btCylinderShapeX_calculateLocalInertia_2=function(){return(hl=b._emscripten_bind_btCylinderShapeX_calculateLocalInertia_2=b.asm.gj).apply(null,arguments)},il=b._emscripten_bind_btCylinderShapeX___destroy___0=function(){return(il=b._emscripten_bind_btCylinderShapeX___destroy___0=b.asm.hj).apply(null,arguments)},jl=b._emscripten_bind_btCylinderShapeZ_btCylinderShapeZ_1=function(){return(jl=b._emscripten_bind_btCylinderShapeZ_btCylinderShapeZ_1=b.asm.ij).apply(null,
|
||||
arguments)},kl=b._emscripten_bind_btCylinderShapeZ_setMargin_1=function(){return(kl=b._emscripten_bind_btCylinderShapeZ_setMargin_1=b.asm.jj).apply(null,arguments)},ll=b._emscripten_bind_btCylinderShapeZ_getMargin_0=function(){return(ll=b._emscripten_bind_btCylinderShapeZ_getMargin_0=b.asm.kj).apply(null,arguments)},ml=b._emscripten_bind_btCylinderShapeZ_setLocalScaling_1=function(){return(ml=b._emscripten_bind_btCylinderShapeZ_setLocalScaling_1=b.asm.lj).apply(null,arguments)},nl=b._emscripten_bind_btCylinderShapeZ_getLocalScaling_0=
|
||||
function(){return(nl=b._emscripten_bind_btCylinderShapeZ_getLocalScaling_0=b.asm.mj).apply(null,arguments)},ol=b._emscripten_bind_btCylinderShapeZ_calculateLocalInertia_2=function(){return(ol=b._emscripten_bind_btCylinderShapeZ_calculateLocalInertia_2=b.asm.nj).apply(null,arguments)},pl=b._emscripten_bind_btCylinderShapeZ___destroy___0=function(){return(pl=b._emscripten_bind_btCylinderShapeZ___destroy___0=b.asm.oj).apply(null,arguments)},ql=b._emscripten_bind_btSphereShape_btSphereShape_1=function(){return(ql=
|
||||
b._emscripten_bind_btSphereShape_btSphereShape_1=b.asm.pj).apply(null,arguments)},rl=b._emscripten_bind_btSphereShape_setMargin_1=function(){return(rl=b._emscripten_bind_btSphereShape_setMargin_1=b.asm.qj).apply(null,arguments)},sl=b._emscripten_bind_btSphereShape_getMargin_0=function(){return(sl=b._emscripten_bind_btSphereShape_getMargin_0=b.asm.rj).apply(null,arguments)},tl=b._emscripten_bind_btSphereShape_setLocalScaling_1=function(){return(tl=b._emscripten_bind_btSphereShape_setLocalScaling_1=
|
||||
b.asm.sj).apply(null,arguments)},ul=b._emscripten_bind_btSphereShape_getLocalScaling_0=function(){return(ul=b._emscripten_bind_btSphereShape_getLocalScaling_0=b.asm.tj).apply(null,arguments)},vl=b._emscripten_bind_btSphereShape_calculateLocalInertia_2=function(){return(vl=b._emscripten_bind_btSphereShape_calculateLocalInertia_2=b.asm.uj).apply(null,arguments)},wl=b._emscripten_bind_btSphereShape___destroy___0=function(){return(wl=b._emscripten_bind_btSphereShape___destroy___0=b.asm.vj).apply(null,
|
||||
arguments)},xl=b._emscripten_bind_btMultiSphereShape_btMultiSphereShape_3=function(){return(xl=b._emscripten_bind_btMultiSphereShape_btMultiSphereShape_3=b.asm.wj).apply(null,arguments)},yl=b._emscripten_bind_btMultiSphereShape_setLocalScaling_1=function(){return(yl=b._emscripten_bind_btMultiSphereShape_setLocalScaling_1=b.asm.xj).apply(null,arguments)},zl=b._emscripten_bind_btMultiSphereShape_getLocalScaling_0=function(){return(zl=b._emscripten_bind_btMultiSphereShape_getLocalScaling_0=b.asm.yj).apply(null,
|
||||
arguments)},Al=b._emscripten_bind_btMultiSphereShape_calculateLocalInertia_2=function(){return(Al=b._emscripten_bind_btMultiSphereShape_calculateLocalInertia_2=b.asm.zj).apply(null,arguments)},Bl=b._emscripten_bind_btMultiSphereShape___destroy___0=function(){return(Bl=b._emscripten_bind_btMultiSphereShape___destroy___0=b.asm.Aj).apply(null,arguments)},Cl=b._emscripten_bind_btConeShapeX_btConeShapeX_2=function(){return(Cl=b._emscripten_bind_btConeShapeX_btConeShapeX_2=b.asm.Bj).apply(null,arguments)},
|
||||
Dl=b._emscripten_bind_btConeShapeX_setLocalScaling_1=function(){return(Dl=b._emscripten_bind_btConeShapeX_setLocalScaling_1=b.asm.Cj).apply(null,arguments)},El=b._emscripten_bind_btConeShapeX_getLocalScaling_0=function(){return(El=b._emscripten_bind_btConeShapeX_getLocalScaling_0=b.asm.Dj).apply(null,arguments)},Fl=b._emscripten_bind_btConeShapeX_calculateLocalInertia_2=function(){return(Fl=b._emscripten_bind_btConeShapeX_calculateLocalInertia_2=b.asm.Ej).apply(null,arguments)},Gl=b._emscripten_bind_btConeShapeX___destroy___0=
|
||||
function(){return(Gl=b._emscripten_bind_btConeShapeX___destroy___0=b.asm.Fj).apply(null,arguments)},Hl=b._emscripten_bind_btConeShapeZ_btConeShapeZ_2=function(){return(Hl=b._emscripten_bind_btConeShapeZ_btConeShapeZ_2=b.asm.Gj).apply(null,arguments)},Il=b._emscripten_bind_btConeShapeZ_setLocalScaling_1=function(){return(Il=b._emscripten_bind_btConeShapeZ_setLocalScaling_1=b.asm.Hj).apply(null,arguments)},Jl=b._emscripten_bind_btConeShapeZ_getLocalScaling_0=function(){return(Jl=b._emscripten_bind_btConeShapeZ_getLocalScaling_0=
|
||||
b.asm.Ij).apply(null,arguments)},Kl=b._emscripten_bind_btConeShapeZ_calculateLocalInertia_2=function(){return(Kl=b._emscripten_bind_btConeShapeZ_calculateLocalInertia_2=b.asm.Jj).apply(null,arguments)},Ll=b._emscripten_bind_btConeShapeZ___destroy___0=function(){return(Ll=b._emscripten_bind_btConeShapeZ___destroy___0=b.asm.Kj).apply(null,arguments)},Ml=b._emscripten_bind_btIntArray_size_0=function(){return(Ml=b._emscripten_bind_btIntArray_size_0=b.asm.Lj).apply(null,arguments)},Nl=b._emscripten_bind_btIntArray_at_1=
|
||||
function(){return(Nl=b._emscripten_bind_btIntArray_at_1=b.asm.Mj).apply(null,arguments)},Ol=b._emscripten_bind_btIntArray___destroy___0=function(){return(Ol=b._emscripten_bind_btIntArray___destroy___0=b.asm.Nj).apply(null,arguments)},Pl=b._emscripten_bind_btFace_get_m_indices_0=function(){return(Pl=b._emscripten_bind_btFace_get_m_indices_0=b.asm.Oj).apply(null,arguments)},Ql=b._emscripten_bind_btFace_set_m_indices_1=function(){return(Ql=b._emscripten_bind_btFace_set_m_indices_1=b.asm.Pj).apply(null,
|
||||
arguments)},Rl=b._emscripten_bind_btFace_get_m_plane_1=function(){return(Rl=b._emscripten_bind_btFace_get_m_plane_1=b.asm.Qj).apply(null,arguments)},Sl=b._emscripten_bind_btFace_set_m_plane_2=function(){return(Sl=b._emscripten_bind_btFace_set_m_plane_2=b.asm.Rj).apply(null,arguments)},Tl=b._emscripten_bind_btFace___destroy___0=function(){return(Tl=b._emscripten_bind_btFace___destroy___0=b.asm.Sj).apply(null,arguments)},Ul=b._emscripten_bind_btVector3Array_size_0=function(){return(Ul=b._emscripten_bind_btVector3Array_size_0=
|
||||
b.asm.Tj).apply(null,arguments)},Vl=b._emscripten_bind_btVector3Array_at_1=function(){return(Vl=b._emscripten_bind_btVector3Array_at_1=b.asm.Uj).apply(null,arguments)},Wl=b._emscripten_bind_btVector3Array___destroy___0=function(){return(Wl=b._emscripten_bind_btVector3Array___destroy___0=b.asm.Vj).apply(null,arguments)},Xl=b._emscripten_bind_btFaceArray_size_0=function(){return(Xl=b._emscripten_bind_btFaceArray_size_0=b.asm.Wj).apply(null,arguments)},Yl=b._emscripten_bind_btFaceArray_at_1=function(){return(Yl=
|
||||
b._emscripten_bind_btFaceArray_at_1=b.asm.Xj).apply(null,arguments)},Zl=b._emscripten_bind_btFaceArray___destroy___0=function(){return(Zl=b._emscripten_bind_btFaceArray___destroy___0=b.asm.Yj).apply(null,arguments)},$l=b._emscripten_bind_btConvexPolyhedron_get_m_vertices_0=function(){return($l=b._emscripten_bind_btConvexPolyhedron_get_m_vertices_0=b.asm.Zj).apply(null,arguments)},am=b._emscripten_bind_btConvexPolyhedron_set_m_vertices_1=function(){return(am=b._emscripten_bind_btConvexPolyhedron_set_m_vertices_1=
|
||||
b.asm._j).apply(null,arguments)},bm=b._emscripten_bind_btConvexPolyhedron_get_m_faces_0=function(){return(bm=b._emscripten_bind_btConvexPolyhedron_get_m_faces_0=b.asm.$j).apply(null,arguments)},cm=b._emscripten_bind_btConvexPolyhedron_set_m_faces_1=function(){return(cm=b._emscripten_bind_btConvexPolyhedron_set_m_faces_1=b.asm.ak).apply(null,arguments)},dm=b._emscripten_bind_btConvexPolyhedron___destroy___0=function(){return(dm=b._emscripten_bind_btConvexPolyhedron___destroy___0=b.asm.bk).apply(null,
|
||||
arguments)},em=b._emscripten_bind_btConvexHullShape_btConvexHullShape_0=function(){return(em=b._emscripten_bind_btConvexHullShape_btConvexHullShape_0=b.asm.ck).apply(null,arguments)},fm=b._emscripten_bind_btConvexHullShape_btConvexHullShape_1=function(){return(fm=b._emscripten_bind_btConvexHullShape_btConvexHullShape_1=b.asm.dk).apply(null,arguments)},gm=b._emscripten_bind_btConvexHullShape_btConvexHullShape_2=function(){return(gm=b._emscripten_bind_btConvexHullShape_btConvexHullShape_2=b.asm.ek).apply(null,
|
||||
arguments)},hm=b._emscripten_bind_btConvexHullShape_addPoint_1=function(){return(hm=b._emscripten_bind_btConvexHullShape_addPoint_1=b.asm.fk).apply(null,arguments)},im=b._emscripten_bind_btConvexHullShape_addPoint_2=function(){return(im=b._emscripten_bind_btConvexHullShape_addPoint_2=b.asm.gk).apply(null,arguments)},jm=b._emscripten_bind_btConvexHullShape_setMargin_1=function(){return(jm=b._emscripten_bind_btConvexHullShape_setMargin_1=b.asm.hk).apply(null,arguments)},km=b._emscripten_bind_btConvexHullShape_getMargin_0=
|
||||
function(){return(km=b._emscripten_bind_btConvexHullShape_getMargin_0=b.asm.ik).apply(null,arguments)},lm=b._emscripten_bind_btConvexHullShape_getNumVertices_0=function(){return(lm=b._emscripten_bind_btConvexHullShape_getNumVertices_0=b.asm.jk).apply(null,arguments)},mm=b._emscripten_bind_btConvexHullShape_initializePolyhedralFeatures_1=function(){return(mm=b._emscripten_bind_btConvexHullShape_initializePolyhedralFeatures_1=b.asm.kk).apply(null,arguments)},nm=b._emscripten_bind_btConvexHullShape_recalcLocalAabb_0=
|
||||
function(){return(nm=b._emscripten_bind_btConvexHullShape_recalcLocalAabb_0=b.asm.lk).apply(null,arguments)},om=b._emscripten_bind_btConvexHullShape_getConvexPolyhedron_0=function(){return(om=b._emscripten_bind_btConvexHullShape_getConvexPolyhedron_0=b.asm.mk).apply(null,arguments)},pm=b._emscripten_bind_btConvexHullShape_setLocalScaling_1=function(){return(pm=b._emscripten_bind_btConvexHullShape_setLocalScaling_1=b.asm.nk).apply(null,arguments)},qm=b._emscripten_bind_btConvexHullShape_getLocalScaling_0=
|
||||
function(){return(qm=b._emscripten_bind_btConvexHullShape_getLocalScaling_0=b.asm.ok).apply(null,arguments)},rm=b._emscripten_bind_btConvexHullShape_calculateLocalInertia_2=function(){return(rm=b._emscripten_bind_btConvexHullShape_calculateLocalInertia_2=b.asm.pk).apply(null,arguments)},sm=b._emscripten_bind_btConvexHullShape___destroy___0=function(){return(sm=b._emscripten_bind_btConvexHullShape___destroy___0=b.asm.qk).apply(null,arguments)},tm=b._emscripten_bind_btShapeHull_btShapeHull_1=function(){return(tm=
|
||||
b._emscripten_bind_btShapeHull_btShapeHull_1=b.asm.rk).apply(null,arguments)},um=b._emscripten_bind_btShapeHull_buildHull_1=function(){return(um=b._emscripten_bind_btShapeHull_buildHull_1=b.asm.sk).apply(null,arguments)},wm=b._emscripten_bind_btShapeHull_numVertices_0=function(){return(wm=b._emscripten_bind_btShapeHull_numVertices_0=b.asm.tk).apply(null,arguments)},xm=b._emscripten_bind_btShapeHull_getVertexPointer_0=function(){return(xm=b._emscripten_bind_btShapeHull_getVertexPointer_0=b.asm.uk).apply(null,
|
||||
arguments)},ym=b._emscripten_bind_btShapeHull___destroy___0=function(){return(ym=b._emscripten_bind_btShapeHull___destroy___0=b.asm.vk).apply(null,arguments)},zm=b._emscripten_bind_btCompoundShape_btCompoundShape_0=function(){return(zm=b._emscripten_bind_btCompoundShape_btCompoundShape_0=b.asm.wk).apply(null,arguments)},Am=b._emscripten_bind_btCompoundShape_btCompoundShape_1=function(){return(Am=b._emscripten_bind_btCompoundShape_btCompoundShape_1=b.asm.xk).apply(null,arguments)},Bm=b._emscripten_bind_btCompoundShape_addChildShape_2=
|
||||
function(){return(Bm=b._emscripten_bind_btCompoundShape_addChildShape_2=b.asm.yk).apply(null,arguments)},Cm=b._emscripten_bind_btCompoundShape_removeChildShape_1=function(){return(Cm=b._emscripten_bind_btCompoundShape_removeChildShape_1=b.asm.zk).apply(null,arguments)},Dm=b._emscripten_bind_btCompoundShape_removeChildShapeByIndex_1=function(){return(Dm=b._emscripten_bind_btCompoundShape_removeChildShapeByIndex_1=b.asm.Ak).apply(null,arguments)},Em=b._emscripten_bind_btCompoundShape_getNumChildShapes_0=
|
||||
function(){return(Em=b._emscripten_bind_btCompoundShape_getNumChildShapes_0=b.asm.Bk).apply(null,arguments)},Fm=b._emscripten_bind_btCompoundShape_getChildShape_1=function(){return(Fm=b._emscripten_bind_btCompoundShape_getChildShape_1=b.asm.Ck).apply(null,arguments)},Gm=b._emscripten_bind_btCompoundShape_updateChildTransform_2=function(){return(Gm=b._emscripten_bind_btCompoundShape_updateChildTransform_2=b.asm.Dk).apply(null,arguments)},Hm=b._emscripten_bind_btCompoundShape_updateChildTransform_3=
|
||||
function(){return(Hm=b._emscripten_bind_btCompoundShape_updateChildTransform_3=b.asm.Ek).apply(null,arguments)},Im=b._emscripten_bind_btCompoundShape_setMargin_1=function(){return(Im=b._emscripten_bind_btCompoundShape_setMargin_1=b.asm.Fk).apply(null,arguments)},Jm=b._emscripten_bind_btCompoundShape_getMargin_0=function(){return(Jm=b._emscripten_bind_btCompoundShape_getMargin_0=b.asm.Gk).apply(null,arguments)},Km=b._emscripten_bind_btCompoundShape_setLocalScaling_1=function(){return(Km=b._emscripten_bind_btCompoundShape_setLocalScaling_1=
|
||||
b.asm.Hk).apply(null,arguments)},Lm=b._emscripten_bind_btCompoundShape_getLocalScaling_0=function(){return(Lm=b._emscripten_bind_btCompoundShape_getLocalScaling_0=b.asm.Ik).apply(null,arguments)},Mm=b._emscripten_bind_btCompoundShape_calculateLocalInertia_2=function(){return(Mm=b._emscripten_bind_btCompoundShape_calculateLocalInertia_2=b.asm.Jk).apply(null,arguments)},Nm=b._emscripten_bind_btCompoundShape___destroy___0=function(){return(Nm=b._emscripten_bind_btCompoundShape___destroy___0=b.asm.Kk).apply(null,
|
||||
arguments)},Om=b._emscripten_bind_btIndexedMesh_get_m_numTriangles_0=function(){return(Om=b._emscripten_bind_btIndexedMesh_get_m_numTriangles_0=b.asm.Lk).apply(null,arguments)},Pm=b._emscripten_bind_btIndexedMesh_set_m_numTriangles_1=function(){return(Pm=b._emscripten_bind_btIndexedMesh_set_m_numTriangles_1=b.asm.Mk).apply(null,arguments)},Qm=b._emscripten_bind_btIndexedMesh___destroy___0=function(){return(Qm=b._emscripten_bind_btIndexedMesh___destroy___0=b.asm.Nk).apply(null,arguments)},Rm=b._emscripten_bind_btIndexedMeshArray_size_0=
|
||||
function(){return(Rm=b._emscripten_bind_btIndexedMeshArray_size_0=b.asm.Ok).apply(null,arguments)},Sm=b._emscripten_bind_btIndexedMeshArray_at_1=function(){return(Sm=b._emscripten_bind_btIndexedMeshArray_at_1=b.asm.Pk).apply(null,arguments)},Tm=b._emscripten_bind_btIndexedMeshArray___destroy___0=function(){return(Tm=b._emscripten_bind_btIndexedMeshArray___destroy___0=b.asm.Qk).apply(null,arguments)},Um=b._emscripten_bind_btTriangleMesh_btTriangleMesh_0=function(){return(Um=b._emscripten_bind_btTriangleMesh_btTriangleMesh_0=
|
||||
b.asm.Rk).apply(null,arguments)},Vm=b._emscripten_bind_btTriangleMesh_btTriangleMesh_1=function(){return(Vm=b._emscripten_bind_btTriangleMesh_btTriangleMesh_1=b.asm.Sk).apply(null,arguments)},Wm=b._emscripten_bind_btTriangleMesh_btTriangleMesh_2=function(){return(Wm=b._emscripten_bind_btTriangleMesh_btTriangleMesh_2=b.asm.Tk).apply(null,arguments)},Xm=b._emscripten_bind_btTriangleMesh_addTriangle_3=function(){return(Xm=b._emscripten_bind_btTriangleMesh_addTriangle_3=b.asm.Uk).apply(null,arguments)},
|
||||
Ym=b._emscripten_bind_btTriangleMesh_addTriangle_4=function(){return(Ym=b._emscripten_bind_btTriangleMesh_addTriangle_4=b.asm.Vk).apply(null,arguments)},Zm=b._emscripten_bind_btTriangleMesh_findOrAddVertex_2=function(){return(Zm=b._emscripten_bind_btTriangleMesh_findOrAddVertex_2=b.asm.Wk).apply(null,arguments)},$m=b._emscripten_bind_btTriangleMesh_addIndex_1=function(){return($m=b._emscripten_bind_btTriangleMesh_addIndex_1=b.asm.Xk).apply(null,arguments)},an=b._emscripten_bind_btTriangleMesh_getIndexedMeshArray_0=
|
||||
function(){return(an=b._emscripten_bind_btTriangleMesh_getIndexedMeshArray_0=b.asm.Yk).apply(null,arguments)},bn=b._emscripten_bind_btTriangleMesh_setScaling_1=function(){return(bn=b._emscripten_bind_btTriangleMesh_setScaling_1=b.asm.Zk).apply(null,arguments)},cn=b._emscripten_bind_btTriangleMesh___destroy___0=function(){return(cn=b._emscripten_bind_btTriangleMesh___destroy___0=b.asm._k).apply(null,arguments)},dn=b._emscripten_bind_btEmptyShape_btEmptyShape_0=function(){return(dn=b._emscripten_bind_btEmptyShape_btEmptyShape_0=
|
||||
b.asm.$k).apply(null,arguments)},en=b._emscripten_bind_btEmptyShape_setLocalScaling_1=function(){return(en=b._emscripten_bind_btEmptyShape_setLocalScaling_1=b.asm.al).apply(null,arguments)},fn=b._emscripten_bind_btEmptyShape_getLocalScaling_0=function(){return(fn=b._emscripten_bind_btEmptyShape_getLocalScaling_0=b.asm.bl).apply(null,arguments)},gn=b._emscripten_bind_btEmptyShape_calculateLocalInertia_2=function(){return(gn=b._emscripten_bind_btEmptyShape_calculateLocalInertia_2=b.asm.cl).apply(null,
|
||||
arguments)},hn=b._emscripten_bind_btEmptyShape___destroy___0=function(){return(hn=b._emscripten_bind_btEmptyShape___destroy___0=b.asm.dl).apply(null,arguments)},jn=b._emscripten_bind_btStaticPlaneShape_btStaticPlaneShape_2=function(){return(jn=b._emscripten_bind_btStaticPlaneShape_btStaticPlaneShape_2=b.asm.el).apply(null,arguments)},kn=b._emscripten_bind_btStaticPlaneShape_setLocalScaling_1=function(){return(kn=b._emscripten_bind_btStaticPlaneShape_setLocalScaling_1=b.asm.fl).apply(null,arguments)},
|
||||
ln=b._emscripten_bind_btStaticPlaneShape_getLocalScaling_0=function(){return(ln=b._emscripten_bind_btStaticPlaneShape_getLocalScaling_0=b.asm.gl).apply(null,arguments)},mn=b._emscripten_bind_btStaticPlaneShape_calculateLocalInertia_2=function(){return(mn=b._emscripten_bind_btStaticPlaneShape_calculateLocalInertia_2=b.asm.hl).apply(null,arguments)},nn=b._emscripten_bind_btStaticPlaneShape___destroy___0=function(){return(nn=b._emscripten_bind_btStaticPlaneShape___destroy___0=b.asm.il).apply(null,arguments)},
|
||||
on=b._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_2=function(){return(on=b._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_2=b.asm.jl).apply(null,arguments)},pn=b._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_3=function(){return(pn=b._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_3=b.asm.kl).apply(null,arguments)},qn=b._emscripten_bind_btBvhTriangleMeshShape_setLocalScaling_1=function(){return(qn=b._emscripten_bind_btBvhTriangleMeshShape_setLocalScaling_1=
|
||||
b.asm.ll).apply(null,arguments)},rn=b._emscripten_bind_btBvhTriangleMeshShape_getLocalScaling_0=function(){return(rn=b._emscripten_bind_btBvhTriangleMeshShape_getLocalScaling_0=b.asm.ml).apply(null,arguments)},sn=b._emscripten_bind_btBvhTriangleMeshShape_calculateLocalInertia_2=function(){return(sn=b._emscripten_bind_btBvhTriangleMeshShape_calculateLocalInertia_2=b.asm.nl).apply(null,arguments)},tn=b._emscripten_bind_btBvhTriangleMeshShape___destroy___0=function(){return(tn=b._emscripten_bind_btBvhTriangleMeshShape___destroy___0=
|
||||
b.asm.ol).apply(null,arguments)},un=b._emscripten_bind_btHeightfieldTerrainShape_btHeightfieldTerrainShape_9=function(){return(un=b._emscripten_bind_btHeightfieldTerrainShape_btHeightfieldTerrainShape_9=b.asm.pl).apply(null,arguments)},vn=b._emscripten_bind_btHeightfieldTerrainShape_setMargin_1=function(){return(vn=b._emscripten_bind_btHeightfieldTerrainShape_setMargin_1=b.asm.ql).apply(null,arguments)},wn=b._emscripten_bind_btHeightfieldTerrainShape_getMargin_0=function(){return(wn=b._emscripten_bind_btHeightfieldTerrainShape_getMargin_0=
|
||||
b.asm.rl).apply(null,arguments)},xn=b._emscripten_bind_btHeightfieldTerrainShape_setLocalScaling_1=function(){return(xn=b._emscripten_bind_btHeightfieldTerrainShape_setLocalScaling_1=b.asm.sl).apply(null,arguments)},yn=b._emscripten_bind_btHeightfieldTerrainShape_getLocalScaling_0=function(){return(yn=b._emscripten_bind_btHeightfieldTerrainShape_getLocalScaling_0=b.asm.tl).apply(null,arguments)},zn=b._emscripten_bind_btHeightfieldTerrainShape_calculateLocalInertia_2=function(){return(zn=b._emscripten_bind_btHeightfieldTerrainShape_calculateLocalInertia_2=
|
||||
b.asm.ul).apply(null,arguments)},An=b._emscripten_bind_btHeightfieldTerrainShape___destroy___0=function(){return(An=b._emscripten_bind_btHeightfieldTerrainShape___destroy___0=b.asm.vl).apply(null,arguments)},Bn=b._emscripten_bind_btAABB_btAABB_4=function(){return(Bn=b._emscripten_bind_btAABB_btAABB_4=b.asm.wl).apply(null,arguments)},Cn=b._emscripten_bind_btAABB_invalidate_0=function(){return(Cn=b._emscripten_bind_btAABB_invalidate_0=b.asm.xl).apply(null,arguments)},Dn=b._emscripten_bind_btAABB_increment_margin_1=
|
||||
function(){return(Dn=b._emscripten_bind_btAABB_increment_margin_1=b.asm.yl).apply(null,arguments)},En=b._emscripten_bind_btAABB_copy_with_margin_2=function(){return(En=b._emscripten_bind_btAABB_copy_with_margin_2=b.asm.zl).apply(null,arguments)},Fn=b._emscripten_bind_btAABB___destroy___0=function(){return(Fn=b._emscripten_bind_btAABB___destroy___0=b.asm.Al).apply(null,arguments)},Gn=b._emscripten_bind_btPrimitiveTriangle_btPrimitiveTriangle_0=function(){return(Gn=b._emscripten_bind_btPrimitiveTriangle_btPrimitiveTriangle_0=
|
||||
b.asm.Bl).apply(null,arguments)},Hn=b._emscripten_bind_btPrimitiveTriangle___destroy___0=function(){return(Hn=b._emscripten_bind_btPrimitiveTriangle___destroy___0=b.asm.Cl).apply(null,arguments)},In=b._emscripten_bind_btTriangleShapeEx_btTriangleShapeEx_3=function(){return(In=b._emscripten_bind_btTriangleShapeEx_btTriangleShapeEx_3=b.asm.Dl).apply(null,arguments)},Jn=b._emscripten_bind_btTriangleShapeEx_getAabb_3=function(){return(Jn=b._emscripten_bind_btTriangleShapeEx_getAabb_3=b.asm.El).apply(null,
|
||||
arguments)},Kn=b._emscripten_bind_btTriangleShapeEx_applyTransform_1=function(){return(Kn=b._emscripten_bind_btTriangleShapeEx_applyTransform_1=b.asm.Fl).apply(null,arguments)},Ln=b._emscripten_bind_btTriangleShapeEx_buildTriPlane_1=function(){return(Ln=b._emscripten_bind_btTriangleShapeEx_buildTriPlane_1=b.asm.Gl).apply(null,arguments)},Mn=b._emscripten_bind_btTriangleShapeEx___destroy___0=function(){return(Mn=b._emscripten_bind_btTriangleShapeEx___destroy___0=b.asm.Hl).apply(null,arguments)},Nn=
|
||||
b._emscripten_bind_btTetrahedronShapeEx_btTetrahedronShapeEx_0=function(){return(Nn=b._emscripten_bind_btTetrahedronShapeEx_btTetrahedronShapeEx_0=b.asm.Il).apply(null,arguments)},On=b._emscripten_bind_btTetrahedronShapeEx_setVertices_4=function(){return(On=b._emscripten_bind_btTetrahedronShapeEx_setVertices_4=b.asm.Jl).apply(null,arguments)},Pn=b._emscripten_bind_btTetrahedronShapeEx___destroy___0=function(){return(Pn=b._emscripten_bind_btTetrahedronShapeEx___destroy___0=b.asm.Kl).apply(null,arguments)},
|
||||
Qn=b._emscripten_bind_CompoundPrimitiveManager_get_primitive_count_0=function(){return(Qn=b._emscripten_bind_CompoundPrimitiveManager_get_primitive_count_0=b.asm.Ll).apply(null,arguments)},Rn=b._emscripten_bind_CompoundPrimitiveManager_get_primitive_box_2=function(){return(Rn=b._emscripten_bind_CompoundPrimitiveManager_get_primitive_box_2=b.asm.Ml).apply(null,arguments)},Sn=b._emscripten_bind_CompoundPrimitiveManager_get_primitive_triangle_2=function(){return(Sn=b._emscripten_bind_CompoundPrimitiveManager_get_primitive_triangle_2=
|
||||
b.asm.Nl).apply(null,arguments)},Tn=b._emscripten_bind_CompoundPrimitiveManager_is_trimesh_0=function(){return(Tn=b._emscripten_bind_CompoundPrimitiveManager_is_trimesh_0=b.asm.Ol).apply(null,arguments)},Un=b._emscripten_bind_CompoundPrimitiveManager_get_m_compoundShape_0=function(){return(Un=b._emscripten_bind_CompoundPrimitiveManager_get_m_compoundShape_0=b.asm.Pl).apply(null,arguments)},Vn=b._emscripten_bind_CompoundPrimitiveManager_set_m_compoundShape_1=function(){return(Vn=b._emscripten_bind_CompoundPrimitiveManager_set_m_compoundShape_1=
|
||||
b.asm.Ql).apply(null,arguments)},Wn=b._emscripten_bind_CompoundPrimitiveManager___destroy___0=function(){return(Wn=b._emscripten_bind_CompoundPrimitiveManager___destroy___0=b.asm.Rl).apply(null,arguments)},Xn=b._emscripten_bind_btGImpactCompoundShape_btGImpactCompoundShape_0=function(){return(Xn=b._emscripten_bind_btGImpactCompoundShape_btGImpactCompoundShape_0=b.asm.Sl).apply(null,arguments)},Yn=b._emscripten_bind_btGImpactCompoundShape_btGImpactCompoundShape_1=function(){return(Yn=b._emscripten_bind_btGImpactCompoundShape_btGImpactCompoundShape_1=
|
||||
b.asm.Tl).apply(null,arguments)},Zn=b._emscripten_bind_btGImpactCompoundShape_childrenHasTransform_0=function(){return(Zn=b._emscripten_bind_btGImpactCompoundShape_childrenHasTransform_0=b.asm.Ul).apply(null,arguments)},$n=b._emscripten_bind_btGImpactCompoundShape_getPrimitiveManager_0=function(){return($n=b._emscripten_bind_btGImpactCompoundShape_getPrimitiveManager_0=b.asm.Vl).apply(null,arguments)},ao=b._emscripten_bind_btGImpactCompoundShape_getCompoundPrimitiveManager_0=function(){return(ao=
|
||||
b._emscripten_bind_btGImpactCompoundShape_getCompoundPrimitiveManager_0=b.asm.Wl).apply(null,arguments)},bo=b._emscripten_bind_btGImpactCompoundShape_getNumChildShapes_0=function(){return(bo=b._emscripten_bind_btGImpactCompoundShape_getNumChildShapes_0=b.asm.Xl).apply(null,arguments)},co=b._emscripten_bind_btGImpactCompoundShape_addChildShape_2=function(){return(co=b._emscripten_bind_btGImpactCompoundShape_addChildShape_2=b.asm.Yl).apply(null,arguments)},eo=b._emscripten_bind_btGImpactCompoundShape_getChildShape_1=
|
||||
function(){return(eo=b._emscripten_bind_btGImpactCompoundShape_getChildShape_1=b.asm.Zl).apply(null,arguments)},fo=b._emscripten_bind_btGImpactCompoundShape_getChildAabb_4=function(){return(fo=b._emscripten_bind_btGImpactCompoundShape_getChildAabb_4=b.asm._l).apply(null,arguments)},go=b._emscripten_bind_btGImpactCompoundShape_getChildTransform_1=function(){return(go=b._emscripten_bind_btGImpactCompoundShape_getChildTransform_1=b.asm.$l).apply(null,arguments)},ho=b._emscripten_bind_btGImpactCompoundShape_setChildTransform_2=
|
||||
function(){return(ho=b._emscripten_bind_btGImpactCompoundShape_setChildTransform_2=b.asm.am).apply(null,arguments)},io=b._emscripten_bind_btGImpactCompoundShape_calculateLocalInertia_2=function(){return(io=b._emscripten_bind_btGImpactCompoundShape_calculateLocalInertia_2=b.asm.bm).apply(null,arguments)},jo=b._emscripten_bind_btGImpactCompoundShape_getName_0=function(){return(jo=b._emscripten_bind_btGImpactCompoundShape_getName_0=b.asm.cm).apply(null,arguments)},ko=b._emscripten_bind_btGImpactCompoundShape_getGImpactShapeType_0=
|
||||
function(){return(ko=b._emscripten_bind_btGImpactCompoundShape_getGImpactShapeType_0=b.asm.dm).apply(null,arguments)},lo=b._emscripten_bind_btGImpactCompoundShape_setLocalScaling_1=function(){return(lo=b._emscripten_bind_btGImpactCompoundShape_setLocalScaling_1=b.asm.em).apply(null,arguments)},mo=b._emscripten_bind_btGImpactCompoundShape_getLocalScaling_0=function(){return(mo=b._emscripten_bind_btGImpactCompoundShape_getLocalScaling_0=b.asm.fm).apply(null,arguments)},no=b._emscripten_bind_btGImpactCompoundShape_updateBound_0=
|
||||
function(){return(no=b._emscripten_bind_btGImpactCompoundShape_updateBound_0=b.asm.gm).apply(null,arguments)},oo=b._emscripten_bind_btGImpactCompoundShape_postUpdate_0=function(){return(oo=b._emscripten_bind_btGImpactCompoundShape_postUpdate_0=b.asm.hm).apply(null,arguments)},po=b._emscripten_bind_btGImpactCompoundShape_getShapeType_0=function(){return(po=b._emscripten_bind_btGImpactCompoundShape_getShapeType_0=b.asm.im).apply(null,arguments)},qo=b._emscripten_bind_btGImpactCompoundShape_needsRetrieveTriangles_0=
|
||||
function(){return(qo=b._emscripten_bind_btGImpactCompoundShape_needsRetrieveTriangles_0=b.asm.jm).apply(null,arguments)},ro=b._emscripten_bind_btGImpactCompoundShape_needsRetrieveTetrahedrons_0=function(){return(ro=b._emscripten_bind_btGImpactCompoundShape_needsRetrieveTetrahedrons_0=b.asm.km).apply(null,arguments)},so=b._emscripten_bind_btGImpactCompoundShape_getBulletTriangle_2=function(){return(so=b._emscripten_bind_btGImpactCompoundShape_getBulletTriangle_2=b.asm.lm).apply(null,arguments)},to=
|
||||
b._emscripten_bind_btGImpactCompoundShape_getBulletTetrahedron_2=function(){return(to=b._emscripten_bind_btGImpactCompoundShape_getBulletTetrahedron_2=b.asm.mm).apply(null,arguments)},uo=b._emscripten_bind_btGImpactCompoundShape___destroy___0=function(){return(uo=b._emscripten_bind_btGImpactCompoundShape___destroy___0=b.asm.nm).apply(null,arguments)},vo=b._emscripten_bind_TrimeshPrimitiveManager_TrimeshPrimitiveManager_0=function(){return(vo=b._emscripten_bind_TrimeshPrimitiveManager_TrimeshPrimitiveManager_0=
|
||||
b.asm.om).apply(null,arguments)},wo=b._emscripten_bind_TrimeshPrimitiveManager_TrimeshPrimitiveManager_1=function(){return(wo=b._emscripten_bind_TrimeshPrimitiveManager_TrimeshPrimitiveManager_1=b.asm.pm).apply(null,arguments)},xo=b._emscripten_bind_TrimeshPrimitiveManager_lock_0=function(){return(xo=b._emscripten_bind_TrimeshPrimitiveManager_lock_0=b.asm.qm).apply(null,arguments)},yo=b._emscripten_bind_TrimeshPrimitiveManager_unlock_0=function(){return(yo=b._emscripten_bind_TrimeshPrimitiveManager_unlock_0=
|
||||
b.asm.rm).apply(null,arguments)},zo=b._emscripten_bind_TrimeshPrimitiveManager_is_trimesh_0=function(){return(zo=b._emscripten_bind_TrimeshPrimitiveManager_is_trimesh_0=b.asm.sm).apply(null,arguments)},Ao=b._emscripten_bind_TrimeshPrimitiveManager_get_vertex_count_0=function(){return(Ao=b._emscripten_bind_TrimeshPrimitiveManager_get_vertex_count_0=b.asm.tm).apply(null,arguments)},Bo=b._emscripten_bind_TrimeshPrimitiveManager_get_indices_4=function(){return(Bo=b._emscripten_bind_TrimeshPrimitiveManager_get_indices_4=
|
||||
b.asm.um).apply(null,arguments)},Co=b._emscripten_bind_TrimeshPrimitiveManager_get_vertex_2=function(){return(Co=b._emscripten_bind_TrimeshPrimitiveManager_get_vertex_2=b.asm.vm).apply(null,arguments)},Do=b._emscripten_bind_TrimeshPrimitiveManager_get_bullet_triangle_2=function(){return(Do=b._emscripten_bind_TrimeshPrimitiveManager_get_bullet_triangle_2=b.asm.wm).apply(null,arguments)},Eo=b._emscripten_bind_TrimeshPrimitiveManager_get_m_margin_0=function(){return(Eo=b._emscripten_bind_TrimeshPrimitiveManager_get_m_margin_0=
|
||||
b.asm.xm).apply(null,arguments)},Fo=b._emscripten_bind_TrimeshPrimitiveManager_set_m_margin_1=function(){return(Fo=b._emscripten_bind_TrimeshPrimitiveManager_set_m_margin_1=b.asm.ym).apply(null,arguments)},Go=b._emscripten_bind_TrimeshPrimitiveManager_get_m_meshInterface_0=function(){return(Go=b._emscripten_bind_TrimeshPrimitiveManager_get_m_meshInterface_0=b.asm.zm).apply(null,arguments)},Ho=b._emscripten_bind_TrimeshPrimitiveManager_set_m_meshInterface_1=function(){return(Ho=b._emscripten_bind_TrimeshPrimitiveManager_set_m_meshInterface_1=
|
||||
b.asm.Am).apply(null,arguments)},Io=b._emscripten_bind_TrimeshPrimitiveManager_get_m_part_0=function(){return(Io=b._emscripten_bind_TrimeshPrimitiveManager_get_m_part_0=b.asm.Bm).apply(null,arguments)},Jo=b._emscripten_bind_TrimeshPrimitiveManager_set_m_part_1=function(){return(Jo=b._emscripten_bind_TrimeshPrimitiveManager_set_m_part_1=b.asm.Cm).apply(null,arguments)},Ko=b._emscripten_bind_TrimeshPrimitiveManager_get_m_lock_count_0=function(){return(Ko=b._emscripten_bind_TrimeshPrimitiveManager_get_m_lock_count_0=
|
||||
b.asm.Dm).apply(null,arguments)},Lo=b._emscripten_bind_TrimeshPrimitiveManager_set_m_lock_count_1=function(){return(Lo=b._emscripten_bind_TrimeshPrimitiveManager_set_m_lock_count_1=b.asm.Em).apply(null,arguments)},Mo=b._emscripten_bind_TrimeshPrimitiveManager_get_numverts_0=function(){return(Mo=b._emscripten_bind_TrimeshPrimitiveManager_get_numverts_0=b.asm.Fm).apply(null,arguments)},No=b._emscripten_bind_TrimeshPrimitiveManager_set_numverts_1=function(){return(No=b._emscripten_bind_TrimeshPrimitiveManager_set_numverts_1=
|
||||
b.asm.Gm).apply(null,arguments)},Oo=b._emscripten_bind_TrimeshPrimitiveManager_get_type_0=function(){return(Oo=b._emscripten_bind_TrimeshPrimitiveManager_get_type_0=b.asm.Hm).apply(null,arguments)},Po=b._emscripten_bind_TrimeshPrimitiveManager_set_type_1=function(){return(Po=b._emscripten_bind_TrimeshPrimitiveManager_set_type_1=b.asm.Im).apply(null,arguments)},Qo=b._emscripten_bind_TrimeshPrimitiveManager_get_stride_0=function(){return(Qo=b._emscripten_bind_TrimeshPrimitiveManager_get_stride_0=b.asm.Jm).apply(null,
|
||||
arguments)},Ro=b._emscripten_bind_TrimeshPrimitiveManager_set_stride_1=function(){return(Ro=b._emscripten_bind_TrimeshPrimitiveManager_set_stride_1=b.asm.Km).apply(null,arguments)},So=b._emscripten_bind_TrimeshPrimitiveManager_get_indexstride_0=function(){return(So=b._emscripten_bind_TrimeshPrimitiveManager_get_indexstride_0=b.asm.Lm).apply(null,arguments)},To=b._emscripten_bind_TrimeshPrimitiveManager_set_indexstride_1=function(){return(To=b._emscripten_bind_TrimeshPrimitiveManager_set_indexstride_1=
|
||||
b.asm.Mm).apply(null,arguments)},Uo=b._emscripten_bind_TrimeshPrimitiveManager_get_numfaces_0=function(){return(Uo=b._emscripten_bind_TrimeshPrimitiveManager_get_numfaces_0=b.asm.Nm).apply(null,arguments)},Vo=b._emscripten_bind_TrimeshPrimitiveManager_set_numfaces_1=function(){return(Vo=b._emscripten_bind_TrimeshPrimitiveManager_set_numfaces_1=b.asm.Om).apply(null,arguments)},Wo=b._emscripten_bind_TrimeshPrimitiveManager_get_indicestype_0=function(){return(Wo=b._emscripten_bind_TrimeshPrimitiveManager_get_indicestype_0=
|
||||
b.asm.Pm).apply(null,arguments)},Xo=b._emscripten_bind_TrimeshPrimitiveManager_set_indicestype_1=function(){return(Xo=b._emscripten_bind_TrimeshPrimitiveManager_set_indicestype_1=b.asm.Qm).apply(null,arguments)},Yo=b._emscripten_bind_TrimeshPrimitiveManager___destroy___0=function(){return(Yo=b._emscripten_bind_TrimeshPrimitiveManager___destroy___0=b.asm.Rm).apply(null,arguments)},Zo=b._emscripten_bind_btGImpactMeshShapePart_btGImpactMeshShapePart_2=function(){return(Zo=b._emscripten_bind_btGImpactMeshShapePart_btGImpactMeshShapePart_2=
|
||||
b.asm.Sm).apply(null,arguments)},$o=b._emscripten_bind_btGImpactMeshShapePart_getTrimeshPrimitiveManager_0=function(){return($o=b._emscripten_bind_btGImpactMeshShapePart_getTrimeshPrimitiveManager_0=b.asm.Tm).apply(null,arguments)},ap=b._emscripten_bind_btGImpactMeshShapePart_getVertexCount_0=function(){return(ap=b._emscripten_bind_btGImpactMeshShapePart_getVertexCount_0=b.asm.Um).apply(null,arguments)},bp=b._emscripten_bind_btGImpactMeshShapePart_getVertex_2=function(){return(bp=b._emscripten_bind_btGImpactMeshShapePart_getVertex_2=
|
||||
b.asm.Vm).apply(null,arguments)},cp=b._emscripten_bind_btGImpactMeshShapePart_getPart_0=function(){return(cp=b._emscripten_bind_btGImpactMeshShapePart_getPart_0=b.asm.Wm).apply(null,arguments)},dp=b._emscripten_bind_btGImpactMeshShapePart_setLocalScaling_1=function(){return(dp=b._emscripten_bind_btGImpactMeshShapePart_setLocalScaling_1=b.asm.Xm).apply(null,arguments)},ep=b._emscripten_bind_btGImpactMeshShapePart_getLocalScaling_0=function(){return(ep=b._emscripten_bind_btGImpactMeshShapePart_getLocalScaling_0=
|
||||
b.asm.Ym).apply(null,arguments)},fp=b._emscripten_bind_btGImpactMeshShapePart_updateBound_0=function(){return(fp=b._emscripten_bind_btGImpactMeshShapePart_updateBound_0=b.asm.Zm).apply(null,arguments)},gp=b._emscripten_bind_btGImpactMeshShapePart_postUpdate_0=function(){return(gp=b._emscripten_bind_btGImpactMeshShapePart_postUpdate_0=b.asm._m).apply(null,arguments)},hp=b._emscripten_bind_btGImpactMeshShapePart_getShapeType_0=function(){return(hp=b._emscripten_bind_btGImpactMeshShapePart_getShapeType_0=
|
||||
b.asm.$m).apply(null,arguments)},ip=b._emscripten_bind_btGImpactMeshShapePart_needsRetrieveTriangles_0=function(){return(ip=b._emscripten_bind_btGImpactMeshShapePart_needsRetrieveTriangles_0=b.asm.an).apply(null,arguments)},jp=b._emscripten_bind_btGImpactMeshShapePart_needsRetrieveTetrahedrons_0=function(){return(jp=b._emscripten_bind_btGImpactMeshShapePart_needsRetrieveTetrahedrons_0=b.asm.bn).apply(null,arguments)},kp=b._emscripten_bind_btGImpactMeshShapePart_getBulletTriangle_2=function(){return(kp=
|
||||
b._emscripten_bind_btGImpactMeshShapePart_getBulletTriangle_2=b.asm.cn).apply(null,arguments)},lp=b._emscripten_bind_btGImpactMeshShapePart_getBulletTetrahedron_2=function(){return(lp=b._emscripten_bind_btGImpactMeshShapePart_getBulletTetrahedron_2=b.asm.dn).apply(null,arguments)},mp=b._emscripten_bind_btGImpactMeshShapePart___destroy___0=function(){return(mp=b._emscripten_bind_btGImpactMeshShapePart___destroy___0=b.asm.en).apply(null,arguments)},np=b._emscripten_bind_btGImpactMeshShape_btGImpactMeshShape_1=
|
||||
function(){return(np=b._emscripten_bind_btGImpactMeshShape_btGImpactMeshShape_1=b.asm.fn).apply(null,arguments)},op=b._emscripten_bind_btGImpactMeshShape_getMeshInterface_0=function(){return(op=b._emscripten_bind_btGImpactMeshShape_getMeshInterface_0=b.asm.gn).apply(null,arguments)},pp=b._emscripten_bind_btGImpactMeshShape_getMeshPartCount_0=function(){return(pp=b._emscripten_bind_btGImpactMeshShape_getMeshPartCount_0=b.asm.hn).apply(null,arguments)},qp=b._emscripten_bind_btGImpactMeshShape_getMeshPart_1=
|
||||
function(){return(qp=b._emscripten_bind_btGImpactMeshShape_getMeshPart_1=b.asm.jn).apply(null,arguments)},rp=b._emscripten_bind_btGImpactMeshShape_calculateSerializeBufferSize_0=function(){return(rp=b._emscripten_bind_btGImpactMeshShape_calculateSerializeBufferSize_0=b.asm.kn).apply(null,arguments)},sp=b._emscripten_bind_btGImpactMeshShape_setLocalScaling_1=function(){return(sp=b._emscripten_bind_btGImpactMeshShape_setLocalScaling_1=b.asm.ln).apply(null,arguments)},tp=b._emscripten_bind_btGImpactMeshShape_getLocalScaling_0=
|
||||
function(){return(tp=b._emscripten_bind_btGImpactMeshShape_getLocalScaling_0=b.asm.mn).apply(null,arguments)},up=b._emscripten_bind_btGImpactMeshShape_updateBound_0=function(){return(up=b._emscripten_bind_btGImpactMeshShape_updateBound_0=b.asm.nn).apply(null,arguments)},vp=b._emscripten_bind_btGImpactMeshShape_postUpdate_0=function(){return(vp=b._emscripten_bind_btGImpactMeshShape_postUpdate_0=b.asm.on).apply(null,arguments)},wp=b._emscripten_bind_btGImpactMeshShape_getShapeType_0=function(){return(wp=
|
||||
b._emscripten_bind_btGImpactMeshShape_getShapeType_0=b.asm.pn).apply(null,arguments)},xp=b._emscripten_bind_btGImpactMeshShape_needsRetrieveTriangles_0=function(){return(xp=b._emscripten_bind_btGImpactMeshShape_needsRetrieveTriangles_0=b.asm.qn).apply(null,arguments)},yp=b._emscripten_bind_btGImpactMeshShape_needsRetrieveTetrahedrons_0=function(){return(yp=b._emscripten_bind_btGImpactMeshShape_needsRetrieveTetrahedrons_0=b.asm.rn).apply(null,arguments)},zp=b._emscripten_bind_btGImpactMeshShape_getBulletTriangle_2=
|
||||
function(){return(zp=b._emscripten_bind_btGImpactMeshShape_getBulletTriangle_2=b.asm.sn).apply(null,arguments)},Ap=b._emscripten_bind_btGImpactMeshShape_getBulletTetrahedron_2=function(){return(Ap=b._emscripten_bind_btGImpactMeshShape_getBulletTetrahedron_2=b.asm.tn).apply(null,arguments)},Bp=b._emscripten_bind_btGImpactMeshShape___destroy___0=function(){return(Bp=b._emscripten_bind_btGImpactMeshShape___destroy___0=b.asm.un).apply(null,arguments)},Cp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_0=
|
||||
function(){return(Cp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_0=b.asm.vn).apply(null,arguments)},Dp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_2=function(){return(Dp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_2=b.asm.wn).apply(null,arguments)},Ep=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_get_m_dispatcher1_0=function(){return(Ep=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_get_m_dispatcher1_0=
|
||||
b.asm.xn).apply(null,arguments)},Fp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_set_m_dispatcher1_1=function(){return(Fp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_set_m_dispatcher1_1=b.asm.yn).apply(null,arguments)},Gp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_get_m_manifold_0=function(){return(Gp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_get_m_manifold_0=b.asm.zn).apply(null,arguments)},Hp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_set_m_manifold_1=
|
||||
function(){return(Hp=b._emscripten_bind_btCollisionAlgorithmConstructionInfo_set_m_manifold_1=b.asm.An).apply(null,arguments)},Ip=b._emscripten_bind_btCollisionAlgorithmConstructionInfo___destroy___0=function(){return(Ip=b._emscripten_bind_btCollisionAlgorithmConstructionInfo___destroy___0=b.asm.Bn).apply(null,arguments)},Jp=b._emscripten_bind_btGImpactCollisionAlgorithm_btGImpactCollisionAlgorithm_3=function(){return(Jp=b._emscripten_bind_btGImpactCollisionAlgorithm_btGImpactCollisionAlgorithm_3=
|
||||
b.asm.Cn).apply(null,arguments)},Kp=b._emscripten_bind_btGImpactCollisionAlgorithm_registerAlgorithm_1=function(){return(Kp=b._emscripten_bind_btGImpactCollisionAlgorithm_registerAlgorithm_1=b.asm.Dn).apply(null,arguments)},Lp=b._emscripten_bind_btGImpactCollisionAlgorithm___destroy___0=function(){return(Lp=b._emscripten_bind_btGImpactCollisionAlgorithm___destroy___0=b.asm.En).apply(null,arguments)},Mp=b._emscripten_bind_btDefaultCollisionConstructionInfo_btDefaultCollisionConstructionInfo_0=function(){return(Mp=
|
||||
b._emscripten_bind_btDefaultCollisionConstructionInfo_btDefaultCollisionConstructionInfo_0=b.asm.Fn).apply(null,arguments)},Np=b._emscripten_bind_btDefaultCollisionConstructionInfo___destroy___0=function(){return(Np=b._emscripten_bind_btDefaultCollisionConstructionInfo___destroy___0=b.asm.Gn).apply(null,arguments)},Op=b._emscripten_bind_btPersistentManifold_btPersistentManifold_0=function(){return(Op=b._emscripten_bind_btPersistentManifold_btPersistentManifold_0=b.asm.Hn).apply(null,arguments)},Pp=
|
||||
b._emscripten_bind_btPersistentManifold_getBody0_0=function(){return(Pp=b._emscripten_bind_btPersistentManifold_getBody0_0=b.asm.In).apply(null,arguments)},Qp=b._emscripten_bind_btPersistentManifold_getBody1_0=function(){return(Qp=b._emscripten_bind_btPersistentManifold_getBody1_0=b.asm.Jn).apply(null,arguments)},Rp=b._emscripten_bind_btPersistentManifold_getNumContacts_0=function(){return(Rp=b._emscripten_bind_btPersistentManifold_getNumContacts_0=b.asm.Kn).apply(null,arguments)},Sp=b._emscripten_bind_btPersistentManifold_getContactPoint_1=
|
||||
function(){return(Sp=b._emscripten_bind_btPersistentManifold_getContactPoint_1=b.asm.Ln).apply(null,arguments)},Tp=b._emscripten_bind_btPersistentManifold___destroy___0=function(){return(Tp=b._emscripten_bind_btPersistentManifold___destroy___0=b.asm.Mn).apply(null,arguments)},Up=b._emscripten_bind_btCollisionDispatcher_btCollisionDispatcher_1=function(){return(Up=b._emscripten_bind_btCollisionDispatcher_btCollisionDispatcher_1=b.asm.Nn).apply(null,arguments)},Vp=b._emscripten_bind_btCollisionDispatcher_getNumManifolds_0=
|
||||
function(){return(Vp=b._emscripten_bind_btCollisionDispatcher_getNumManifolds_0=b.asm.On).apply(null,arguments)},Wp=b._emscripten_bind_btCollisionDispatcher_getManifoldByIndexInternal_1=function(){return(Wp=b._emscripten_bind_btCollisionDispatcher_getManifoldByIndexInternal_1=b.asm.Pn).apply(null,arguments)},Xp=b._emscripten_bind_btCollisionDispatcher___destroy___0=function(){return(Xp=b._emscripten_bind_btCollisionDispatcher___destroy___0=b.asm.Qn).apply(null,arguments)},Yp=b._emscripten_bind_btOverlappingPairCallback___destroy___0=
|
||||
function(){return(Yp=b._emscripten_bind_btOverlappingPairCallback___destroy___0=b.asm.Rn).apply(null,arguments)},Zp=b._emscripten_bind_btOverlappingPairCache_setInternalGhostPairCallback_1=function(){return(Zp=b._emscripten_bind_btOverlappingPairCache_setInternalGhostPairCallback_1=b.asm.Sn).apply(null,arguments)},$p=b._emscripten_bind_btOverlappingPairCache_getNumOverlappingPairs_0=function(){return($p=b._emscripten_bind_btOverlappingPairCache_getNumOverlappingPairs_0=b.asm.Tn).apply(null,arguments)},
|
||||
aq=b._emscripten_bind_btOverlappingPairCache___destroy___0=function(){return(aq=b._emscripten_bind_btOverlappingPairCache___destroy___0=b.asm.Un).apply(null,arguments)},bq=b._emscripten_bind_btAxisSweep3_btAxisSweep3_2=function(){return(bq=b._emscripten_bind_btAxisSweep3_btAxisSweep3_2=b.asm.Vn).apply(null,arguments)},cq=b._emscripten_bind_btAxisSweep3_btAxisSweep3_3=function(){return(cq=b._emscripten_bind_btAxisSweep3_btAxisSweep3_3=b.asm.Wn).apply(null,arguments)},dq=b._emscripten_bind_btAxisSweep3_btAxisSweep3_4=
|
||||
function(){return(dq=b._emscripten_bind_btAxisSweep3_btAxisSweep3_4=b.asm.Xn).apply(null,arguments)},eq=b._emscripten_bind_btAxisSweep3_btAxisSweep3_5=function(){return(eq=b._emscripten_bind_btAxisSweep3_btAxisSweep3_5=b.asm.Yn).apply(null,arguments)},fq=b._emscripten_bind_btAxisSweep3___destroy___0=function(){return(fq=b._emscripten_bind_btAxisSweep3___destroy___0=b.asm.Zn).apply(null,arguments)},gq=b._emscripten_bind_btBroadphaseInterface_getOverlappingPairCache_0=function(){return(gq=b._emscripten_bind_btBroadphaseInterface_getOverlappingPairCache_0=
|
||||
b.asm._n).apply(null,arguments)},hq=b._emscripten_bind_btBroadphaseInterface___destroy___0=function(){return(hq=b._emscripten_bind_btBroadphaseInterface___destroy___0=b.asm.$n).apply(null,arguments)},iq=b._emscripten_bind_btCollisionConfiguration___destroy___0=function(){return(iq=b._emscripten_bind_btCollisionConfiguration___destroy___0=b.asm.ao).apply(null,arguments)},jq=b._emscripten_bind_btDbvtBroadphase_btDbvtBroadphase_0=function(){return(jq=b._emscripten_bind_btDbvtBroadphase_btDbvtBroadphase_0=
|
||||
b.asm.bo).apply(null,arguments)},kq=b._emscripten_bind_btDbvtBroadphase___destroy___0=function(){return(kq=b._emscripten_bind_btDbvtBroadphase___destroy___0=b.asm.co).apply(null,arguments)},lq=b._emscripten_bind_btBroadphaseProxy_get_m_collisionFilterGroup_0=function(){return(lq=b._emscripten_bind_btBroadphaseProxy_get_m_collisionFilterGroup_0=b.asm.eo).apply(null,arguments)},mq=b._emscripten_bind_btBroadphaseProxy_set_m_collisionFilterGroup_1=function(){return(mq=b._emscripten_bind_btBroadphaseProxy_set_m_collisionFilterGroup_1=
|
||||
b.asm.fo).apply(null,arguments)},nq=b._emscripten_bind_btBroadphaseProxy_get_m_collisionFilterMask_0=function(){return(nq=b._emscripten_bind_btBroadphaseProxy_get_m_collisionFilterMask_0=b.asm.go).apply(null,arguments)},oq=b._emscripten_bind_btBroadphaseProxy_set_m_collisionFilterMask_1=function(){return(oq=b._emscripten_bind_btBroadphaseProxy_set_m_collisionFilterMask_1=b.asm.ho).apply(null,arguments)},pq=b._emscripten_bind_btBroadphaseProxy___destroy___0=function(){return(pq=b._emscripten_bind_btBroadphaseProxy___destroy___0=
|
||||
b.asm.io).apply(null,arguments)},qq=b._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_3=function(){return(qq=b._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_3=b.asm.jo).apply(null,arguments)},rq=b._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_4=function(){return(rq=b._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_4=b.asm.ko).apply(null,arguments)},sq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearDamping_0=
|
||||
function(){return(sq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearDamping_0=b.asm.lo).apply(null,arguments)},tq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearDamping_1=function(){return(tq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearDamping_1=b.asm.mo).apply(null,arguments)},uq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularDamping_0=function(){return(uq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularDamping_0=b.asm.no).apply(null,
|
||||
arguments)},vq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularDamping_1=function(){return(vq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularDamping_1=b.asm.oo).apply(null,arguments)},wq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_friction_0=function(){return(wq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_friction_0=b.asm.po).apply(null,arguments)},xq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_friction_1=function(){return(xq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_friction_1=
|
||||
b.asm.qo).apply(null,arguments)},yq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_rollingFriction_0=function(){return(yq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_rollingFriction_0=b.asm.ro).apply(null,arguments)},zq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_rollingFriction_1=function(){return(zq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_rollingFriction_1=b.asm.so).apply(null,arguments)},Aq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_restitution_0=
|
||||
function(){return(Aq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_restitution_0=b.asm.to).apply(null,arguments)},Bq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_restitution_1=function(){return(Bq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_restitution_1=b.asm.uo).apply(null,arguments)},Cq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearSleepingThreshold_0=function(){return(Cq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearSleepingThreshold_0=b.asm.vo).apply(null,
|
||||
arguments)},Dq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearSleepingThreshold_1=function(){return(Dq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearSleepingThreshold_1=b.asm.wo).apply(null,arguments)},Eq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularSleepingThreshold_0=function(){return(Eq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularSleepingThreshold_0=b.asm.xo).apply(null,arguments)},Fq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularSleepingThreshold_1=
|
||||
function(){return(Fq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularSleepingThreshold_1=b.asm.yo).apply(null,arguments)},Gq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDamping_0=function(){return(Gq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDamping_0=b.asm.zo).apply(null,arguments)},Hq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDamping_1=function(){return(Hq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDamping_1=
|
||||
b.asm.Ao).apply(null,arguments)},Iq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDampingFactor_0=function(){return(Iq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDampingFactor_0=b.asm.Bo).apply(null,arguments)},Jq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDampingFactor_1=function(){return(Jq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDampingFactor_1=b.asm.Co).apply(null,arguments)},Kq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalLinearDampingThresholdSqr_0=
|
||||
function(){return(Kq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalLinearDampingThresholdSqr_0=b.asm.Do).apply(null,arguments)},Lq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalLinearDampingThresholdSqr_1=function(){return(Lq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalLinearDampingThresholdSqr_1=b.asm.Eo).apply(null,arguments)},Mq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingThresholdSqr_0=function(){return(Mq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingThresholdSqr_0=
|
||||
b.asm.Fo).apply(null,arguments)},Nq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingThresholdSqr_1=function(){return(Nq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingThresholdSqr_1=b.asm.Go).apply(null,arguments)},Oq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingFactor_0=function(){return(Oq=b._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingFactor_0=b.asm.Ho).apply(null,arguments)},
|
||||
Pq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingFactor_1=function(){return(Pq=b._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingFactor_1=b.asm.Io).apply(null,arguments)},Qq=b._emscripten_bind_btRigidBodyConstructionInfo___destroy___0=function(){return(Qq=b._emscripten_bind_btRigidBodyConstructionInfo___destroy___0=b.asm.Jo).apply(null,arguments)},Rq=b._emscripten_bind_btRigidBody_btRigidBody_1=function(){return(Rq=b._emscripten_bind_btRigidBody_btRigidBody_1=
|
||||
b.asm.Ko).apply(null,arguments)},Sq=b._emscripten_bind_btRigidBody_getCenterOfMassTransform_0=function(){return(Sq=b._emscripten_bind_btRigidBody_getCenterOfMassTransform_0=b.asm.Lo).apply(null,arguments)},Tq=b._emscripten_bind_btRigidBody_setCenterOfMassTransform_1=function(){return(Tq=b._emscripten_bind_btRigidBody_setCenterOfMassTransform_1=b.asm.Mo).apply(null,arguments)},Uq=b._emscripten_bind_btRigidBody_setSleepingThresholds_2=function(){return(Uq=b._emscripten_bind_btRigidBody_setSleepingThresholds_2=
|
||||
b.asm.No).apply(null,arguments)},Vq=b._emscripten_bind_btRigidBody_getLinearDamping_0=function(){return(Vq=b._emscripten_bind_btRigidBody_getLinearDamping_0=b.asm.Oo).apply(null,arguments)},Wq=b._emscripten_bind_btRigidBody_getAngularDamping_0=function(){return(Wq=b._emscripten_bind_btRigidBody_getAngularDamping_0=b.asm.Po).apply(null,arguments)},Xq=b._emscripten_bind_btRigidBody_setDamping_2=function(){return(Xq=b._emscripten_bind_btRigidBody_setDamping_2=b.asm.Qo).apply(null,arguments)},Yq=b._emscripten_bind_btRigidBody_setMassProps_2=
|
||||
function(){return(Yq=b._emscripten_bind_btRigidBody_setMassProps_2=b.asm.Ro).apply(null,arguments)},Zq=b._emscripten_bind_btRigidBody_getLinearFactor_0=function(){return(Zq=b._emscripten_bind_btRigidBody_getLinearFactor_0=b.asm.So).apply(null,arguments)},$q=b._emscripten_bind_btRigidBody_setLinearFactor_1=function(){return($q=b._emscripten_bind_btRigidBody_setLinearFactor_1=b.asm.To).apply(null,arguments)},ar=b._emscripten_bind_btRigidBody_applyTorque_1=function(){return(ar=b._emscripten_bind_btRigidBody_applyTorque_1=
|
||||
b.asm.Uo).apply(null,arguments)},br=b._emscripten_bind_btRigidBody_applyLocalTorque_1=function(){return(br=b._emscripten_bind_btRigidBody_applyLocalTorque_1=b.asm.Vo).apply(null,arguments)},cr=b._emscripten_bind_btRigidBody_applyForce_2=function(){return(cr=b._emscripten_bind_btRigidBody_applyForce_2=b.asm.Wo).apply(null,arguments)},dr=b._emscripten_bind_btRigidBody_applyCentralForce_1=function(){return(dr=b._emscripten_bind_btRigidBody_applyCentralForce_1=b.asm.Xo).apply(null,arguments)},er=b._emscripten_bind_btRigidBody_applyCentralLocalForce_1=
|
||||
function(){return(er=b._emscripten_bind_btRigidBody_applyCentralLocalForce_1=b.asm.Yo).apply(null,arguments)},fr=b._emscripten_bind_btRigidBody_applyTorqueImpulse_1=function(){return(fr=b._emscripten_bind_btRigidBody_applyTorqueImpulse_1=b.asm.Zo).apply(null,arguments)},gr=b._emscripten_bind_btRigidBody_applyImpulse_2=function(){return(gr=b._emscripten_bind_btRigidBody_applyImpulse_2=b.asm._o).apply(null,arguments)},hr=b._emscripten_bind_btRigidBody_applyCentralImpulse_1=function(){return(hr=b._emscripten_bind_btRigidBody_applyCentralImpulse_1=
|
||||
b.asm.$o).apply(null,arguments)},ir=b._emscripten_bind_btRigidBody_updateInertiaTensor_0=function(){return(ir=b._emscripten_bind_btRigidBody_updateInertiaTensor_0=b.asm.ap).apply(null,arguments)},jr=b._emscripten_bind_btRigidBody_getLinearVelocity_0=function(){return(jr=b._emscripten_bind_btRigidBody_getLinearVelocity_0=b.asm.bp).apply(null,arguments)},kr=b._emscripten_bind_btRigidBody_getAngularVelocity_0=function(){return(kr=b._emscripten_bind_btRigidBody_getAngularVelocity_0=b.asm.cp).apply(null,
|
||||
arguments)},lr=b._emscripten_bind_btRigidBody_setLinearVelocity_1=function(){return(lr=b._emscripten_bind_btRigidBody_setLinearVelocity_1=b.asm.dp).apply(null,arguments)},mr=b._emscripten_bind_btRigidBody_setAngularVelocity_1=function(){return(mr=b._emscripten_bind_btRigidBody_setAngularVelocity_1=b.asm.ep).apply(null,arguments)},nr=b._emscripten_bind_btRigidBody_getMotionState_0=function(){return(nr=b._emscripten_bind_btRigidBody_getMotionState_0=b.asm.fp).apply(null,arguments)},or=b._emscripten_bind_btRigidBody_setMotionState_1=
|
||||
function(){return(or=b._emscripten_bind_btRigidBody_setMotionState_1=b.asm.gp).apply(null,arguments)},pr=b._emscripten_bind_btRigidBody_getAngularFactor_0=function(){return(pr=b._emscripten_bind_btRigidBody_getAngularFactor_0=b.asm.hp).apply(null,arguments)},qr=b._emscripten_bind_btRigidBody_setAngularFactor_1=function(){return(qr=b._emscripten_bind_btRigidBody_setAngularFactor_1=b.asm.ip).apply(null,arguments)},rr=b._emscripten_bind_btRigidBody_upcast_1=function(){return(rr=b._emscripten_bind_btRigidBody_upcast_1=
|
||||
b.asm.jp).apply(null,arguments)},sr=b._emscripten_bind_btRigidBody_getAabb_2=function(){return(sr=b._emscripten_bind_btRigidBody_getAabb_2=b.asm.kp).apply(null,arguments)},tr=b._emscripten_bind_btRigidBody_applyGravity_0=function(){return(tr=b._emscripten_bind_btRigidBody_applyGravity_0=b.asm.lp).apply(null,arguments)},ur=b._emscripten_bind_btRigidBody_getGravity_0=function(){return(ur=b._emscripten_bind_btRigidBody_getGravity_0=b.asm.mp).apply(null,arguments)},vr=b._emscripten_bind_btRigidBody_setGravity_1=
|
||||
function(){return(vr=b._emscripten_bind_btRigidBody_setGravity_1=b.asm.np).apply(null,arguments)},wr=b._emscripten_bind_btRigidBody_getBroadphaseProxy_0=function(){return(wr=b._emscripten_bind_btRigidBody_getBroadphaseProxy_0=b.asm.op).apply(null,arguments)},xr=b._emscripten_bind_btRigidBody_clearForces_0=function(){return(xr=b._emscripten_bind_btRigidBody_clearForces_0=b.asm.pp).apply(null,arguments)},yr=b._emscripten_bind_btRigidBody_setFlags_1=function(){return(yr=b._emscripten_bind_btRigidBody_setFlags_1=
|
||||
b.asm.qp).apply(null,arguments)},zr=b._emscripten_bind_btRigidBody_getFlags_0=function(){return(zr=b._emscripten_bind_btRigidBody_getFlags_0=b.asm.rp).apply(null,arguments)},Ar=b._emscripten_bind_btRigidBody_setAnisotropicFriction_2=function(){return(Ar=b._emscripten_bind_btRigidBody_setAnisotropicFriction_2=b.asm.sp).apply(null,arguments)},Br=b._emscripten_bind_btRigidBody_getCollisionShape_0=function(){return(Br=b._emscripten_bind_btRigidBody_getCollisionShape_0=b.asm.tp).apply(null,arguments)},
|
||||
Cr=b._emscripten_bind_btRigidBody_setContactProcessingThreshold_1=function(){return(Cr=b._emscripten_bind_btRigidBody_setContactProcessingThreshold_1=b.asm.up).apply(null,arguments)},Dr=b._emscripten_bind_btRigidBody_setActivationState_1=function(){return(Dr=b._emscripten_bind_btRigidBody_setActivationState_1=b.asm.vp).apply(null,arguments)},Er=b._emscripten_bind_btRigidBody_forceActivationState_1=function(){return(Er=b._emscripten_bind_btRigidBody_forceActivationState_1=b.asm.wp).apply(null,arguments)},
|
||||
Fr=b._emscripten_bind_btRigidBody_activate_0=function(){return(Fr=b._emscripten_bind_btRigidBody_activate_0=b.asm.xp).apply(null,arguments)},Gr=b._emscripten_bind_btRigidBody_activate_1=function(){return(Gr=b._emscripten_bind_btRigidBody_activate_1=b.asm.yp).apply(null,arguments)},Hr=b._emscripten_bind_btRigidBody_isActive_0=function(){return(Hr=b._emscripten_bind_btRigidBody_isActive_0=b.asm.zp).apply(null,arguments)},Ir=b._emscripten_bind_btRigidBody_isKinematicObject_0=function(){return(Ir=b._emscripten_bind_btRigidBody_isKinematicObject_0=
|
||||
b.asm.Ap).apply(null,arguments)},Jr=b._emscripten_bind_btRigidBody_isStaticObject_0=function(){return(Jr=b._emscripten_bind_btRigidBody_isStaticObject_0=b.asm.Bp).apply(null,arguments)},Kr=b._emscripten_bind_btRigidBody_isStaticOrKinematicObject_0=function(){return(Kr=b._emscripten_bind_btRigidBody_isStaticOrKinematicObject_0=b.asm.Cp).apply(null,arguments)},Lr=b._emscripten_bind_btRigidBody_getRestitution_0=function(){return(Lr=b._emscripten_bind_btRigidBody_getRestitution_0=b.asm.Dp).apply(null,
|
||||
arguments)},Mr=b._emscripten_bind_btRigidBody_getFriction_0=function(){return(Mr=b._emscripten_bind_btRigidBody_getFriction_0=b.asm.Ep).apply(null,arguments)},Nr=b._emscripten_bind_btRigidBody_getRollingFriction_0=function(){return(Nr=b._emscripten_bind_btRigidBody_getRollingFriction_0=b.asm.Fp).apply(null,arguments)},Or=b._emscripten_bind_btRigidBody_setRestitution_1=function(){return(Or=b._emscripten_bind_btRigidBody_setRestitution_1=b.asm.Gp).apply(null,arguments)},Pr=b._emscripten_bind_btRigidBody_setFriction_1=
|
||||
function(){return(Pr=b._emscripten_bind_btRigidBody_setFriction_1=b.asm.Hp).apply(null,arguments)},Qr=b._emscripten_bind_btRigidBody_setRollingFriction_1=function(){return(Qr=b._emscripten_bind_btRigidBody_setRollingFriction_1=b.asm.Ip).apply(null,arguments)},Rr=b._emscripten_bind_btRigidBody_getWorldTransform_0=function(){return(Rr=b._emscripten_bind_btRigidBody_getWorldTransform_0=b.asm.Jp).apply(null,arguments)},Sr=b._emscripten_bind_btRigidBody_getCollisionFlags_0=function(){return(Sr=b._emscripten_bind_btRigidBody_getCollisionFlags_0=
|
||||
b.asm.Kp).apply(null,arguments)},Tr=b._emscripten_bind_btRigidBody_setCollisionFlags_1=function(){return(Tr=b._emscripten_bind_btRigidBody_setCollisionFlags_1=b.asm.Lp).apply(null,arguments)},Ur=b._emscripten_bind_btRigidBody_setWorldTransform_1=function(){return(Ur=b._emscripten_bind_btRigidBody_setWorldTransform_1=b.asm.Mp).apply(null,arguments)},Vr=b._emscripten_bind_btRigidBody_setCollisionShape_1=function(){return(Vr=b._emscripten_bind_btRigidBody_setCollisionShape_1=b.asm.Np).apply(null,arguments)},
|
||||
Wr=b._emscripten_bind_btRigidBody_setCcdMotionThreshold_1=function(){return(Wr=b._emscripten_bind_btRigidBody_setCcdMotionThreshold_1=b.asm.Op).apply(null,arguments)},Xr=b._emscripten_bind_btRigidBody_setCcdSweptSphereRadius_1=function(){return(Xr=b._emscripten_bind_btRigidBody_setCcdSweptSphereRadius_1=b.asm.Pp).apply(null,arguments)},Yr=b._emscripten_bind_btRigidBody_getUserIndex_0=function(){return(Yr=b._emscripten_bind_btRigidBody_getUserIndex_0=b.asm.Qp).apply(null,arguments)},Zr=b._emscripten_bind_btRigidBody_setUserIndex_1=
|
||||
function(){return(Zr=b._emscripten_bind_btRigidBody_setUserIndex_1=b.asm.Rp).apply(null,arguments)},$r=b._emscripten_bind_btRigidBody_getUserPointer_0=function(){return($r=b._emscripten_bind_btRigidBody_getUserPointer_0=b.asm.Sp).apply(null,arguments)},as=b._emscripten_bind_btRigidBody_setUserPointer_1=function(){return(as=b._emscripten_bind_btRigidBody_setUserPointer_1=b.asm.Tp).apply(null,arguments)},bs=b._emscripten_bind_btRigidBody_getBroadphaseHandle_0=function(){return(bs=b._emscripten_bind_btRigidBody_getBroadphaseHandle_0=
|
||||
b.asm.Up).apply(null,arguments)},cs=b._emscripten_bind_btRigidBody___destroy___0=function(){return(cs=b._emscripten_bind_btRigidBody___destroy___0=b.asm.Vp).apply(null,arguments)},ds=b._emscripten_bind_btConstraintSetting_btConstraintSetting_0=function(){return(ds=b._emscripten_bind_btConstraintSetting_btConstraintSetting_0=b.asm.Wp).apply(null,arguments)},es=b._emscripten_bind_btConstraintSetting_get_m_tau_0=function(){return(es=b._emscripten_bind_btConstraintSetting_get_m_tau_0=b.asm.Xp).apply(null,
|
||||
arguments)},gs=b._emscripten_bind_btConstraintSetting_set_m_tau_1=function(){return(gs=b._emscripten_bind_btConstraintSetting_set_m_tau_1=b.asm.Yp).apply(null,arguments)},hs=b._emscripten_bind_btConstraintSetting_get_m_damping_0=function(){return(hs=b._emscripten_bind_btConstraintSetting_get_m_damping_0=b.asm.Zp).apply(null,arguments)},is=b._emscripten_bind_btConstraintSetting_set_m_damping_1=function(){return(is=b._emscripten_bind_btConstraintSetting_set_m_damping_1=b.asm._p).apply(null,arguments)},
|
||||
js=b._emscripten_bind_btConstraintSetting_get_m_impulseClamp_0=function(){return(js=b._emscripten_bind_btConstraintSetting_get_m_impulseClamp_0=b.asm.$p).apply(null,arguments)},ks=b._emscripten_bind_btConstraintSetting_set_m_impulseClamp_1=function(){return(ks=b._emscripten_bind_btConstraintSetting_set_m_impulseClamp_1=b.asm.aq).apply(null,arguments)},ls=b._emscripten_bind_btConstraintSetting___destroy___0=function(){return(ls=b._emscripten_bind_btConstraintSetting___destroy___0=b.asm.bq).apply(null,
|
||||
arguments)},ms=b._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_2=function(){return(ms=b._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_2=b.asm.cq).apply(null,arguments)},ns=b._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_4=function(){return(ns=b._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_4=b.asm.dq).apply(null,arguments)},ps=b._emscripten_bind_btPoint2PointConstraint_setPivotA_1=function(){return(ps=b._emscripten_bind_btPoint2PointConstraint_setPivotA_1=
|
||||
b.asm.eq).apply(null,arguments)},qs=b._emscripten_bind_btPoint2PointConstraint_setPivotB_1=function(){return(qs=b._emscripten_bind_btPoint2PointConstraint_setPivotB_1=b.asm.fq).apply(null,arguments)},rs=b._emscripten_bind_btPoint2PointConstraint_getPivotInA_0=function(){return(rs=b._emscripten_bind_btPoint2PointConstraint_getPivotInA_0=b.asm.gq).apply(null,arguments)},ss=b._emscripten_bind_btPoint2PointConstraint_getPivotInB_0=function(){return(ss=b._emscripten_bind_btPoint2PointConstraint_getPivotInB_0=
|
||||
b.asm.hq).apply(null,arguments)},ts=b._emscripten_bind_btPoint2PointConstraint_enableFeedback_1=function(){return(ts=b._emscripten_bind_btPoint2PointConstraint_enableFeedback_1=b.asm.iq).apply(null,arguments)},us=b._emscripten_bind_btPoint2PointConstraint_getBreakingImpulseThreshold_0=function(){return(us=b._emscripten_bind_btPoint2PointConstraint_getBreakingImpulseThreshold_0=b.asm.jq).apply(null,arguments)},vs=b._emscripten_bind_btPoint2PointConstraint_setBreakingImpulseThreshold_1=function(){return(vs=
|
||||
b._emscripten_bind_btPoint2PointConstraint_setBreakingImpulseThreshold_1=b.asm.kq).apply(null,arguments)},xs=b._emscripten_bind_btPoint2PointConstraint_getParam_2=function(){return(xs=b._emscripten_bind_btPoint2PointConstraint_getParam_2=b.asm.lq).apply(null,arguments)},ys=b._emscripten_bind_btPoint2PointConstraint_setParam_3=function(){return(ys=b._emscripten_bind_btPoint2PointConstraint_setParam_3=b.asm.mq).apply(null,arguments)},zs=b._emscripten_bind_btPoint2PointConstraint_get_m_setting_0=function(){return(zs=
|
||||
b._emscripten_bind_btPoint2PointConstraint_get_m_setting_0=b.asm.nq).apply(null,arguments)},As=b._emscripten_bind_btPoint2PointConstraint_set_m_setting_1=function(){return(As=b._emscripten_bind_btPoint2PointConstraint_set_m_setting_1=b.asm.oq).apply(null,arguments)},Bs=b._emscripten_bind_btPoint2PointConstraint___destroy___0=function(){return(Bs=b._emscripten_bind_btPoint2PointConstraint___destroy___0=b.asm.pq).apply(null,arguments)},Cs=b._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_3=
|
||||
function(){return(Cs=b._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_3=b.asm.qq).apply(null,arguments)},Ds=b._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_5=function(){return(Ds=b._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_5=b.asm.rq).apply(null,arguments)},Es=b._emscripten_bind_btGeneric6DofSpringConstraint_enableSpring_2=function(){return(Es=b._emscripten_bind_btGeneric6DofSpringConstraint_enableSpring_2=
|
||||
b.asm.sq).apply(null,arguments)},Fs=b._emscripten_bind_btGeneric6DofSpringConstraint_setStiffness_2=function(){return(Fs=b._emscripten_bind_btGeneric6DofSpringConstraint_setStiffness_2=b.asm.tq).apply(null,arguments)},Gs=b._emscripten_bind_btGeneric6DofSpringConstraint_setDamping_2=function(){return(Gs=b._emscripten_bind_btGeneric6DofSpringConstraint_setDamping_2=b.asm.uq).apply(null,arguments)},Hs=b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_0=function(){return(Hs=b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_0=
|
||||
b.asm.vq).apply(null,arguments)},Is=b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_1=function(){return(Is=b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_1=b.asm.wq).apply(null,arguments)},Js=b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_2=function(){return(Js=b._emscripten_bind_btGeneric6DofSpringConstraint_setEquilibriumPoint_2=b.asm.xq).apply(null,arguments)},Ks=b._emscripten_bind_btGeneric6DofSpringConstraint_setLinearLowerLimit_1=
|
||||
function(){return(Ks=b._emscripten_bind_btGeneric6DofSpringConstraint_setLinearLowerLimit_1=b.asm.yq).apply(null,arguments)},Ls=b._emscripten_bind_btGeneric6DofSpringConstraint_setLinearUpperLimit_1=function(){return(Ls=b._emscripten_bind_btGeneric6DofSpringConstraint_setLinearUpperLimit_1=b.asm.zq).apply(null,arguments)},Ms=b._emscripten_bind_btGeneric6DofSpringConstraint_setAngularLowerLimit_1=function(){return(Ms=b._emscripten_bind_btGeneric6DofSpringConstraint_setAngularLowerLimit_1=b.asm.Aq).apply(null,
|
||||
arguments)},Ns=b._emscripten_bind_btGeneric6DofSpringConstraint_setAngularUpperLimit_1=function(){return(Ns=b._emscripten_bind_btGeneric6DofSpringConstraint_setAngularUpperLimit_1=b.asm.Bq).apply(null,arguments)},Os=b._emscripten_bind_btGeneric6DofSpringConstraint_getFrameOffsetA_0=function(){return(Os=b._emscripten_bind_btGeneric6DofSpringConstraint_getFrameOffsetA_0=b.asm.Cq).apply(null,arguments)},Ps=b._emscripten_bind_btGeneric6DofSpringConstraint_enableFeedback_1=function(){return(Ps=b._emscripten_bind_btGeneric6DofSpringConstraint_enableFeedback_1=
|
||||
b.asm.Dq).apply(null,arguments)},Qs=b._emscripten_bind_btGeneric6DofSpringConstraint_getBreakingImpulseThreshold_0=function(){return(Qs=b._emscripten_bind_btGeneric6DofSpringConstraint_getBreakingImpulseThreshold_0=b.asm.Eq).apply(null,arguments)},Rs=b._emscripten_bind_btGeneric6DofSpringConstraint_setBreakingImpulseThreshold_1=function(){return(Rs=b._emscripten_bind_btGeneric6DofSpringConstraint_setBreakingImpulseThreshold_1=b.asm.Fq).apply(null,arguments)},Ss=b._emscripten_bind_btGeneric6DofSpringConstraint_getParam_2=
|
||||
function(){return(Ss=b._emscripten_bind_btGeneric6DofSpringConstraint_getParam_2=b.asm.Gq).apply(null,arguments)},Ts=b._emscripten_bind_btGeneric6DofSpringConstraint_setParam_3=function(){return(Ts=b._emscripten_bind_btGeneric6DofSpringConstraint_setParam_3=b.asm.Hq).apply(null,arguments)},Us=b._emscripten_bind_btGeneric6DofSpringConstraint___destroy___0=function(){return(Us=b._emscripten_bind_btGeneric6DofSpringConstraint___destroy___0=b.asm.Iq).apply(null,arguments)},Vs=b._emscripten_bind_btSequentialImpulseConstraintSolver_btSequentialImpulseConstraintSolver_0=
|
||||
function(){return(Vs=b._emscripten_bind_btSequentialImpulseConstraintSolver_btSequentialImpulseConstraintSolver_0=b.asm.Jq).apply(null,arguments)},Ws=b._emscripten_bind_btSequentialImpulseConstraintSolver___destroy___0=function(){return(Ws=b._emscripten_bind_btSequentialImpulseConstraintSolver___destroy___0=b.asm.Kq).apply(null,arguments)},Xs=b._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_2=function(){return(Xs=b._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_2=b.asm.Lq).apply(null,
|
||||
arguments)},Ys=b._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_4=function(){return(Ys=b._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_4=b.asm.Mq).apply(null,arguments)},Zs=b._emscripten_bind_btConeTwistConstraint_setLimit_2=function(){return(Zs=b._emscripten_bind_btConeTwistConstraint_setLimit_2=b.asm.Nq).apply(null,arguments)},$s=b._emscripten_bind_btConeTwistConstraint_setAngularOnly_1=function(){return($s=b._emscripten_bind_btConeTwistConstraint_setAngularOnly_1=b.asm.Oq).apply(null,
|
||||
arguments)},at=b._emscripten_bind_btConeTwistConstraint_setDamping_1=function(){return(at=b._emscripten_bind_btConeTwistConstraint_setDamping_1=b.asm.Pq).apply(null,arguments)},bt=b._emscripten_bind_btConeTwistConstraint_enableMotor_1=function(){return(bt=b._emscripten_bind_btConeTwistConstraint_enableMotor_1=b.asm.Qq).apply(null,arguments)},ct=b._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulse_1=function(){return(ct=b._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulse_1=b.asm.Rq).apply(null,
|
||||
arguments)},dt=b._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulseNormalized_1=function(){return(dt=b._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulseNormalized_1=b.asm.Sq).apply(null,arguments)},et=b._emscripten_bind_btConeTwistConstraint_setMotorTarget_1=function(){return(et=b._emscripten_bind_btConeTwistConstraint_setMotorTarget_1=b.asm.Tq).apply(null,arguments)},ft=b._emscripten_bind_btConeTwistConstraint_setMotorTargetInConstraintSpace_1=function(){return(ft=b._emscripten_bind_btConeTwistConstraint_setMotorTargetInConstraintSpace_1=
|
||||
b.asm.Uq).apply(null,arguments)},gt=b._emscripten_bind_btConeTwistConstraint_enableFeedback_1=function(){return(gt=b._emscripten_bind_btConeTwistConstraint_enableFeedback_1=b.asm.Vq).apply(null,arguments)},ht=b._emscripten_bind_btConeTwistConstraint_getBreakingImpulseThreshold_0=function(){return(ht=b._emscripten_bind_btConeTwistConstraint_getBreakingImpulseThreshold_0=b.asm.Wq).apply(null,arguments)},it=b._emscripten_bind_btConeTwistConstraint_setBreakingImpulseThreshold_1=function(){return(it=b._emscripten_bind_btConeTwistConstraint_setBreakingImpulseThreshold_1=
|
||||
b.asm.Xq).apply(null,arguments)},jt=b._emscripten_bind_btConeTwistConstraint_getParam_2=function(){return(jt=b._emscripten_bind_btConeTwistConstraint_getParam_2=b.asm.Yq).apply(null,arguments)},kt=b._emscripten_bind_btConeTwistConstraint_setParam_3=function(){return(kt=b._emscripten_bind_btConeTwistConstraint_setParam_3=b.asm.Zq).apply(null,arguments)},lt=b._emscripten_bind_btConeTwistConstraint___destroy___0=function(){return(lt=b._emscripten_bind_btConeTwistConstraint___destroy___0=b.asm._q).apply(null,
|
||||
arguments)},mt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_2=function(){return(mt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_2=b.asm.$q).apply(null,arguments)},nt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_3=function(){return(nt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_3=b.asm.ar).apply(null,arguments)},ot=b._emscripten_bind_btHingeConstraint_btHingeConstraint_4=function(){return(ot=b._emscripten_bind_btHingeConstraint_btHingeConstraint_4=b.asm.br).apply(null,
|
||||
arguments)},pt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_5=function(){return(pt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_5=b.asm.cr).apply(null,arguments)},qt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_6=function(){return(qt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_6=b.asm.dr).apply(null,arguments)},rt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_7=function(){return(rt=b._emscripten_bind_btHingeConstraint_btHingeConstraint_7=b.asm.er).apply(null,
|
||||
arguments)},st=b._emscripten_bind_btHingeConstraint_getHingeAngle_0=function(){return(st=b._emscripten_bind_btHingeConstraint_getHingeAngle_0=b.asm.fr).apply(null,arguments)},tt=b._emscripten_bind_btHingeConstraint_setLimit_4=function(){return(tt=b._emscripten_bind_btHingeConstraint_setLimit_4=b.asm.gr).apply(null,arguments)},ut=b._emscripten_bind_btHingeConstraint_setLimit_5=function(){return(ut=b._emscripten_bind_btHingeConstraint_setLimit_5=b.asm.hr).apply(null,arguments)},vt=b._emscripten_bind_btHingeConstraint_enableAngularMotor_3=
|
||||
function(){return(vt=b._emscripten_bind_btHingeConstraint_enableAngularMotor_3=b.asm.ir).apply(null,arguments)},wt=b._emscripten_bind_btHingeConstraint_setAngularOnly_1=function(){return(wt=b._emscripten_bind_btHingeConstraint_setAngularOnly_1=b.asm.jr).apply(null,arguments)},xt=b._emscripten_bind_btHingeConstraint_enableMotor_1=function(){return(xt=b._emscripten_bind_btHingeConstraint_enableMotor_1=b.asm.kr).apply(null,arguments)},yt=b._emscripten_bind_btHingeConstraint_setMaxMotorImpulse_1=function(){return(yt=
|
||||
b._emscripten_bind_btHingeConstraint_setMaxMotorImpulse_1=b.asm.lr).apply(null,arguments)},zt=b._emscripten_bind_btHingeConstraint_setMotorTarget_2=function(){return(zt=b._emscripten_bind_btHingeConstraint_setMotorTarget_2=b.asm.mr).apply(null,arguments)},At=b._emscripten_bind_btHingeConstraint_enableFeedback_1=function(){return(At=b._emscripten_bind_btHingeConstraint_enableFeedback_1=b.asm.nr).apply(null,arguments)},Bt=b._emscripten_bind_btHingeConstraint_getBreakingImpulseThreshold_0=function(){return(Bt=
|
||||
b._emscripten_bind_btHingeConstraint_getBreakingImpulseThreshold_0=b.asm.or).apply(null,arguments)},Ct=b._emscripten_bind_btHingeConstraint_setBreakingImpulseThreshold_1=function(){return(Ct=b._emscripten_bind_btHingeConstraint_setBreakingImpulseThreshold_1=b.asm.pr).apply(null,arguments)},Dt=b._emscripten_bind_btHingeConstraint_getParam_2=function(){return(Dt=b._emscripten_bind_btHingeConstraint_getParam_2=b.asm.qr).apply(null,arguments)},Et=b._emscripten_bind_btHingeConstraint_setParam_3=function(){return(Et=
|
||||
b._emscripten_bind_btHingeConstraint_setParam_3=b.asm.rr).apply(null,arguments)},Ft=b._emscripten_bind_btHingeConstraint___destroy___0=function(){return(Ft=b._emscripten_bind_btHingeConstraint___destroy___0=b.asm.sr).apply(null,arguments)},Gt=b._emscripten_bind_btSliderConstraint_btSliderConstraint_3=function(){return(Gt=b._emscripten_bind_btSliderConstraint_btSliderConstraint_3=b.asm.tr).apply(null,arguments)},Ht=b._emscripten_bind_btSliderConstraint_btSliderConstraint_5=function(){return(Ht=b._emscripten_bind_btSliderConstraint_btSliderConstraint_5=
|
||||
b.asm.ur).apply(null,arguments)},It=b._emscripten_bind_btSliderConstraint_getLinearPos_0=function(){return(It=b._emscripten_bind_btSliderConstraint_getLinearPos_0=b.asm.vr).apply(null,arguments)},Jt=b._emscripten_bind_btSliderConstraint_getAngularPos_0=function(){return(Jt=b._emscripten_bind_btSliderConstraint_getAngularPos_0=b.asm.wr).apply(null,arguments)},Kt=b._emscripten_bind_btSliderConstraint_setLowerLinLimit_1=function(){return(Kt=b._emscripten_bind_btSliderConstraint_setLowerLinLimit_1=b.asm.xr).apply(null,
|
||||
arguments)},Lt=b._emscripten_bind_btSliderConstraint_setUpperLinLimit_1=function(){return(Lt=b._emscripten_bind_btSliderConstraint_setUpperLinLimit_1=b.asm.yr).apply(null,arguments)},Mt=b._emscripten_bind_btSliderConstraint_setLowerAngLimit_1=function(){return(Mt=b._emscripten_bind_btSliderConstraint_setLowerAngLimit_1=b.asm.zr).apply(null,arguments)},Nt=b._emscripten_bind_btSliderConstraint_setUpperAngLimit_1=function(){return(Nt=b._emscripten_bind_btSliderConstraint_setUpperAngLimit_1=b.asm.Ar).apply(null,
|
||||
arguments)},Ot=b._emscripten_bind_btSliderConstraint_setPoweredLinMotor_1=function(){return(Ot=b._emscripten_bind_btSliderConstraint_setPoweredLinMotor_1=b.asm.Br).apply(null,arguments)},Pt=b._emscripten_bind_btSliderConstraint_setMaxLinMotorForce_1=function(){return(Pt=b._emscripten_bind_btSliderConstraint_setMaxLinMotorForce_1=b.asm.Cr).apply(null,arguments)},Qt=b._emscripten_bind_btSliderConstraint_setTargetLinMotorVelocity_1=function(){return(Qt=b._emscripten_bind_btSliderConstraint_setTargetLinMotorVelocity_1=
|
||||
b.asm.Dr).apply(null,arguments)},Rt=b._emscripten_bind_btSliderConstraint_enableFeedback_1=function(){return(Rt=b._emscripten_bind_btSliderConstraint_enableFeedback_1=b.asm.Er).apply(null,arguments)},St=b._emscripten_bind_btSliderConstraint_getBreakingImpulseThreshold_0=function(){return(St=b._emscripten_bind_btSliderConstraint_getBreakingImpulseThreshold_0=b.asm.Fr).apply(null,arguments)},Tt=b._emscripten_bind_btSliderConstraint_setBreakingImpulseThreshold_1=function(){return(Tt=b._emscripten_bind_btSliderConstraint_setBreakingImpulseThreshold_1=
|
||||
b.asm.Gr).apply(null,arguments)},Ut=b._emscripten_bind_btSliderConstraint_getParam_2=function(){return(Ut=b._emscripten_bind_btSliderConstraint_getParam_2=b.asm.Hr).apply(null,arguments)},Vt=b._emscripten_bind_btSliderConstraint_setParam_3=function(){return(Vt=b._emscripten_bind_btSliderConstraint_setParam_3=b.asm.Ir).apply(null,arguments)},Wt=b._emscripten_bind_btSliderConstraint___destroy___0=function(){return(Wt=b._emscripten_bind_btSliderConstraint___destroy___0=b.asm.Jr).apply(null,arguments)},
|
||||
Xt=b._emscripten_bind_btFixedConstraint_btFixedConstraint_4=function(){return(Xt=b._emscripten_bind_btFixedConstraint_btFixedConstraint_4=b.asm.Kr).apply(null,arguments)},Yt=b._emscripten_bind_btFixedConstraint_enableFeedback_1=function(){return(Yt=b._emscripten_bind_btFixedConstraint_enableFeedback_1=b.asm.Lr).apply(null,arguments)},Zt=b._emscripten_bind_btFixedConstraint_getBreakingImpulseThreshold_0=function(){return(Zt=b._emscripten_bind_btFixedConstraint_getBreakingImpulseThreshold_0=b.asm.Mr).apply(null,
|
||||
arguments)},$t=b._emscripten_bind_btFixedConstraint_setBreakingImpulseThreshold_1=function(){return($t=b._emscripten_bind_btFixedConstraint_setBreakingImpulseThreshold_1=b.asm.Nr).apply(null,arguments)},au=b._emscripten_bind_btFixedConstraint_getParam_2=function(){return(au=b._emscripten_bind_btFixedConstraint_getParam_2=b.asm.Or).apply(null,arguments)},bu=b._emscripten_bind_btFixedConstraint_setParam_3=function(){return(bu=b._emscripten_bind_btFixedConstraint_setParam_3=b.asm.Pr).apply(null,arguments)},
|
||||
cu=b._emscripten_bind_btFixedConstraint___destroy___0=function(){return(cu=b._emscripten_bind_btFixedConstraint___destroy___0=b.asm.Qr).apply(null,arguments)},du=b._emscripten_bind_btConstraintSolver___destroy___0=function(){return(du=b._emscripten_bind_btConstraintSolver___destroy___0=b.asm.Rr).apply(null,arguments)},eu=b._emscripten_bind_btDispatcherInfo_get_m_timeStep_0=function(){return(eu=b._emscripten_bind_btDispatcherInfo_get_m_timeStep_0=b.asm.Sr).apply(null,arguments)},fu=b._emscripten_bind_btDispatcherInfo_set_m_timeStep_1=
|
||||
function(){return(fu=b._emscripten_bind_btDispatcherInfo_set_m_timeStep_1=b.asm.Tr).apply(null,arguments)},gu=b._emscripten_bind_btDispatcherInfo_get_m_stepCount_0=function(){return(gu=b._emscripten_bind_btDispatcherInfo_get_m_stepCount_0=b.asm.Ur).apply(null,arguments)},hu=b._emscripten_bind_btDispatcherInfo_set_m_stepCount_1=function(){return(hu=b._emscripten_bind_btDispatcherInfo_set_m_stepCount_1=b.asm.Vr).apply(null,arguments)},iu=b._emscripten_bind_btDispatcherInfo_get_m_dispatchFunc_0=function(){return(iu=
|
||||
b._emscripten_bind_btDispatcherInfo_get_m_dispatchFunc_0=b.asm.Wr).apply(null,arguments)},ju=b._emscripten_bind_btDispatcherInfo_set_m_dispatchFunc_1=function(){return(ju=b._emscripten_bind_btDispatcherInfo_set_m_dispatchFunc_1=b.asm.Xr).apply(null,arguments)},ku=b._emscripten_bind_btDispatcherInfo_get_m_timeOfImpact_0=function(){return(ku=b._emscripten_bind_btDispatcherInfo_get_m_timeOfImpact_0=b.asm.Yr).apply(null,arguments)},lu=b._emscripten_bind_btDispatcherInfo_set_m_timeOfImpact_1=function(){return(lu=
|
||||
b._emscripten_bind_btDispatcherInfo_set_m_timeOfImpact_1=b.asm.Zr).apply(null,arguments)},mu=b._emscripten_bind_btDispatcherInfo_get_m_useContinuous_0=function(){return(mu=b._emscripten_bind_btDispatcherInfo_get_m_useContinuous_0=b.asm._r).apply(null,arguments)},nu=b._emscripten_bind_btDispatcherInfo_set_m_useContinuous_1=function(){return(nu=b._emscripten_bind_btDispatcherInfo_set_m_useContinuous_1=b.asm.$r).apply(null,arguments)},ou=b._emscripten_bind_btDispatcherInfo_get_m_enableSatConvex_0=function(){return(ou=
|
||||
b._emscripten_bind_btDispatcherInfo_get_m_enableSatConvex_0=b.asm.as).apply(null,arguments)},pu=b._emscripten_bind_btDispatcherInfo_set_m_enableSatConvex_1=function(){return(pu=b._emscripten_bind_btDispatcherInfo_set_m_enableSatConvex_1=b.asm.bs).apply(null,arguments)},qu=b._emscripten_bind_btDispatcherInfo_get_m_enableSPU_0=function(){return(qu=b._emscripten_bind_btDispatcherInfo_get_m_enableSPU_0=b.asm.cs).apply(null,arguments)},ru=b._emscripten_bind_btDispatcherInfo_set_m_enableSPU_1=function(){return(ru=
|
||||
b._emscripten_bind_btDispatcherInfo_set_m_enableSPU_1=b.asm.ds).apply(null,arguments)},su=b._emscripten_bind_btDispatcherInfo_get_m_useEpa_0=function(){return(su=b._emscripten_bind_btDispatcherInfo_get_m_useEpa_0=b.asm.es).apply(null,arguments)},tu=b._emscripten_bind_btDispatcherInfo_set_m_useEpa_1=function(){return(tu=b._emscripten_bind_btDispatcherInfo_set_m_useEpa_1=b.asm.fs).apply(null,arguments)},uu=b._emscripten_bind_btDispatcherInfo_get_m_allowedCcdPenetration_0=function(){return(uu=b._emscripten_bind_btDispatcherInfo_get_m_allowedCcdPenetration_0=
|
||||
b.asm.gs).apply(null,arguments)},vu=b._emscripten_bind_btDispatcherInfo_set_m_allowedCcdPenetration_1=function(){return(vu=b._emscripten_bind_btDispatcherInfo_set_m_allowedCcdPenetration_1=b.asm.hs).apply(null,arguments)},wu=b._emscripten_bind_btDispatcherInfo_get_m_useConvexConservativeDistanceUtil_0=function(){return(wu=b._emscripten_bind_btDispatcherInfo_get_m_useConvexConservativeDistanceUtil_0=b.asm.is).apply(null,arguments)},xu=b._emscripten_bind_btDispatcherInfo_set_m_useConvexConservativeDistanceUtil_1=
|
||||
function(){return(xu=b._emscripten_bind_btDispatcherInfo_set_m_useConvexConservativeDistanceUtil_1=b.asm.js).apply(null,arguments)},yu=b._emscripten_bind_btDispatcherInfo_get_m_convexConservativeDistanceThreshold_0=function(){return(yu=b._emscripten_bind_btDispatcherInfo_get_m_convexConservativeDistanceThreshold_0=b.asm.ks).apply(null,arguments)},zu=b._emscripten_bind_btDispatcherInfo_set_m_convexConservativeDistanceThreshold_1=function(){return(zu=b._emscripten_bind_btDispatcherInfo_set_m_convexConservativeDistanceThreshold_1=
|
||||
b.asm.ls).apply(null,arguments)},Au=b._emscripten_bind_btDispatcherInfo___destroy___0=function(){return(Au=b._emscripten_bind_btDispatcherInfo___destroy___0=b.asm.ms).apply(null,arguments)},Bu=b._emscripten_bind_btContactSolverInfo_get_m_splitImpulse_0=function(){return(Bu=b._emscripten_bind_btContactSolverInfo_get_m_splitImpulse_0=b.asm.ns).apply(null,arguments)},Cu=b._emscripten_bind_btContactSolverInfo_set_m_splitImpulse_1=function(){return(Cu=b._emscripten_bind_btContactSolverInfo_set_m_splitImpulse_1=
|
||||
b.asm.os).apply(null,arguments)},Du=b._emscripten_bind_btContactSolverInfo_get_m_splitImpulsePenetrationThreshold_0=function(){return(Du=b._emscripten_bind_btContactSolverInfo_get_m_splitImpulsePenetrationThreshold_0=b.asm.ps).apply(null,arguments)},Eu=b._emscripten_bind_btContactSolverInfo_set_m_splitImpulsePenetrationThreshold_1=function(){return(Eu=b._emscripten_bind_btContactSolverInfo_set_m_splitImpulsePenetrationThreshold_1=b.asm.qs).apply(null,arguments)},Fu=b._emscripten_bind_btContactSolverInfo_get_m_numIterations_0=
|
||||
function(){return(Fu=b._emscripten_bind_btContactSolverInfo_get_m_numIterations_0=b.asm.rs).apply(null,arguments)},Gu=b._emscripten_bind_btContactSolverInfo_set_m_numIterations_1=function(){return(Gu=b._emscripten_bind_btContactSolverInfo_set_m_numIterations_1=b.asm.ss).apply(null,arguments)},Hu=b._emscripten_bind_btContactSolverInfo___destroy___0=function(){return(Hu=b._emscripten_bind_btContactSolverInfo___destroy___0=b.asm.ts).apply(null,arguments)},Iu=b._emscripten_bind_btVehicleTuning_btVehicleTuning_0=
|
||||
function(){return(Iu=b._emscripten_bind_btVehicleTuning_btVehicleTuning_0=b.asm.us).apply(null,arguments)},Ju=b._emscripten_bind_btVehicleTuning_get_m_suspensionStiffness_0=function(){return(Ju=b._emscripten_bind_btVehicleTuning_get_m_suspensionStiffness_0=b.asm.vs).apply(null,arguments)},Ku=b._emscripten_bind_btVehicleTuning_set_m_suspensionStiffness_1=function(){return(Ku=b._emscripten_bind_btVehicleTuning_set_m_suspensionStiffness_1=b.asm.ws).apply(null,arguments)},Lu=b._emscripten_bind_btVehicleTuning_get_m_suspensionCompression_0=
|
||||
function(){return(Lu=b._emscripten_bind_btVehicleTuning_get_m_suspensionCompression_0=b.asm.xs).apply(null,arguments)},Mu=b._emscripten_bind_btVehicleTuning_set_m_suspensionCompression_1=function(){return(Mu=b._emscripten_bind_btVehicleTuning_set_m_suspensionCompression_1=b.asm.ys).apply(null,arguments)},Nu=b._emscripten_bind_btVehicleTuning_get_m_suspensionDamping_0=function(){return(Nu=b._emscripten_bind_btVehicleTuning_get_m_suspensionDamping_0=b.asm.zs).apply(null,arguments)},Ou=b._emscripten_bind_btVehicleTuning_set_m_suspensionDamping_1=
|
||||
function(){return(Ou=b._emscripten_bind_btVehicleTuning_set_m_suspensionDamping_1=b.asm.As).apply(null,arguments)},Pu=b._emscripten_bind_btVehicleTuning_get_m_maxSuspensionTravelCm_0=function(){return(Pu=b._emscripten_bind_btVehicleTuning_get_m_maxSuspensionTravelCm_0=b.asm.Bs).apply(null,arguments)},Qu=b._emscripten_bind_btVehicleTuning_set_m_maxSuspensionTravelCm_1=function(){return(Qu=b._emscripten_bind_btVehicleTuning_set_m_maxSuspensionTravelCm_1=b.asm.Cs).apply(null,arguments)},Ru=b._emscripten_bind_btVehicleTuning_get_m_frictionSlip_0=
|
||||
function(){return(Ru=b._emscripten_bind_btVehicleTuning_get_m_frictionSlip_0=b.asm.Ds).apply(null,arguments)},Su=b._emscripten_bind_btVehicleTuning_set_m_frictionSlip_1=function(){return(Su=b._emscripten_bind_btVehicleTuning_set_m_frictionSlip_1=b.asm.Es).apply(null,arguments)},Tu=b._emscripten_bind_btVehicleTuning_get_m_maxSuspensionForce_0=function(){return(Tu=b._emscripten_bind_btVehicleTuning_get_m_maxSuspensionForce_0=b.asm.Fs).apply(null,arguments)},Uu=b._emscripten_bind_btVehicleTuning_set_m_maxSuspensionForce_1=
|
||||
function(){return(Uu=b._emscripten_bind_btVehicleTuning_set_m_maxSuspensionForce_1=b.asm.Gs).apply(null,arguments)},Vu=b._emscripten_bind_btVehicleRaycasterResult_get_m_hitPointInWorld_0=function(){return(Vu=b._emscripten_bind_btVehicleRaycasterResult_get_m_hitPointInWorld_0=b.asm.Hs).apply(null,arguments)},Wu=b._emscripten_bind_btVehicleRaycasterResult_set_m_hitPointInWorld_1=function(){return(Wu=b._emscripten_bind_btVehicleRaycasterResult_set_m_hitPointInWorld_1=b.asm.Is).apply(null,arguments)},
|
||||
Xu=b._emscripten_bind_btVehicleRaycasterResult_get_m_hitNormalInWorld_0=function(){return(Xu=b._emscripten_bind_btVehicleRaycasterResult_get_m_hitNormalInWorld_0=b.asm.Js).apply(null,arguments)},Yu=b._emscripten_bind_btVehicleRaycasterResult_set_m_hitNormalInWorld_1=function(){return(Yu=b._emscripten_bind_btVehicleRaycasterResult_set_m_hitNormalInWorld_1=b.asm.Ks).apply(null,arguments)},Zu=b._emscripten_bind_btVehicleRaycasterResult_get_m_distFraction_0=function(){return(Zu=b._emscripten_bind_btVehicleRaycasterResult_get_m_distFraction_0=
|
||||
b.asm.Ls).apply(null,arguments)},$u=b._emscripten_bind_btVehicleRaycasterResult_set_m_distFraction_1=function(){return($u=b._emscripten_bind_btVehicleRaycasterResult_set_m_distFraction_1=b.asm.Ms).apply(null,arguments)},av=b._emscripten_bind_btVehicleRaycasterResult___destroy___0=function(){return(av=b._emscripten_bind_btVehicleRaycasterResult___destroy___0=b.asm.Ns).apply(null,arguments)},bv=b._emscripten_bind_btDefaultVehicleRaycaster_btDefaultVehicleRaycaster_1=function(){return(bv=b._emscripten_bind_btDefaultVehicleRaycaster_btDefaultVehicleRaycaster_1=
|
||||
b.asm.Os).apply(null,arguments)},cv=b._emscripten_bind_btDefaultVehicleRaycaster_castRay_3=function(){return(cv=b._emscripten_bind_btDefaultVehicleRaycaster_castRay_3=b.asm.Ps).apply(null,arguments)},dv=b._emscripten_bind_btDefaultVehicleRaycaster___destroy___0=function(){return(dv=b._emscripten_bind_btDefaultVehicleRaycaster___destroy___0=b.asm.Qs).apply(null,arguments)},ev=b._emscripten_bind_RaycastInfo_get_m_contactNormalWS_0=function(){return(ev=b._emscripten_bind_RaycastInfo_get_m_contactNormalWS_0=
|
||||
b.asm.Rs).apply(null,arguments)},fv=b._emscripten_bind_RaycastInfo_set_m_contactNormalWS_1=function(){return(fv=b._emscripten_bind_RaycastInfo_set_m_contactNormalWS_1=b.asm.Ss).apply(null,arguments)},gv=b._emscripten_bind_RaycastInfo_get_m_contactPointWS_0=function(){return(gv=b._emscripten_bind_RaycastInfo_get_m_contactPointWS_0=b.asm.Ts).apply(null,arguments)},hv=b._emscripten_bind_RaycastInfo_set_m_contactPointWS_1=function(){return(hv=b._emscripten_bind_RaycastInfo_set_m_contactPointWS_1=b.asm.Us).apply(null,
|
||||
arguments)},iv=b._emscripten_bind_RaycastInfo_get_m_suspensionLength_0=function(){return(iv=b._emscripten_bind_RaycastInfo_get_m_suspensionLength_0=b.asm.Vs).apply(null,arguments)},jv=b._emscripten_bind_RaycastInfo_set_m_suspensionLength_1=function(){return(jv=b._emscripten_bind_RaycastInfo_set_m_suspensionLength_1=b.asm.Ws).apply(null,arguments)},kv=b._emscripten_bind_RaycastInfo_get_m_hardPointWS_0=function(){return(kv=b._emscripten_bind_RaycastInfo_get_m_hardPointWS_0=b.asm.Xs).apply(null,arguments)},
|
||||
lv=b._emscripten_bind_RaycastInfo_set_m_hardPointWS_1=function(){return(lv=b._emscripten_bind_RaycastInfo_set_m_hardPointWS_1=b.asm.Ys).apply(null,arguments)},mv=b._emscripten_bind_RaycastInfo_get_m_wheelDirectionWS_0=function(){return(mv=b._emscripten_bind_RaycastInfo_get_m_wheelDirectionWS_0=b.asm.Zs).apply(null,arguments)},nv=b._emscripten_bind_RaycastInfo_set_m_wheelDirectionWS_1=function(){return(nv=b._emscripten_bind_RaycastInfo_set_m_wheelDirectionWS_1=b.asm._s).apply(null,arguments)},ov=b._emscripten_bind_RaycastInfo_get_m_wheelAxleWS_0=
|
||||
function(){return(ov=b._emscripten_bind_RaycastInfo_get_m_wheelAxleWS_0=b.asm.$s).apply(null,arguments)},pv=b._emscripten_bind_RaycastInfo_set_m_wheelAxleWS_1=function(){return(pv=b._emscripten_bind_RaycastInfo_set_m_wheelAxleWS_1=b.asm.at).apply(null,arguments)},qv=b._emscripten_bind_RaycastInfo_get_m_isInContact_0=function(){return(qv=b._emscripten_bind_RaycastInfo_get_m_isInContact_0=b.asm.bt).apply(null,arguments)},rv=b._emscripten_bind_RaycastInfo_set_m_isInContact_1=function(){return(rv=b._emscripten_bind_RaycastInfo_set_m_isInContact_1=
|
||||
b.asm.ct).apply(null,arguments)},sv=b._emscripten_bind_RaycastInfo_get_m_groundObject_0=function(){return(sv=b._emscripten_bind_RaycastInfo_get_m_groundObject_0=b.asm.dt).apply(null,arguments)},tv=b._emscripten_bind_RaycastInfo_set_m_groundObject_1=function(){return(tv=b._emscripten_bind_RaycastInfo_set_m_groundObject_1=b.asm.et).apply(null,arguments)},uv=b._emscripten_bind_RaycastInfo___destroy___0=function(){return(uv=b._emscripten_bind_RaycastInfo___destroy___0=b.asm.ft).apply(null,arguments)},
|
||||
vv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_chassisConnectionCS_0=function(){return(vv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_chassisConnectionCS_0=b.asm.gt).apply(null,arguments)},wv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_chassisConnectionCS_1=function(){return(wv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_chassisConnectionCS_1=b.asm.ht).apply(null,arguments)},xv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelDirectionCS_0=function(){return(xv=
|
||||
b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelDirectionCS_0=b.asm.it).apply(null,arguments)},yv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelDirectionCS_1=function(){return(yv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelDirectionCS_1=b.asm.jt).apply(null,arguments)},zv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelAxleCS_0=function(){return(zv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelAxleCS_0=b.asm.kt).apply(null,arguments)},Av=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelAxleCS_1=
|
||||
function(){return(Av=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelAxleCS_1=b.asm.lt).apply(null,arguments)},Bv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionRestLength_0=function(){return(Bv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionRestLength_0=b.asm.mt).apply(null,arguments)},Cv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionRestLength_1=function(){return(Cv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionRestLength_1=
|
||||
b.asm.nt).apply(null,arguments)},Dv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionTravelCm_0=function(){return(Dv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionTravelCm_0=b.asm.ot).apply(null,arguments)},Ev=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionTravelCm_1=function(){return(Ev=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionTravelCm_1=b.asm.pt).apply(null,arguments)},Fv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelRadius_0=
|
||||
function(){return(Fv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelRadius_0=b.asm.qt).apply(null,arguments)},Gv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelRadius_1=function(){return(Gv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelRadius_1=b.asm.rt).apply(null,arguments)},Hv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionStiffness_0=function(){return(Hv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionStiffness_0=b.asm.st).apply(null,
|
||||
arguments)},Iv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionStiffness_1=function(){return(Iv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionStiffness_1=b.asm.tt).apply(null,arguments)},Jv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingCompression_0=function(){return(Jv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingCompression_0=b.asm.ut).apply(null,arguments)},Kv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingCompression_1=
|
||||
function(){return(Kv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingCompression_1=b.asm.vt).apply(null,arguments)},Lv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingRelaxation_0=function(){return(Lv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingRelaxation_0=b.asm.wt).apply(null,arguments)},Mv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingRelaxation_1=function(){return(Mv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingRelaxation_1=
|
||||
b.asm.xt).apply(null,arguments)},Nv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_frictionSlip_0=function(){return(Nv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_frictionSlip_0=b.asm.yt).apply(null,arguments)},Ov=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_frictionSlip_1=function(){return(Ov=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_frictionSlip_1=b.asm.zt).apply(null,arguments)},Pv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionForce_0=function(){return(Pv=
|
||||
b._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionForce_0=b.asm.At).apply(null,arguments)},Qv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionForce_1=function(){return(Qv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionForce_1=b.asm.Bt).apply(null,arguments)},Rv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_bIsFrontWheel_0=function(){return(Rv=b._emscripten_bind_btWheelInfoConstructionInfo_get_m_bIsFrontWheel_0=b.asm.Ct).apply(null,arguments)},
|
||||
Sv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_bIsFrontWheel_1=function(){return(Sv=b._emscripten_bind_btWheelInfoConstructionInfo_set_m_bIsFrontWheel_1=b.asm.Dt).apply(null,arguments)},Tv=b._emscripten_bind_btWheelInfoConstructionInfo___destroy___0=function(){return(Tv=b._emscripten_bind_btWheelInfoConstructionInfo___destroy___0=b.asm.Et).apply(null,arguments)},Uv=b._emscripten_bind_btWheelInfo_btWheelInfo_1=function(){return(Uv=b._emscripten_bind_btWheelInfo_btWheelInfo_1=b.asm.Ft).apply(null,
|
||||
arguments)},Vv=b._emscripten_bind_btWheelInfo_getSuspensionRestLength_0=function(){return(Vv=b._emscripten_bind_btWheelInfo_getSuspensionRestLength_0=b.asm.Gt).apply(null,arguments)},Wv=b._emscripten_bind_btWheelInfo_updateWheel_2=function(){return(Wv=b._emscripten_bind_btWheelInfo_updateWheel_2=b.asm.Ht).apply(null,arguments)},Xv=b._emscripten_bind_btWheelInfo_get_m_suspensionStiffness_0=function(){return(Xv=b._emscripten_bind_btWheelInfo_get_m_suspensionStiffness_0=b.asm.It).apply(null,arguments)},
|
||||
Yv=b._emscripten_bind_btWheelInfo_set_m_suspensionStiffness_1=function(){return(Yv=b._emscripten_bind_btWheelInfo_set_m_suspensionStiffness_1=b.asm.Jt).apply(null,arguments)},Zv=b._emscripten_bind_btWheelInfo_get_m_frictionSlip_0=function(){return(Zv=b._emscripten_bind_btWheelInfo_get_m_frictionSlip_0=b.asm.Kt).apply(null,arguments)},$v=b._emscripten_bind_btWheelInfo_set_m_frictionSlip_1=function(){return($v=b._emscripten_bind_btWheelInfo_set_m_frictionSlip_1=b.asm.Lt).apply(null,arguments)},aw=b._emscripten_bind_btWheelInfo_get_m_engineForce_0=
|
||||
function(){return(aw=b._emscripten_bind_btWheelInfo_get_m_engineForce_0=b.asm.Mt).apply(null,arguments)},bw=b._emscripten_bind_btWheelInfo_set_m_engineForce_1=function(){return(bw=b._emscripten_bind_btWheelInfo_set_m_engineForce_1=b.asm.Nt).apply(null,arguments)},cw=b._emscripten_bind_btWheelInfo_get_m_rollInfluence_0=function(){return(cw=b._emscripten_bind_btWheelInfo_get_m_rollInfluence_0=b.asm.Ot).apply(null,arguments)},dw=b._emscripten_bind_btWheelInfo_set_m_rollInfluence_1=function(){return(dw=
|
||||
b._emscripten_bind_btWheelInfo_set_m_rollInfluence_1=b.asm.Pt).apply(null,arguments)},ew=b._emscripten_bind_btWheelInfo_get_m_suspensionRestLength1_0=function(){return(ew=b._emscripten_bind_btWheelInfo_get_m_suspensionRestLength1_0=b.asm.Qt).apply(null,arguments)},fw=b._emscripten_bind_btWheelInfo_set_m_suspensionRestLength1_1=function(){return(fw=b._emscripten_bind_btWheelInfo_set_m_suspensionRestLength1_1=b.asm.Rt).apply(null,arguments)},gw=b._emscripten_bind_btWheelInfo_get_m_wheelsRadius_0=function(){return(gw=
|
||||
b._emscripten_bind_btWheelInfo_get_m_wheelsRadius_0=b.asm.St).apply(null,arguments)},hw=b._emscripten_bind_btWheelInfo_set_m_wheelsRadius_1=function(){return(hw=b._emscripten_bind_btWheelInfo_set_m_wheelsRadius_1=b.asm.Tt).apply(null,arguments)},iw=b._emscripten_bind_btWheelInfo_get_m_wheelsDampingCompression_0=function(){return(iw=b._emscripten_bind_btWheelInfo_get_m_wheelsDampingCompression_0=b.asm.Ut).apply(null,arguments)},jw=b._emscripten_bind_btWheelInfo_set_m_wheelsDampingCompression_1=function(){return(jw=
|
||||
b._emscripten_bind_btWheelInfo_set_m_wheelsDampingCompression_1=b.asm.Vt).apply(null,arguments)},kw=b._emscripten_bind_btWheelInfo_get_m_wheelsDampingRelaxation_0=function(){return(kw=b._emscripten_bind_btWheelInfo_get_m_wheelsDampingRelaxation_0=b.asm.Wt).apply(null,arguments)},lw=b._emscripten_bind_btWheelInfo_set_m_wheelsDampingRelaxation_1=function(){return(lw=b._emscripten_bind_btWheelInfo_set_m_wheelsDampingRelaxation_1=b.asm.Xt).apply(null,arguments)},mw=b._emscripten_bind_btWheelInfo_get_m_steering_0=
|
||||
function(){return(mw=b._emscripten_bind_btWheelInfo_get_m_steering_0=b.asm.Yt).apply(null,arguments)},nw=b._emscripten_bind_btWheelInfo_set_m_steering_1=function(){return(nw=b._emscripten_bind_btWheelInfo_set_m_steering_1=b.asm.Zt).apply(null,arguments)},ow=b._emscripten_bind_btWheelInfo_get_m_maxSuspensionForce_0=function(){return(ow=b._emscripten_bind_btWheelInfo_get_m_maxSuspensionForce_0=b.asm._t).apply(null,arguments)},pw=b._emscripten_bind_btWheelInfo_set_m_maxSuspensionForce_1=function(){return(pw=
|
||||
b._emscripten_bind_btWheelInfo_set_m_maxSuspensionForce_1=b.asm.$t).apply(null,arguments)},qw=b._emscripten_bind_btWheelInfo_get_m_maxSuspensionTravelCm_0=function(){return(qw=b._emscripten_bind_btWheelInfo_get_m_maxSuspensionTravelCm_0=b.asm.au).apply(null,arguments)},rw=b._emscripten_bind_btWheelInfo_set_m_maxSuspensionTravelCm_1=function(){return(rw=b._emscripten_bind_btWheelInfo_set_m_maxSuspensionTravelCm_1=b.asm.bu).apply(null,arguments)},sw=b._emscripten_bind_btWheelInfo_get_m_wheelsSuspensionForce_0=
|
||||
function(){return(sw=b._emscripten_bind_btWheelInfo_get_m_wheelsSuspensionForce_0=b.asm.cu).apply(null,arguments)},tw=b._emscripten_bind_btWheelInfo_set_m_wheelsSuspensionForce_1=function(){return(tw=b._emscripten_bind_btWheelInfo_set_m_wheelsSuspensionForce_1=b.asm.du).apply(null,arguments)},uw=b._emscripten_bind_btWheelInfo_get_m_bIsFrontWheel_0=function(){return(uw=b._emscripten_bind_btWheelInfo_get_m_bIsFrontWheel_0=b.asm.eu).apply(null,arguments)},vw=b._emscripten_bind_btWheelInfo_set_m_bIsFrontWheel_1=
|
||||
function(){return(vw=b._emscripten_bind_btWheelInfo_set_m_bIsFrontWheel_1=b.asm.fu).apply(null,arguments)},ww=b._emscripten_bind_btWheelInfo_get_m_raycastInfo_0=function(){return(ww=b._emscripten_bind_btWheelInfo_get_m_raycastInfo_0=b.asm.gu).apply(null,arguments)},xw=b._emscripten_bind_btWheelInfo_set_m_raycastInfo_1=function(){return(xw=b._emscripten_bind_btWheelInfo_set_m_raycastInfo_1=b.asm.hu).apply(null,arguments)},yw=b._emscripten_bind_btWheelInfo_get_m_chassisConnectionPointCS_0=function(){return(yw=
|
||||
b._emscripten_bind_btWheelInfo_get_m_chassisConnectionPointCS_0=b.asm.iu).apply(null,arguments)},zw=b._emscripten_bind_btWheelInfo_set_m_chassisConnectionPointCS_1=function(){return(zw=b._emscripten_bind_btWheelInfo_set_m_chassisConnectionPointCS_1=b.asm.ju).apply(null,arguments)},Aw=b._emscripten_bind_btWheelInfo_get_m_worldTransform_0=function(){return(Aw=b._emscripten_bind_btWheelInfo_get_m_worldTransform_0=b.asm.ku).apply(null,arguments)},Bw=b._emscripten_bind_btWheelInfo_set_m_worldTransform_1=
|
||||
function(){return(Bw=b._emscripten_bind_btWheelInfo_set_m_worldTransform_1=b.asm.lu).apply(null,arguments)},Cw=b._emscripten_bind_btWheelInfo_get_m_wheelDirectionCS_0=function(){return(Cw=b._emscripten_bind_btWheelInfo_get_m_wheelDirectionCS_0=b.asm.mu).apply(null,arguments)},Dw=b._emscripten_bind_btWheelInfo_set_m_wheelDirectionCS_1=function(){return(Dw=b._emscripten_bind_btWheelInfo_set_m_wheelDirectionCS_1=b.asm.nu).apply(null,arguments)},Ew=b._emscripten_bind_btWheelInfo_get_m_wheelAxleCS_0=function(){return(Ew=
|
||||
b._emscripten_bind_btWheelInfo_get_m_wheelAxleCS_0=b.asm.ou).apply(null,arguments)},Fw=b._emscripten_bind_btWheelInfo_set_m_wheelAxleCS_1=function(){return(Fw=b._emscripten_bind_btWheelInfo_set_m_wheelAxleCS_1=b.asm.pu).apply(null,arguments)},Gw=b._emscripten_bind_btWheelInfo_get_m_rotation_0=function(){return(Gw=b._emscripten_bind_btWheelInfo_get_m_rotation_0=b.asm.qu).apply(null,arguments)},Hw=b._emscripten_bind_btWheelInfo_set_m_rotation_1=function(){return(Hw=b._emscripten_bind_btWheelInfo_set_m_rotation_1=
|
||||
b.asm.ru).apply(null,arguments)},Iw=b._emscripten_bind_btWheelInfo_get_m_deltaRotation_0=function(){return(Iw=b._emscripten_bind_btWheelInfo_get_m_deltaRotation_0=b.asm.su).apply(null,arguments)},Jw=b._emscripten_bind_btWheelInfo_set_m_deltaRotation_1=function(){return(Jw=b._emscripten_bind_btWheelInfo_set_m_deltaRotation_1=b.asm.tu).apply(null,arguments)},Kw=b._emscripten_bind_btWheelInfo_get_m_brake_0=function(){return(Kw=b._emscripten_bind_btWheelInfo_get_m_brake_0=b.asm.uu).apply(null,arguments)},
|
||||
Lw=b._emscripten_bind_btWheelInfo_set_m_brake_1=function(){return(Lw=b._emscripten_bind_btWheelInfo_set_m_brake_1=b.asm.vu).apply(null,arguments)},Mw=b._emscripten_bind_btWheelInfo_get_m_clippedInvContactDotSuspension_0=function(){return(Mw=b._emscripten_bind_btWheelInfo_get_m_clippedInvContactDotSuspension_0=b.asm.wu).apply(null,arguments)},Nw=b._emscripten_bind_btWheelInfo_set_m_clippedInvContactDotSuspension_1=function(){return(Nw=b._emscripten_bind_btWheelInfo_set_m_clippedInvContactDotSuspension_1=
|
||||
b.asm.xu).apply(null,arguments)},Ow=b._emscripten_bind_btWheelInfo_get_m_suspensionRelativeVelocity_0=function(){return(Ow=b._emscripten_bind_btWheelInfo_get_m_suspensionRelativeVelocity_0=b.asm.yu).apply(null,arguments)},Pw=b._emscripten_bind_btWheelInfo_set_m_suspensionRelativeVelocity_1=function(){return(Pw=b._emscripten_bind_btWheelInfo_set_m_suspensionRelativeVelocity_1=b.asm.zu).apply(null,arguments)},Qw=b._emscripten_bind_btWheelInfo_get_m_skidInfo_0=function(){return(Qw=b._emscripten_bind_btWheelInfo_get_m_skidInfo_0=
|
||||
b.asm.Au).apply(null,arguments)},Rw=b._emscripten_bind_btWheelInfo_set_m_skidInfo_1=function(){return(Rw=b._emscripten_bind_btWheelInfo_set_m_skidInfo_1=b.asm.Bu).apply(null,arguments)},Sw=b._emscripten_bind_btWheelInfo___destroy___0=function(){return(Sw=b._emscripten_bind_btWheelInfo___destroy___0=b.asm.Cu).apply(null,arguments)},Tw=b._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_3=function(){return(Tw=b._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_3=
|
||||
b.asm.Du).apply(null,arguments)},Uw=b._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_4=function(){return(Uw=b._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_4=b.asm.Eu).apply(null,arguments)},Vw=b._emscripten_bind_btKinematicCharacterController_setUpAxis_1=function(){return(Vw=b._emscripten_bind_btKinematicCharacterController_setUpAxis_1=b.asm.Fu).apply(null,arguments)},Ww=b._emscripten_bind_btKinematicCharacterController_setWalkDirection_1=
|
||||
function(){return(Ww=b._emscripten_bind_btKinematicCharacterController_setWalkDirection_1=b.asm.Gu).apply(null,arguments)},Xw=b._emscripten_bind_btKinematicCharacterController_setVelocityForTimeInterval_2=function(){return(Xw=b._emscripten_bind_btKinematicCharacterController_setVelocityForTimeInterval_2=b.asm.Hu).apply(null,arguments)},Yw=b._emscripten_bind_btKinematicCharacterController_warp_1=function(){return(Yw=b._emscripten_bind_btKinematicCharacterController_warp_1=b.asm.Iu).apply(null,arguments)},
|
||||
Zw=b._emscripten_bind_btKinematicCharacterController_preStep_1=function(){return(Zw=b._emscripten_bind_btKinematicCharacterController_preStep_1=b.asm.Ju).apply(null,arguments)},$w=b._emscripten_bind_btKinematicCharacterController_playerStep_2=function(){return($w=b._emscripten_bind_btKinematicCharacterController_playerStep_2=b.asm.Ku).apply(null,arguments)},ax=b._emscripten_bind_btKinematicCharacterController_setFallSpeed_1=function(){return(ax=b._emscripten_bind_btKinematicCharacterController_setFallSpeed_1=
|
||||
b.asm.Lu).apply(null,arguments)},bx=b._emscripten_bind_btKinematicCharacterController_setJumpSpeed_1=function(){return(bx=b._emscripten_bind_btKinematicCharacterController_setJumpSpeed_1=b.asm.Mu).apply(null,arguments)},cx=b._emscripten_bind_btKinematicCharacterController_setMaxJumpHeight_1=function(){return(cx=b._emscripten_bind_btKinematicCharacterController_setMaxJumpHeight_1=b.asm.Nu).apply(null,arguments)},dx=b._emscripten_bind_btKinematicCharacterController_canJump_0=function(){return(dx=b._emscripten_bind_btKinematicCharacterController_canJump_0=
|
||||
b.asm.Ou).apply(null,arguments)},ex=b._emscripten_bind_btKinematicCharacterController_jump_0=function(){return(ex=b._emscripten_bind_btKinematicCharacterController_jump_0=b.asm.Pu).apply(null,arguments)},fx=b._emscripten_bind_btKinematicCharacterController_setGravity_1=function(){return(fx=b._emscripten_bind_btKinematicCharacterController_setGravity_1=b.asm.Qu).apply(null,arguments)},gx=b._emscripten_bind_btKinematicCharacterController_getGravity_0=function(){return(gx=b._emscripten_bind_btKinematicCharacterController_getGravity_0=
|
||||
b.asm.Ru).apply(null,arguments)},hx=b._emscripten_bind_btKinematicCharacterController_setMaxSlope_1=function(){return(hx=b._emscripten_bind_btKinematicCharacterController_setMaxSlope_1=b.asm.Su).apply(null,arguments)},ix=b._emscripten_bind_btKinematicCharacterController_getMaxSlope_0=function(){return(ix=b._emscripten_bind_btKinematicCharacterController_getMaxSlope_0=b.asm.Tu).apply(null,arguments)},jx=b._emscripten_bind_btKinematicCharacterController_getGhostObject_0=function(){return(jx=b._emscripten_bind_btKinematicCharacterController_getGhostObject_0=
|
||||
b.asm.Uu).apply(null,arguments)},kx=b._emscripten_bind_btKinematicCharacterController_setUseGhostSweepTest_1=function(){return(kx=b._emscripten_bind_btKinematicCharacterController_setUseGhostSweepTest_1=b.asm.Vu).apply(null,arguments)},lx=b._emscripten_bind_btKinematicCharacterController_onGround_0=function(){return(lx=b._emscripten_bind_btKinematicCharacterController_onGround_0=b.asm.Wu).apply(null,arguments)},mx=b._emscripten_bind_btKinematicCharacterController_setUpInterpolate_1=function(){return(mx=
|
||||
b._emscripten_bind_btKinematicCharacterController_setUpInterpolate_1=b.asm.Xu).apply(null,arguments)},nx=b._emscripten_bind_btKinematicCharacterController_updateAction_2=function(){return(nx=b._emscripten_bind_btKinematicCharacterController_updateAction_2=b.asm.Yu).apply(null,arguments)},ox=b._emscripten_bind_btKinematicCharacterController___destroy___0=function(){return(ox=b._emscripten_bind_btKinematicCharacterController___destroy___0=b.asm.Zu).apply(null,arguments)},px=b._emscripten_bind_btRaycastVehicle_btRaycastVehicle_3=
|
||||
function(){return(px=b._emscripten_bind_btRaycastVehicle_btRaycastVehicle_3=b.asm._u).apply(null,arguments)},qx=b._emscripten_bind_btRaycastVehicle_applyEngineForce_2=function(){return(qx=b._emscripten_bind_btRaycastVehicle_applyEngineForce_2=b.asm.$u).apply(null,arguments)},rx=b._emscripten_bind_btRaycastVehicle_setSteeringValue_2=function(){return(rx=b._emscripten_bind_btRaycastVehicle_setSteeringValue_2=b.asm.av).apply(null,arguments)},sx=b._emscripten_bind_btRaycastVehicle_getWheelTransformWS_1=
|
||||
function(){return(sx=b._emscripten_bind_btRaycastVehicle_getWheelTransformWS_1=b.asm.bv).apply(null,arguments)},tx=b._emscripten_bind_btRaycastVehicle_updateWheelTransform_2=function(){return(tx=b._emscripten_bind_btRaycastVehicle_updateWheelTransform_2=b.asm.cv).apply(null,arguments)},ux=b._emscripten_bind_btRaycastVehicle_addWheel_7=function(){return(ux=b._emscripten_bind_btRaycastVehicle_addWheel_7=b.asm.dv).apply(null,arguments)},vx=b._emscripten_bind_btRaycastVehicle_getNumWheels_0=function(){return(vx=
|
||||
b._emscripten_bind_btRaycastVehicle_getNumWheels_0=b.asm.ev).apply(null,arguments)},wx=b._emscripten_bind_btRaycastVehicle_getRigidBody_0=function(){return(wx=b._emscripten_bind_btRaycastVehicle_getRigidBody_0=b.asm.fv).apply(null,arguments)},xx=b._emscripten_bind_btRaycastVehicle_getWheelInfo_1=function(){return(xx=b._emscripten_bind_btRaycastVehicle_getWheelInfo_1=b.asm.gv).apply(null,arguments)},yx=b._emscripten_bind_btRaycastVehicle_setBrake_2=function(){return(yx=b._emscripten_bind_btRaycastVehicle_setBrake_2=
|
||||
b.asm.hv).apply(null,arguments)},zx=b._emscripten_bind_btRaycastVehicle_setCoordinateSystem_3=function(){return(zx=b._emscripten_bind_btRaycastVehicle_setCoordinateSystem_3=b.asm.iv).apply(null,arguments)},Ax=b._emscripten_bind_btRaycastVehicle_getCurrentSpeedKmHour_0=function(){return(Ax=b._emscripten_bind_btRaycastVehicle_getCurrentSpeedKmHour_0=b.asm.jv).apply(null,arguments)},Bx=b._emscripten_bind_btRaycastVehicle_getChassisWorldTransform_0=function(){return(Bx=b._emscripten_bind_btRaycastVehicle_getChassisWorldTransform_0=
|
||||
b.asm.kv).apply(null,arguments)},Cx=b._emscripten_bind_btRaycastVehicle_rayCast_1=function(){return(Cx=b._emscripten_bind_btRaycastVehicle_rayCast_1=b.asm.lv).apply(null,arguments)},Dx=b._emscripten_bind_btRaycastVehicle_updateVehicle_1=function(){return(Dx=b._emscripten_bind_btRaycastVehicle_updateVehicle_1=b.asm.mv).apply(null,arguments)},Ex=b._emscripten_bind_btRaycastVehicle_resetSuspension_0=function(){return(Ex=b._emscripten_bind_btRaycastVehicle_resetSuspension_0=b.asm.nv).apply(null,arguments)},
|
||||
Fx=b._emscripten_bind_btRaycastVehicle_getSteeringValue_1=function(){return(Fx=b._emscripten_bind_btRaycastVehicle_getSteeringValue_1=b.asm.ov).apply(null,arguments)},Gx=b._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_1=function(){return(Gx=b._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_1=b.asm.pv).apply(null,arguments)},Hx=b._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_2=function(){return(Hx=b._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_2=b.asm.qv).apply(null,
|
||||
arguments)},Ix=b._emscripten_bind_btRaycastVehicle_setPitchControl_1=function(){return(Ix=b._emscripten_bind_btRaycastVehicle_setPitchControl_1=b.asm.rv).apply(null,arguments)},Jx=b._emscripten_bind_btRaycastVehicle_updateSuspension_1=function(){return(Jx=b._emscripten_bind_btRaycastVehicle_updateSuspension_1=b.asm.sv).apply(null,arguments)},Kx=b._emscripten_bind_btRaycastVehicle_updateFriction_1=function(){return(Kx=b._emscripten_bind_btRaycastVehicle_updateFriction_1=b.asm.tv).apply(null,arguments)},
|
||||
Lx=b._emscripten_bind_btRaycastVehicle_getRightAxis_0=function(){return(Lx=b._emscripten_bind_btRaycastVehicle_getRightAxis_0=b.asm.uv).apply(null,arguments)},Mx=b._emscripten_bind_btRaycastVehicle_getUpAxis_0=function(){return(Mx=b._emscripten_bind_btRaycastVehicle_getUpAxis_0=b.asm.vv).apply(null,arguments)},Nx=b._emscripten_bind_btRaycastVehicle_getForwardAxis_0=function(){return(Nx=b._emscripten_bind_btRaycastVehicle_getForwardAxis_0=b.asm.wv).apply(null,arguments)},Ox=b._emscripten_bind_btRaycastVehicle_getForwardVector_0=
|
||||
function(){return(Ox=b._emscripten_bind_btRaycastVehicle_getForwardVector_0=b.asm.xv).apply(null,arguments)},Px=b._emscripten_bind_btRaycastVehicle_getUserConstraintType_0=function(){return(Px=b._emscripten_bind_btRaycastVehicle_getUserConstraintType_0=b.asm.yv).apply(null,arguments)},Qx=b._emscripten_bind_btRaycastVehicle_setUserConstraintType_1=function(){return(Qx=b._emscripten_bind_btRaycastVehicle_setUserConstraintType_1=b.asm.zv).apply(null,arguments)},Rx=b._emscripten_bind_btRaycastVehicle_setUserConstraintId_1=
|
||||
function(){return(Rx=b._emscripten_bind_btRaycastVehicle_setUserConstraintId_1=b.asm.Av).apply(null,arguments)},Sx=b._emscripten_bind_btRaycastVehicle_getUserConstraintId_0=function(){return(Sx=b._emscripten_bind_btRaycastVehicle_getUserConstraintId_0=b.asm.Bv).apply(null,arguments)},Tx=b._emscripten_bind_btRaycastVehicle_updateAction_2=function(){return(Tx=b._emscripten_bind_btRaycastVehicle_updateAction_2=b.asm.Cv).apply(null,arguments)},Ux=b._emscripten_bind_btRaycastVehicle___destroy___0=function(){return(Ux=
|
||||
b._emscripten_bind_btRaycastVehicle___destroy___0=b.asm.Dv).apply(null,arguments)},Vx=b._emscripten_bind_btPairCachingGhostObject_btPairCachingGhostObject_0=function(){return(Vx=b._emscripten_bind_btPairCachingGhostObject_btPairCachingGhostObject_0=b.asm.Ev).apply(null,arguments)},Wx=b._emscripten_bind_btPairCachingGhostObject_setAnisotropicFriction_2=function(){return(Wx=b._emscripten_bind_btPairCachingGhostObject_setAnisotropicFriction_2=b.asm.Fv).apply(null,arguments)},Xx=b._emscripten_bind_btPairCachingGhostObject_getCollisionShape_0=
|
||||
function(){return(Xx=b._emscripten_bind_btPairCachingGhostObject_getCollisionShape_0=b.asm.Gv).apply(null,arguments)},Yx=b._emscripten_bind_btPairCachingGhostObject_setContactProcessingThreshold_1=function(){return(Yx=b._emscripten_bind_btPairCachingGhostObject_setContactProcessingThreshold_1=b.asm.Hv).apply(null,arguments)},Zx=b._emscripten_bind_btPairCachingGhostObject_setActivationState_1=function(){return(Zx=b._emscripten_bind_btPairCachingGhostObject_setActivationState_1=b.asm.Iv).apply(null,
|
||||
arguments)},$x=b._emscripten_bind_btPairCachingGhostObject_forceActivationState_1=function(){return($x=b._emscripten_bind_btPairCachingGhostObject_forceActivationState_1=b.asm.Jv).apply(null,arguments)},ay=b._emscripten_bind_btPairCachingGhostObject_activate_0=function(){return(ay=b._emscripten_bind_btPairCachingGhostObject_activate_0=b.asm.Kv).apply(null,arguments)},by=b._emscripten_bind_btPairCachingGhostObject_activate_1=function(){return(by=b._emscripten_bind_btPairCachingGhostObject_activate_1=
|
||||
b.asm.Lv).apply(null,arguments)},cy=b._emscripten_bind_btPairCachingGhostObject_isActive_0=function(){return(cy=b._emscripten_bind_btPairCachingGhostObject_isActive_0=b.asm.Mv).apply(null,arguments)},dy=b._emscripten_bind_btPairCachingGhostObject_isKinematicObject_0=function(){return(dy=b._emscripten_bind_btPairCachingGhostObject_isKinematicObject_0=b.asm.Nv).apply(null,arguments)},ey=b._emscripten_bind_btPairCachingGhostObject_isStaticObject_0=function(){return(ey=b._emscripten_bind_btPairCachingGhostObject_isStaticObject_0=
|
||||
b.asm.Ov).apply(null,arguments)},fy=b._emscripten_bind_btPairCachingGhostObject_isStaticOrKinematicObject_0=function(){return(fy=b._emscripten_bind_btPairCachingGhostObject_isStaticOrKinematicObject_0=b.asm.Pv).apply(null,arguments)},gy=b._emscripten_bind_btPairCachingGhostObject_getRestitution_0=function(){return(gy=b._emscripten_bind_btPairCachingGhostObject_getRestitution_0=b.asm.Qv).apply(null,arguments)},hy=b._emscripten_bind_btPairCachingGhostObject_getFriction_0=function(){return(hy=b._emscripten_bind_btPairCachingGhostObject_getFriction_0=
|
||||
b.asm.Rv).apply(null,arguments)},iy=b._emscripten_bind_btPairCachingGhostObject_getRollingFriction_0=function(){return(iy=b._emscripten_bind_btPairCachingGhostObject_getRollingFriction_0=b.asm.Sv).apply(null,arguments)},jy=b._emscripten_bind_btPairCachingGhostObject_setRestitution_1=function(){return(jy=b._emscripten_bind_btPairCachingGhostObject_setRestitution_1=b.asm.Tv).apply(null,arguments)},ky=b._emscripten_bind_btPairCachingGhostObject_setFriction_1=function(){return(ky=b._emscripten_bind_btPairCachingGhostObject_setFriction_1=
|
||||
b.asm.Uv).apply(null,arguments)},ly=b._emscripten_bind_btPairCachingGhostObject_setRollingFriction_1=function(){return(ly=b._emscripten_bind_btPairCachingGhostObject_setRollingFriction_1=b.asm.Vv).apply(null,arguments)},my=b._emscripten_bind_btPairCachingGhostObject_getWorldTransform_0=function(){return(my=b._emscripten_bind_btPairCachingGhostObject_getWorldTransform_0=b.asm.Wv).apply(null,arguments)},ny=b._emscripten_bind_btPairCachingGhostObject_getCollisionFlags_0=function(){return(ny=b._emscripten_bind_btPairCachingGhostObject_getCollisionFlags_0=
|
||||
b.asm.Xv).apply(null,arguments)},oy=b._emscripten_bind_btPairCachingGhostObject_setCollisionFlags_1=function(){return(oy=b._emscripten_bind_btPairCachingGhostObject_setCollisionFlags_1=b.asm.Yv).apply(null,arguments)},py=b._emscripten_bind_btPairCachingGhostObject_setWorldTransform_1=function(){return(py=b._emscripten_bind_btPairCachingGhostObject_setWorldTransform_1=b.asm.Zv).apply(null,arguments)},qy=b._emscripten_bind_btPairCachingGhostObject_setCollisionShape_1=function(){return(qy=b._emscripten_bind_btPairCachingGhostObject_setCollisionShape_1=
|
||||
b.asm._v).apply(null,arguments)},ry=b._emscripten_bind_btPairCachingGhostObject_setCcdMotionThreshold_1=function(){return(ry=b._emscripten_bind_btPairCachingGhostObject_setCcdMotionThreshold_1=b.asm.$v).apply(null,arguments)},sy=b._emscripten_bind_btPairCachingGhostObject_setCcdSweptSphereRadius_1=function(){return(sy=b._emscripten_bind_btPairCachingGhostObject_setCcdSweptSphereRadius_1=b.asm.aw).apply(null,arguments)},ty=b._emscripten_bind_btPairCachingGhostObject_getUserIndex_0=function(){return(ty=
|
||||
b._emscripten_bind_btPairCachingGhostObject_getUserIndex_0=b.asm.bw).apply(null,arguments)},uy=b._emscripten_bind_btPairCachingGhostObject_setUserIndex_1=function(){return(uy=b._emscripten_bind_btPairCachingGhostObject_setUserIndex_1=b.asm.cw).apply(null,arguments)},vy=b._emscripten_bind_btPairCachingGhostObject_getUserPointer_0=function(){return(vy=b._emscripten_bind_btPairCachingGhostObject_getUserPointer_0=b.asm.dw).apply(null,arguments)},wy=b._emscripten_bind_btPairCachingGhostObject_setUserPointer_1=
|
||||
function(){return(wy=b._emscripten_bind_btPairCachingGhostObject_setUserPointer_1=b.asm.ew).apply(null,arguments)},xy=b._emscripten_bind_btPairCachingGhostObject_getBroadphaseHandle_0=function(){return(xy=b._emscripten_bind_btPairCachingGhostObject_getBroadphaseHandle_0=b.asm.fw).apply(null,arguments)},yy=b._emscripten_bind_btPairCachingGhostObject_getNumOverlappingObjects_0=function(){return(yy=b._emscripten_bind_btPairCachingGhostObject_getNumOverlappingObjects_0=b.asm.gw).apply(null,arguments)},
|
||||
zy=b._emscripten_bind_btPairCachingGhostObject_getOverlappingObject_1=function(){return(zy=b._emscripten_bind_btPairCachingGhostObject_getOverlappingObject_1=b.asm.hw).apply(null,arguments)},Ay=b._emscripten_bind_btPairCachingGhostObject___destroy___0=function(){return(Ay=b._emscripten_bind_btPairCachingGhostObject___destroy___0=b.asm.iw).apply(null,arguments)},By=b._emscripten_bind_btGhostPairCallback_btGhostPairCallback_0=function(){return(By=b._emscripten_bind_btGhostPairCallback_btGhostPairCallback_0=
|
||||
b.asm.jw).apply(null,arguments)},Cy=b._emscripten_bind_btGhostPairCallback___destroy___0=function(){return(Cy=b._emscripten_bind_btGhostPairCallback___destroy___0=b.asm.kw).apply(null,arguments)},Dy=b._emscripten_bind_btSoftBodyWorldInfo_btSoftBodyWorldInfo_0=function(){return(Dy=b._emscripten_bind_btSoftBodyWorldInfo_btSoftBodyWorldInfo_0=b.asm.lw).apply(null,arguments)},Ey=b._emscripten_bind_btSoftBodyWorldInfo_get_air_density_0=function(){return(Ey=b._emscripten_bind_btSoftBodyWorldInfo_get_air_density_0=
|
||||
b.asm.mw).apply(null,arguments)},Fy=b._emscripten_bind_btSoftBodyWorldInfo_set_air_density_1=function(){return(Fy=b._emscripten_bind_btSoftBodyWorldInfo_set_air_density_1=b.asm.nw).apply(null,arguments)},Gy=b._emscripten_bind_btSoftBodyWorldInfo_get_water_density_0=function(){return(Gy=b._emscripten_bind_btSoftBodyWorldInfo_get_water_density_0=b.asm.ow).apply(null,arguments)},Hy=b._emscripten_bind_btSoftBodyWorldInfo_set_water_density_1=function(){return(Hy=b._emscripten_bind_btSoftBodyWorldInfo_set_water_density_1=
|
||||
b.asm.pw).apply(null,arguments)},Iy=b._emscripten_bind_btSoftBodyWorldInfo_get_water_offset_0=function(){return(Iy=b._emscripten_bind_btSoftBodyWorldInfo_get_water_offset_0=b.asm.qw).apply(null,arguments)},Jy=b._emscripten_bind_btSoftBodyWorldInfo_set_water_offset_1=function(){return(Jy=b._emscripten_bind_btSoftBodyWorldInfo_set_water_offset_1=b.asm.rw).apply(null,arguments)},Ky=b._emscripten_bind_btSoftBodyWorldInfo_get_m_maxDisplacement_0=function(){return(Ky=b._emscripten_bind_btSoftBodyWorldInfo_get_m_maxDisplacement_0=
|
||||
b.asm.sw).apply(null,arguments)},Ly=b._emscripten_bind_btSoftBodyWorldInfo_set_m_maxDisplacement_1=function(){return(Ly=b._emscripten_bind_btSoftBodyWorldInfo_set_m_maxDisplacement_1=b.asm.tw).apply(null,arguments)},My=b._emscripten_bind_btSoftBodyWorldInfo_get_water_normal_0=function(){return(My=b._emscripten_bind_btSoftBodyWorldInfo_get_water_normal_0=b.asm.uw).apply(null,arguments)},Ny=b._emscripten_bind_btSoftBodyWorldInfo_set_water_normal_1=function(){return(Ny=b._emscripten_bind_btSoftBodyWorldInfo_set_water_normal_1=
|
||||
b.asm.vw).apply(null,arguments)},Oy=b._emscripten_bind_btSoftBodyWorldInfo_get_m_broadphase_0=function(){return(Oy=b._emscripten_bind_btSoftBodyWorldInfo_get_m_broadphase_0=b.asm.ww).apply(null,arguments)},Py=b._emscripten_bind_btSoftBodyWorldInfo_set_m_broadphase_1=function(){return(Py=b._emscripten_bind_btSoftBodyWorldInfo_set_m_broadphase_1=b.asm.xw).apply(null,arguments)},Qy=b._emscripten_bind_btSoftBodyWorldInfo_get_m_dispatcher_0=function(){return(Qy=b._emscripten_bind_btSoftBodyWorldInfo_get_m_dispatcher_0=
|
||||
b.asm.yw).apply(null,arguments)},Ry=b._emscripten_bind_btSoftBodyWorldInfo_set_m_dispatcher_1=function(){return(Ry=b._emscripten_bind_btSoftBodyWorldInfo_set_m_dispatcher_1=b.asm.zw).apply(null,arguments)},Sy=b._emscripten_bind_btSoftBodyWorldInfo_get_m_gravity_0=function(){return(Sy=b._emscripten_bind_btSoftBodyWorldInfo_get_m_gravity_0=b.asm.Aw).apply(null,arguments)},Ty=b._emscripten_bind_btSoftBodyWorldInfo_set_m_gravity_1=function(){return(Ty=b._emscripten_bind_btSoftBodyWorldInfo_set_m_gravity_1=
|
||||
b.asm.Bw).apply(null,arguments)},Uy=b._emscripten_bind_btSoftBodyWorldInfo___destroy___0=function(){return(Uy=b._emscripten_bind_btSoftBodyWorldInfo___destroy___0=b.asm.Cw).apply(null,arguments)},Vy=b._emscripten_bind_Face_get_m_n_1=function(){return(Vy=b._emscripten_bind_Face_get_m_n_1=b.asm.Dw).apply(null,arguments)},Wy=b._emscripten_bind_Face_set_m_n_2=function(){return(Wy=b._emscripten_bind_Face_set_m_n_2=b.asm.Ew).apply(null,arguments)},Xy=b._emscripten_bind_Face_get_m_normal_0=function(){return(Xy=
|
||||
b._emscripten_bind_Face_get_m_normal_0=b.asm.Fw).apply(null,arguments)},Yy=b._emscripten_bind_Face_set_m_normal_1=function(){return(Yy=b._emscripten_bind_Face_set_m_normal_1=b.asm.Gw).apply(null,arguments)},Zy=b._emscripten_bind_Face_get_m_ra_0=function(){return(Zy=b._emscripten_bind_Face_get_m_ra_0=b.asm.Hw).apply(null,arguments)},$y=b._emscripten_bind_Face_set_m_ra_1=function(){return($y=b._emscripten_bind_Face_set_m_ra_1=b.asm.Iw).apply(null,arguments)},az=b._emscripten_bind_Face___destroy___0=
|
||||
function(){return(az=b._emscripten_bind_Face___destroy___0=b.asm.Jw).apply(null,arguments)},bz=b._emscripten_bind_tFaceArray_size_0=function(){return(bz=b._emscripten_bind_tFaceArray_size_0=b.asm.Kw).apply(null,arguments)},cz=b._emscripten_bind_tFaceArray_at_1=function(){return(cz=b._emscripten_bind_tFaceArray_at_1=b.asm.Lw).apply(null,arguments)},dz=b._emscripten_bind_tFaceArray___destroy___0=function(){return(dz=b._emscripten_bind_tFaceArray___destroy___0=b.asm.Mw).apply(null,arguments)},ez=b._emscripten_bind_Node_get_m_x_0=
|
||||
function(){return(ez=b._emscripten_bind_Node_get_m_x_0=b.asm.Nw).apply(null,arguments)},fz=b._emscripten_bind_Node_set_m_x_1=function(){return(fz=b._emscripten_bind_Node_set_m_x_1=b.asm.Ow).apply(null,arguments)},gz=b._emscripten_bind_Node_get_m_q_0=function(){return(gz=b._emscripten_bind_Node_get_m_q_0=b.asm.Pw).apply(null,arguments)},hz=b._emscripten_bind_Node_set_m_q_1=function(){return(hz=b._emscripten_bind_Node_set_m_q_1=b.asm.Qw).apply(null,arguments)},iz=b._emscripten_bind_Node_get_m_v_0=function(){return(iz=
|
||||
b._emscripten_bind_Node_get_m_v_0=b.asm.Rw).apply(null,arguments)},jz=b._emscripten_bind_Node_set_m_v_1=function(){return(jz=b._emscripten_bind_Node_set_m_v_1=b.asm.Sw).apply(null,arguments)},kz=b._emscripten_bind_Node_get_m_f_0=function(){return(kz=b._emscripten_bind_Node_get_m_f_0=b.asm.Tw).apply(null,arguments)},lz=b._emscripten_bind_Node_set_m_f_1=function(){return(lz=b._emscripten_bind_Node_set_m_f_1=b.asm.Uw).apply(null,arguments)},mz=b._emscripten_bind_Node_get_m_n_0=function(){return(mz=b._emscripten_bind_Node_get_m_n_0=
|
||||
b.asm.Vw).apply(null,arguments)},nz=b._emscripten_bind_Node_set_m_n_1=function(){return(nz=b._emscripten_bind_Node_set_m_n_1=b.asm.Ww).apply(null,arguments)},oz=b._emscripten_bind_Node_get_m_im_0=function(){return(oz=b._emscripten_bind_Node_get_m_im_0=b.asm.Xw).apply(null,arguments)},pz=b._emscripten_bind_Node_set_m_im_1=function(){return(pz=b._emscripten_bind_Node_set_m_im_1=b.asm.Yw).apply(null,arguments)},qz=b._emscripten_bind_Node_get_m_area_0=function(){return(qz=b._emscripten_bind_Node_get_m_area_0=
|
||||
b.asm.Zw).apply(null,arguments)},rz=b._emscripten_bind_Node_set_m_area_1=function(){return(rz=b._emscripten_bind_Node_set_m_area_1=b.asm._w).apply(null,arguments)},sz=b._emscripten_bind_Node___destroy___0=function(){return(sz=b._emscripten_bind_Node___destroy___0=b.asm.$w).apply(null,arguments)},tz=b._emscripten_bind_tNodeArray_size_0=function(){return(tz=b._emscripten_bind_tNodeArray_size_0=b.asm.ax).apply(null,arguments)},uz=b._emscripten_bind_tNodeArray_at_1=function(){return(uz=b._emscripten_bind_tNodeArray_at_1=
|
||||
b.asm.bx).apply(null,arguments)},vz=b._emscripten_bind_tNodeArray___destroy___0=function(){return(vz=b._emscripten_bind_tNodeArray___destroy___0=b.asm.cx).apply(null,arguments)},wz=b._emscripten_bind_Material_get_m_kLST_0=function(){return(wz=b._emscripten_bind_Material_get_m_kLST_0=b.asm.dx).apply(null,arguments)},xz=b._emscripten_bind_Material_set_m_kLST_1=function(){return(xz=b._emscripten_bind_Material_set_m_kLST_1=b.asm.ex).apply(null,arguments)},yz=b._emscripten_bind_Material_get_m_kAST_0=function(){return(yz=
|
||||
b._emscripten_bind_Material_get_m_kAST_0=b.asm.fx).apply(null,arguments)},zz=b._emscripten_bind_Material_set_m_kAST_1=function(){return(zz=b._emscripten_bind_Material_set_m_kAST_1=b.asm.gx).apply(null,arguments)},Az=b._emscripten_bind_Material_get_m_kVST_0=function(){return(Az=b._emscripten_bind_Material_get_m_kVST_0=b.asm.hx).apply(null,arguments)},Bz=b._emscripten_bind_Material_set_m_kVST_1=function(){return(Bz=b._emscripten_bind_Material_set_m_kVST_1=b.asm.ix).apply(null,arguments)},Cz=b._emscripten_bind_Material_get_m_flags_0=
|
||||
function(){return(Cz=b._emscripten_bind_Material_get_m_flags_0=b.asm.jx).apply(null,arguments)},Dz=b._emscripten_bind_Material_set_m_flags_1=function(){return(Dz=b._emscripten_bind_Material_set_m_flags_1=b.asm.kx).apply(null,arguments)},Ez=b._emscripten_bind_Material___destroy___0=function(){return(Ez=b._emscripten_bind_Material___destroy___0=b.asm.lx).apply(null,arguments)},Fz=b._emscripten_bind_tMaterialArray_size_0=function(){return(Fz=b._emscripten_bind_tMaterialArray_size_0=b.asm.mx).apply(null,
|
||||
arguments)},Gz=b._emscripten_bind_tMaterialArray_at_1=function(){return(Gz=b._emscripten_bind_tMaterialArray_at_1=b.asm.nx).apply(null,arguments)},Hz=b._emscripten_bind_tMaterialArray___destroy___0=function(){return(Hz=b._emscripten_bind_tMaterialArray___destroy___0=b.asm.ox).apply(null,arguments)},Iz=b._emscripten_bind_Anchor_get_m_node_0=function(){return(Iz=b._emscripten_bind_Anchor_get_m_node_0=b.asm.px).apply(null,arguments)},Jz=b._emscripten_bind_Anchor_set_m_node_1=function(){return(Jz=b._emscripten_bind_Anchor_set_m_node_1=
|
||||
b.asm.qx).apply(null,arguments)},Kz=b._emscripten_bind_Anchor_get_m_local_0=function(){return(Kz=b._emscripten_bind_Anchor_get_m_local_0=b.asm.rx).apply(null,arguments)},Lz=b._emscripten_bind_Anchor_set_m_local_1=function(){return(Lz=b._emscripten_bind_Anchor_set_m_local_1=b.asm.sx).apply(null,arguments)},Mz=b._emscripten_bind_Anchor_get_m_body_0=function(){return(Mz=b._emscripten_bind_Anchor_get_m_body_0=b.asm.tx).apply(null,arguments)},Nz=b._emscripten_bind_Anchor_set_m_body_1=function(){return(Nz=
|
||||
b._emscripten_bind_Anchor_set_m_body_1=b.asm.ux).apply(null,arguments)},Oz=b._emscripten_bind_Anchor_get_m_influence_0=function(){return(Oz=b._emscripten_bind_Anchor_get_m_influence_0=b.asm.vx).apply(null,arguments)},Pz=b._emscripten_bind_Anchor_set_m_influence_1=function(){return(Pz=b._emscripten_bind_Anchor_set_m_influence_1=b.asm.wx).apply(null,arguments)},Qz=b._emscripten_bind_Anchor_get_m_c0_0=function(){return(Qz=b._emscripten_bind_Anchor_get_m_c0_0=b.asm.xx).apply(null,arguments)},Rz=b._emscripten_bind_Anchor_set_m_c0_1=
|
||||
function(){return(Rz=b._emscripten_bind_Anchor_set_m_c0_1=b.asm.yx).apply(null,arguments)},Sz=b._emscripten_bind_Anchor_get_m_c1_0=function(){return(Sz=b._emscripten_bind_Anchor_get_m_c1_0=b.asm.zx).apply(null,arguments)},Tz=b._emscripten_bind_Anchor_set_m_c1_1=function(){return(Tz=b._emscripten_bind_Anchor_set_m_c1_1=b.asm.Ax).apply(null,arguments)},Uz=b._emscripten_bind_Anchor_get_m_c2_0=function(){return(Uz=b._emscripten_bind_Anchor_get_m_c2_0=b.asm.Bx).apply(null,arguments)},Vz=b._emscripten_bind_Anchor_set_m_c2_1=
|
||||
function(){return(Vz=b._emscripten_bind_Anchor_set_m_c2_1=b.asm.Cx).apply(null,arguments)},Wz=b._emscripten_bind_Anchor___destroy___0=function(){return(Wz=b._emscripten_bind_Anchor___destroy___0=b.asm.Dx).apply(null,arguments)},Xz=b._emscripten_bind_tAnchorArray_size_0=function(){return(Xz=b._emscripten_bind_tAnchorArray_size_0=b.asm.Ex).apply(null,arguments)},Yz=b._emscripten_bind_tAnchorArray_at_1=function(){return(Yz=b._emscripten_bind_tAnchorArray_at_1=b.asm.Fx).apply(null,arguments)},Zz=b._emscripten_bind_tAnchorArray_clear_0=
|
||||
function(){return(Zz=b._emscripten_bind_tAnchorArray_clear_0=b.asm.Gx).apply(null,arguments)},$z=b._emscripten_bind_tAnchorArray_push_back_1=function(){return($z=b._emscripten_bind_tAnchorArray_push_back_1=b.asm.Hx).apply(null,arguments)},aA=b._emscripten_bind_tAnchorArray_pop_back_0=function(){return(aA=b._emscripten_bind_tAnchorArray_pop_back_0=b.asm.Ix).apply(null,arguments)},bA=b._emscripten_bind_tAnchorArray___destroy___0=function(){return(bA=b._emscripten_bind_tAnchorArray___destroy___0=b.asm.Jx).apply(null,
|
||||
arguments)},cA=b._emscripten_bind_Config_get_kVCF_0=function(){return(cA=b._emscripten_bind_Config_get_kVCF_0=b.asm.Kx).apply(null,arguments)},dA=b._emscripten_bind_Config_set_kVCF_1=function(){return(dA=b._emscripten_bind_Config_set_kVCF_1=b.asm.Lx).apply(null,arguments)},eA=b._emscripten_bind_Config_get_kDP_0=function(){return(eA=b._emscripten_bind_Config_get_kDP_0=b.asm.Mx).apply(null,arguments)},fA=b._emscripten_bind_Config_set_kDP_1=function(){return(fA=b._emscripten_bind_Config_set_kDP_1=b.asm.Nx).apply(null,
|
||||
arguments)},gA=b._emscripten_bind_Config_get_kDG_0=function(){return(gA=b._emscripten_bind_Config_get_kDG_0=b.asm.Ox).apply(null,arguments)},hA=b._emscripten_bind_Config_set_kDG_1=function(){return(hA=b._emscripten_bind_Config_set_kDG_1=b.asm.Px).apply(null,arguments)},iA=b._emscripten_bind_Config_get_kLF_0=function(){return(iA=b._emscripten_bind_Config_get_kLF_0=b.asm.Qx).apply(null,arguments)},jA=b._emscripten_bind_Config_set_kLF_1=function(){return(jA=b._emscripten_bind_Config_set_kLF_1=b.asm.Rx).apply(null,
|
||||
arguments)},kA=b._emscripten_bind_Config_get_kPR_0=function(){return(kA=b._emscripten_bind_Config_get_kPR_0=b.asm.Sx).apply(null,arguments)},lA=b._emscripten_bind_Config_set_kPR_1=function(){return(lA=b._emscripten_bind_Config_set_kPR_1=b.asm.Tx).apply(null,arguments)},mA=b._emscripten_bind_Config_get_kVC_0=function(){return(mA=b._emscripten_bind_Config_get_kVC_0=b.asm.Ux).apply(null,arguments)},nA=b._emscripten_bind_Config_set_kVC_1=function(){return(nA=b._emscripten_bind_Config_set_kVC_1=b.asm.Vx).apply(null,
|
||||
arguments)},oA=b._emscripten_bind_Config_get_kDF_0=function(){return(oA=b._emscripten_bind_Config_get_kDF_0=b.asm.Wx).apply(null,arguments)},pA=b._emscripten_bind_Config_set_kDF_1=function(){return(pA=b._emscripten_bind_Config_set_kDF_1=b.asm.Xx).apply(null,arguments)},qA=b._emscripten_bind_Config_get_kMT_0=function(){return(qA=b._emscripten_bind_Config_get_kMT_0=b.asm.Yx).apply(null,arguments)},rA=b._emscripten_bind_Config_set_kMT_1=function(){return(rA=b._emscripten_bind_Config_set_kMT_1=b.asm.Zx).apply(null,
|
||||
arguments)},sA=b._emscripten_bind_Config_get_kCHR_0=function(){return(sA=b._emscripten_bind_Config_get_kCHR_0=b.asm._x).apply(null,arguments)},tA=b._emscripten_bind_Config_set_kCHR_1=function(){return(tA=b._emscripten_bind_Config_set_kCHR_1=b.asm.$x).apply(null,arguments)},uA=b._emscripten_bind_Config_get_kKHR_0=function(){return(uA=b._emscripten_bind_Config_get_kKHR_0=b.asm.ay).apply(null,arguments)},vA=b._emscripten_bind_Config_set_kKHR_1=function(){return(vA=b._emscripten_bind_Config_set_kKHR_1=
|
||||
b.asm.by).apply(null,arguments)},wA=b._emscripten_bind_Config_get_kSHR_0=function(){return(wA=b._emscripten_bind_Config_get_kSHR_0=b.asm.cy).apply(null,arguments)},xA=b._emscripten_bind_Config_set_kSHR_1=function(){return(xA=b._emscripten_bind_Config_set_kSHR_1=b.asm.dy).apply(null,arguments)},yA=b._emscripten_bind_Config_get_kAHR_0=function(){return(yA=b._emscripten_bind_Config_get_kAHR_0=b.asm.ey).apply(null,arguments)},zA=b._emscripten_bind_Config_set_kAHR_1=function(){return(zA=b._emscripten_bind_Config_set_kAHR_1=
|
||||
b.asm.fy).apply(null,arguments)},AA=b._emscripten_bind_Config_get_kSRHR_CL_0=function(){return(AA=b._emscripten_bind_Config_get_kSRHR_CL_0=b.asm.gy).apply(null,arguments)},BA=b._emscripten_bind_Config_set_kSRHR_CL_1=function(){return(BA=b._emscripten_bind_Config_set_kSRHR_CL_1=b.asm.hy).apply(null,arguments)},CA=b._emscripten_bind_Config_get_kSKHR_CL_0=function(){return(CA=b._emscripten_bind_Config_get_kSKHR_CL_0=b.asm.iy).apply(null,arguments)},DA=b._emscripten_bind_Config_set_kSKHR_CL_1=function(){return(DA=
|
||||
b._emscripten_bind_Config_set_kSKHR_CL_1=b.asm.jy).apply(null,arguments)},EA=b._emscripten_bind_Config_get_kSSHR_CL_0=function(){return(EA=b._emscripten_bind_Config_get_kSSHR_CL_0=b.asm.ky).apply(null,arguments)},FA=b._emscripten_bind_Config_set_kSSHR_CL_1=function(){return(FA=b._emscripten_bind_Config_set_kSSHR_CL_1=b.asm.ly).apply(null,arguments)},GA=b._emscripten_bind_Config_get_kSR_SPLT_CL_0=function(){return(GA=b._emscripten_bind_Config_get_kSR_SPLT_CL_0=b.asm.my).apply(null,arguments)},HA=b._emscripten_bind_Config_set_kSR_SPLT_CL_1=
|
||||
function(){return(HA=b._emscripten_bind_Config_set_kSR_SPLT_CL_1=b.asm.ny).apply(null,arguments)},IA=b._emscripten_bind_Config_get_kSK_SPLT_CL_0=function(){return(IA=b._emscripten_bind_Config_get_kSK_SPLT_CL_0=b.asm.oy).apply(null,arguments)},JA=b._emscripten_bind_Config_set_kSK_SPLT_CL_1=function(){return(JA=b._emscripten_bind_Config_set_kSK_SPLT_CL_1=b.asm.py).apply(null,arguments)},KA=b._emscripten_bind_Config_get_kSS_SPLT_CL_0=function(){return(KA=b._emscripten_bind_Config_get_kSS_SPLT_CL_0=b.asm.qy).apply(null,
|
||||
arguments)},LA=b._emscripten_bind_Config_set_kSS_SPLT_CL_1=function(){return(LA=b._emscripten_bind_Config_set_kSS_SPLT_CL_1=b.asm.ry).apply(null,arguments)},MA=b._emscripten_bind_Config_get_maxvolume_0=function(){return(MA=b._emscripten_bind_Config_get_maxvolume_0=b.asm.sy).apply(null,arguments)},NA=b._emscripten_bind_Config_set_maxvolume_1=function(){return(NA=b._emscripten_bind_Config_set_maxvolume_1=b.asm.ty).apply(null,arguments)},OA=b._emscripten_bind_Config_get_timescale_0=function(){return(OA=
|
||||
b._emscripten_bind_Config_get_timescale_0=b.asm.uy).apply(null,arguments)},PA=b._emscripten_bind_Config_set_timescale_1=function(){return(PA=b._emscripten_bind_Config_set_timescale_1=b.asm.vy).apply(null,arguments)},QA=b._emscripten_bind_Config_get_viterations_0=function(){return(QA=b._emscripten_bind_Config_get_viterations_0=b.asm.wy).apply(null,arguments)},RA=b._emscripten_bind_Config_set_viterations_1=function(){return(RA=b._emscripten_bind_Config_set_viterations_1=b.asm.xy).apply(null,arguments)},
|
||||
SA=b._emscripten_bind_Config_get_piterations_0=function(){return(SA=b._emscripten_bind_Config_get_piterations_0=b.asm.yy).apply(null,arguments)},TA=b._emscripten_bind_Config_set_piterations_1=function(){return(TA=b._emscripten_bind_Config_set_piterations_1=b.asm.zy).apply(null,arguments)},UA=b._emscripten_bind_Config_get_diterations_0=function(){return(UA=b._emscripten_bind_Config_get_diterations_0=b.asm.Ay).apply(null,arguments)},VA=b._emscripten_bind_Config_set_diterations_1=function(){return(VA=
|
||||
b._emscripten_bind_Config_set_diterations_1=b.asm.By).apply(null,arguments)},WA=b._emscripten_bind_Config_get_citerations_0=function(){return(WA=b._emscripten_bind_Config_get_citerations_0=b.asm.Cy).apply(null,arguments)},XA=b._emscripten_bind_Config_set_citerations_1=function(){return(XA=b._emscripten_bind_Config_set_citerations_1=b.asm.Dy).apply(null,arguments)},YA=b._emscripten_bind_Config_get_collisions_0=function(){return(YA=b._emscripten_bind_Config_get_collisions_0=b.asm.Ey).apply(null,arguments)},
|
||||
ZA=b._emscripten_bind_Config_set_collisions_1=function(){return(ZA=b._emscripten_bind_Config_set_collisions_1=b.asm.Fy).apply(null,arguments)},$A=b._emscripten_bind_Config___destroy___0=function(){return($A=b._emscripten_bind_Config___destroy___0=b.asm.Gy).apply(null,arguments)},aB=b._emscripten_bind_btSoftBody_btSoftBody_4=function(){return(aB=b._emscripten_bind_btSoftBody_btSoftBody_4=b.asm.Hy).apply(null,arguments)},bB=b._emscripten_bind_btSoftBody_checkLink_2=function(){return(bB=b._emscripten_bind_btSoftBody_checkLink_2=
|
||||
b.asm.Iy).apply(null,arguments)},cB=b._emscripten_bind_btSoftBody_checkFace_3=function(){return(cB=b._emscripten_bind_btSoftBody_checkFace_3=b.asm.Jy).apply(null,arguments)},dB=b._emscripten_bind_btSoftBody_appendMaterial_0=function(){return(dB=b._emscripten_bind_btSoftBody_appendMaterial_0=b.asm.Ky).apply(null,arguments)},eB=b._emscripten_bind_btSoftBody_appendNode_2=function(){return(eB=b._emscripten_bind_btSoftBody_appendNode_2=b.asm.Ly).apply(null,arguments)},fB=b._emscripten_bind_btSoftBody_appendLink_4=
|
||||
function(){return(fB=b._emscripten_bind_btSoftBody_appendLink_4=b.asm.My).apply(null,arguments)},gB=b._emscripten_bind_btSoftBody_appendFace_4=function(){return(gB=b._emscripten_bind_btSoftBody_appendFace_4=b.asm.Ny).apply(null,arguments)},hB=b._emscripten_bind_btSoftBody_appendTetra_5=function(){return(hB=b._emscripten_bind_btSoftBody_appendTetra_5=b.asm.Oy).apply(null,arguments)},iB=b._emscripten_bind_btSoftBody_appendAnchor_4=function(){return(iB=b._emscripten_bind_btSoftBody_appendAnchor_4=b.asm.Py).apply(null,
|
||||
arguments)},jB=b._emscripten_bind_btSoftBody_addForce_1=function(){return(jB=b._emscripten_bind_btSoftBody_addForce_1=b.asm.Qy).apply(null,arguments)},kB=b._emscripten_bind_btSoftBody_addForce_2=function(){return(kB=b._emscripten_bind_btSoftBody_addForce_2=b.asm.Ry).apply(null,arguments)},lB=b._emscripten_bind_btSoftBody_addAeroForceToNode_2=function(){return(lB=b._emscripten_bind_btSoftBody_addAeroForceToNode_2=b.asm.Sy).apply(null,arguments)},mB=b._emscripten_bind_btSoftBody_getTotalMass_0=function(){return(mB=
|
||||
b._emscripten_bind_btSoftBody_getTotalMass_0=b.asm.Ty).apply(null,arguments)},nB=b._emscripten_bind_btSoftBody_setTotalMass_2=function(){return(nB=b._emscripten_bind_btSoftBody_setTotalMass_2=b.asm.Uy).apply(null,arguments)},oB=b._emscripten_bind_btSoftBody_setMass_2=function(){return(oB=b._emscripten_bind_btSoftBody_setMass_2=b.asm.Vy).apply(null,arguments)},pB=b._emscripten_bind_btSoftBody_transform_1=function(){return(pB=b._emscripten_bind_btSoftBody_transform_1=b.asm.Wy).apply(null,arguments)},
|
||||
qB=b._emscripten_bind_btSoftBody_translate_1=function(){return(qB=b._emscripten_bind_btSoftBody_translate_1=b.asm.Xy).apply(null,arguments)},rB=b._emscripten_bind_btSoftBody_rotate_1=function(){return(rB=b._emscripten_bind_btSoftBody_rotate_1=b.asm.Yy).apply(null,arguments)},sB=b._emscripten_bind_btSoftBody_scale_1=function(){return(sB=b._emscripten_bind_btSoftBody_scale_1=b.asm.Zy).apply(null,arguments)},tB=b._emscripten_bind_btSoftBody_generateClusters_1=function(){return(tB=b._emscripten_bind_btSoftBody_generateClusters_1=
|
||||
b.asm._y).apply(null,arguments)},uB=b._emscripten_bind_btSoftBody_generateClusters_2=function(){return(uB=b._emscripten_bind_btSoftBody_generateClusters_2=b.asm.$y).apply(null,arguments)},vB=b._emscripten_bind_btSoftBody_generateBendingConstraints_2=function(){return(vB=b._emscripten_bind_btSoftBody_generateBendingConstraints_2=b.asm.az).apply(null,arguments)},wB=b._emscripten_bind_btSoftBody_upcast_1=function(){return(wB=b._emscripten_bind_btSoftBody_upcast_1=b.asm.bz).apply(null,arguments)},xB=
|
||||
b._emscripten_bind_btSoftBody_getRestLengthScale_0=function(){return(xB=b._emscripten_bind_btSoftBody_getRestLengthScale_0=b.asm.cz).apply(null,arguments)},yB=b._emscripten_bind_btSoftBody_setRestLengthScale_1=function(){return(yB=b._emscripten_bind_btSoftBody_setRestLengthScale_1=b.asm.dz).apply(null,arguments)},zB=b._emscripten_bind_btSoftBody_setAnisotropicFriction_2=function(){return(zB=b._emscripten_bind_btSoftBody_setAnisotropicFriction_2=b.asm.ez).apply(null,arguments)},AB=b._emscripten_bind_btSoftBody_getCollisionShape_0=
|
||||
function(){return(AB=b._emscripten_bind_btSoftBody_getCollisionShape_0=b.asm.fz).apply(null,arguments)},BB=b._emscripten_bind_btSoftBody_setContactProcessingThreshold_1=function(){return(BB=b._emscripten_bind_btSoftBody_setContactProcessingThreshold_1=b.asm.gz).apply(null,arguments)},CB=b._emscripten_bind_btSoftBody_setActivationState_1=function(){return(CB=b._emscripten_bind_btSoftBody_setActivationState_1=b.asm.hz).apply(null,arguments)},DB=b._emscripten_bind_btSoftBody_forceActivationState_1=function(){return(DB=
|
||||
b._emscripten_bind_btSoftBody_forceActivationState_1=b.asm.iz).apply(null,arguments)},EB=b._emscripten_bind_btSoftBody_activate_0=function(){return(EB=b._emscripten_bind_btSoftBody_activate_0=b.asm.jz).apply(null,arguments)},FB=b._emscripten_bind_btSoftBody_activate_1=function(){return(FB=b._emscripten_bind_btSoftBody_activate_1=b.asm.kz).apply(null,arguments)},GB=b._emscripten_bind_btSoftBody_isActive_0=function(){return(GB=b._emscripten_bind_btSoftBody_isActive_0=b.asm.lz).apply(null,arguments)},
|
||||
HB=b._emscripten_bind_btSoftBody_isKinematicObject_0=function(){return(HB=b._emscripten_bind_btSoftBody_isKinematicObject_0=b.asm.mz).apply(null,arguments)},IB=b._emscripten_bind_btSoftBody_isStaticObject_0=function(){return(IB=b._emscripten_bind_btSoftBody_isStaticObject_0=b.asm.nz).apply(null,arguments)},JB=b._emscripten_bind_btSoftBody_isStaticOrKinematicObject_0=function(){return(JB=b._emscripten_bind_btSoftBody_isStaticOrKinematicObject_0=b.asm.oz).apply(null,arguments)},KB=b._emscripten_bind_btSoftBody_getRestitution_0=
|
||||
function(){return(KB=b._emscripten_bind_btSoftBody_getRestitution_0=b.asm.pz).apply(null,arguments)},LB=b._emscripten_bind_btSoftBody_getFriction_0=function(){return(LB=b._emscripten_bind_btSoftBody_getFriction_0=b.asm.qz).apply(null,arguments)},MB=b._emscripten_bind_btSoftBody_getRollingFriction_0=function(){return(MB=b._emscripten_bind_btSoftBody_getRollingFriction_0=b.asm.rz).apply(null,arguments)},NB=b._emscripten_bind_btSoftBody_setRestitution_1=function(){return(NB=b._emscripten_bind_btSoftBody_setRestitution_1=
|
||||
b.asm.sz).apply(null,arguments)},OB=b._emscripten_bind_btSoftBody_setFriction_1=function(){return(OB=b._emscripten_bind_btSoftBody_setFriction_1=b.asm.tz).apply(null,arguments)},PB=b._emscripten_bind_btSoftBody_setRollingFriction_1=function(){return(PB=b._emscripten_bind_btSoftBody_setRollingFriction_1=b.asm.uz).apply(null,arguments)},QB=b._emscripten_bind_btSoftBody_getWorldTransform_0=function(){return(QB=b._emscripten_bind_btSoftBody_getWorldTransform_0=b.asm.vz).apply(null,arguments)},RB=b._emscripten_bind_btSoftBody_getCollisionFlags_0=
|
||||
function(){return(RB=b._emscripten_bind_btSoftBody_getCollisionFlags_0=b.asm.wz).apply(null,arguments)},SB=b._emscripten_bind_btSoftBody_setCollisionFlags_1=function(){return(SB=b._emscripten_bind_btSoftBody_setCollisionFlags_1=b.asm.xz).apply(null,arguments)},TB=b._emscripten_bind_btSoftBody_setWorldTransform_1=function(){return(TB=b._emscripten_bind_btSoftBody_setWorldTransform_1=b.asm.yz).apply(null,arguments)},UB=b._emscripten_bind_btSoftBody_setCollisionShape_1=function(){return(UB=b._emscripten_bind_btSoftBody_setCollisionShape_1=
|
||||
b.asm.zz).apply(null,arguments)},VB=b._emscripten_bind_btSoftBody_setCcdMotionThreshold_1=function(){return(VB=b._emscripten_bind_btSoftBody_setCcdMotionThreshold_1=b.asm.Az).apply(null,arguments)},WB=b._emscripten_bind_btSoftBody_setCcdSweptSphereRadius_1=function(){return(WB=b._emscripten_bind_btSoftBody_setCcdSweptSphereRadius_1=b.asm.Bz).apply(null,arguments)},XB=b._emscripten_bind_btSoftBody_getUserIndex_0=function(){return(XB=b._emscripten_bind_btSoftBody_getUserIndex_0=b.asm.Cz).apply(null,
|
||||
arguments)},YB=b._emscripten_bind_btSoftBody_setUserIndex_1=function(){return(YB=b._emscripten_bind_btSoftBody_setUserIndex_1=b.asm.Dz).apply(null,arguments)},ZB=b._emscripten_bind_btSoftBody_getUserPointer_0=function(){return(ZB=b._emscripten_bind_btSoftBody_getUserPointer_0=b.asm.Ez).apply(null,arguments)},$B=b._emscripten_bind_btSoftBody_setUserPointer_1=function(){return($B=b._emscripten_bind_btSoftBody_setUserPointer_1=b.asm.Fz).apply(null,arguments)},aC=b._emscripten_bind_btSoftBody_getBroadphaseHandle_0=
|
||||
function(){return(aC=b._emscripten_bind_btSoftBody_getBroadphaseHandle_0=b.asm.Gz).apply(null,arguments)},bC=b._emscripten_bind_btSoftBody_get_m_cfg_0=function(){return(bC=b._emscripten_bind_btSoftBody_get_m_cfg_0=b.asm.Hz).apply(null,arguments)},cC=b._emscripten_bind_btSoftBody_set_m_cfg_1=function(){return(cC=b._emscripten_bind_btSoftBody_set_m_cfg_1=b.asm.Iz).apply(null,arguments)},dC=b._emscripten_bind_btSoftBody_get_m_nodes_0=function(){return(dC=b._emscripten_bind_btSoftBody_get_m_nodes_0=b.asm.Jz).apply(null,
|
||||
arguments)},eC=b._emscripten_bind_btSoftBody_set_m_nodes_1=function(){return(eC=b._emscripten_bind_btSoftBody_set_m_nodes_1=b.asm.Kz).apply(null,arguments)},fC=b._emscripten_bind_btSoftBody_get_m_faces_0=function(){return(fC=b._emscripten_bind_btSoftBody_get_m_faces_0=b.asm.Lz).apply(null,arguments)},gC=b._emscripten_bind_btSoftBody_set_m_faces_1=function(){return(gC=b._emscripten_bind_btSoftBody_set_m_faces_1=b.asm.Mz).apply(null,arguments)},hC=b._emscripten_bind_btSoftBody_get_m_materials_0=function(){return(hC=
|
||||
b._emscripten_bind_btSoftBody_get_m_materials_0=b.asm.Nz).apply(null,arguments)},iC=b._emscripten_bind_btSoftBody_set_m_materials_1=function(){return(iC=b._emscripten_bind_btSoftBody_set_m_materials_1=b.asm.Oz).apply(null,arguments)},jC=b._emscripten_bind_btSoftBody_get_m_anchors_0=function(){return(jC=b._emscripten_bind_btSoftBody_get_m_anchors_0=b.asm.Pz).apply(null,arguments)},kC=b._emscripten_bind_btSoftBody_set_m_anchors_1=function(){return(kC=b._emscripten_bind_btSoftBody_set_m_anchors_1=b.asm.Qz).apply(null,
|
||||
arguments)},lC=b._emscripten_bind_btSoftBody___destroy___0=function(){return(lC=b._emscripten_bind_btSoftBody___destroy___0=b.asm.Rz).apply(null,arguments)},mC=b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_0=function(){return(mC=b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_0=b.asm.Sz).apply(null,arguments)},nC=b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_1=
|
||||
function(){return(nC=b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_1=b.asm.Tz).apply(null,arguments)},oC=b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration___destroy___0=function(){return(oC=b._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration___destroy___0=b.asm.Uz).apply(null,arguments)},pC=b._emscripten_bind_btDefaultSoftBodySolver_btDefaultSoftBodySolver_0=function(){return(pC=b._emscripten_bind_btDefaultSoftBodySolver_btDefaultSoftBodySolver_0=
|
||||
b.asm.Vz).apply(null,arguments)},qC=b._emscripten_bind_btDefaultSoftBodySolver___destroy___0=function(){return(qC=b._emscripten_bind_btDefaultSoftBodySolver___destroy___0=b.asm.Wz).apply(null,arguments)},rC=b._emscripten_bind_btSoftBodyArray_size_0=function(){return(rC=b._emscripten_bind_btSoftBodyArray_size_0=b.asm.Xz).apply(null,arguments)},sC=b._emscripten_bind_btSoftBodyArray_at_1=function(){return(sC=b._emscripten_bind_btSoftBodyArray_at_1=b.asm.Yz).apply(null,arguments)},tC=b._emscripten_bind_btSoftBodyArray___destroy___0=
|
||||
function(){return(tC=b._emscripten_bind_btSoftBodyArray___destroy___0=b.asm.Zz).apply(null,arguments)},uC=b._emscripten_bind_btSoftRigidDynamicsWorld_btSoftRigidDynamicsWorld_5=function(){return(uC=b._emscripten_bind_btSoftRigidDynamicsWorld_btSoftRigidDynamicsWorld_5=b.asm._z).apply(null,arguments)},vC=b._emscripten_bind_btSoftRigidDynamicsWorld_addSoftBody_3=function(){return(vC=b._emscripten_bind_btSoftRigidDynamicsWorld_addSoftBody_3=b.asm.$z).apply(null,arguments)},wC=b._emscripten_bind_btSoftRigidDynamicsWorld_removeSoftBody_1=
|
||||
function(){return(wC=b._emscripten_bind_btSoftRigidDynamicsWorld_removeSoftBody_1=b.asm.aA).apply(null,arguments)},xC=b._emscripten_bind_btSoftRigidDynamicsWorld_removeCollisionObject_1=function(){return(xC=b._emscripten_bind_btSoftRigidDynamicsWorld_removeCollisionObject_1=b.asm.bA).apply(null,arguments)},yC=b._emscripten_bind_btSoftRigidDynamicsWorld_getWorldInfo_0=function(){return(yC=b._emscripten_bind_btSoftRigidDynamicsWorld_getWorldInfo_0=b.asm.cA).apply(null,arguments)},zC=b._emscripten_bind_btSoftRigidDynamicsWorld_getSoftBodyArray_0=
|
||||
function(){return(zC=b._emscripten_bind_btSoftRigidDynamicsWorld_getSoftBodyArray_0=b.asm.dA).apply(null,arguments)},AC=b._emscripten_bind_btSoftRigidDynamicsWorld_getDispatcher_0=function(){return(AC=b._emscripten_bind_btSoftRigidDynamicsWorld_getDispatcher_0=b.asm.eA).apply(null,arguments)},BC=b._emscripten_bind_btSoftRigidDynamicsWorld_rayTest_3=function(){return(BC=b._emscripten_bind_btSoftRigidDynamicsWorld_rayTest_3=b.asm.fA).apply(null,arguments)},CC=b._emscripten_bind_btSoftRigidDynamicsWorld_getPairCache_0=
|
||||
function(){return(CC=b._emscripten_bind_btSoftRigidDynamicsWorld_getPairCache_0=b.asm.gA).apply(null,arguments)},DC=b._emscripten_bind_btSoftRigidDynamicsWorld_getDispatchInfo_0=function(){return(DC=b._emscripten_bind_btSoftRigidDynamicsWorld_getDispatchInfo_0=b.asm.hA).apply(null,arguments)},EC=b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_1=function(){return(EC=b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_1=b.asm.iA).apply(null,arguments)},FC=b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_2=
|
||||
function(){return(FC=b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_2=b.asm.jA).apply(null,arguments)},GC=b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_3=function(){return(GC=b._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_3=b.asm.kA).apply(null,arguments)},HC=b._emscripten_bind_btSoftRigidDynamicsWorld_getBroadphase_0=function(){return(HC=b._emscripten_bind_btSoftRigidDynamicsWorld_getBroadphase_0=b.asm.lA).apply(null,arguments)},IC=b._emscripten_bind_btSoftRigidDynamicsWorld_convexSweepTest_5=
|
||||
function(){return(IC=b._emscripten_bind_btSoftRigidDynamicsWorld_convexSweepTest_5=b.asm.mA).apply(null,arguments)},JC=b._emscripten_bind_btSoftRigidDynamicsWorld_contactPairTest_3=function(){return(JC=b._emscripten_bind_btSoftRigidDynamicsWorld_contactPairTest_3=b.asm.nA).apply(null,arguments)},KC=b._emscripten_bind_btSoftRigidDynamicsWorld_contactTest_2=function(){return(KC=b._emscripten_bind_btSoftRigidDynamicsWorld_contactTest_2=b.asm.oA).apply(null,arguments)},LC=b._emscripten_bind_btSoftRigidDynamicsWorld_updateSingleAabb_1=
|
||||
function(){return(LC=b._emscripten_bind_btSoftRigidDynamicsWorld_updateSingleAabb_1=b.asm.pA).apply(null,arguments)},MC=b._emscripten_bind_btSoftRigidDynamicsWorld_setDebugDrawer_1=function(){return(MC=b._emscripten_bind_btSoftRigidDynamicsWorld_setDebugDrawer_1=b.asm.qA).apply(null,arguments)},NC=b._emscripten_bind_btSoftRigidDynamicsWorld_getDebugDrawer_0=function(){return(NC=b._emscripten_bind_btSoftRigidDynamicsWorld_getDebugDrawer_0=b.asm.rA).apply(null,arguments)},OC=b._emscripten_bind_btSoftRigidDynamicsWorld_debugDrawWorld_0=
|
||||
function(){return(OC=b._emscripten_bind_btSoftRigidDynamicsWorld_debugDrawWorld_0=b.asm.sA).apply(null,arguments)},PC=b._emscripten_bind_btSoftRigidDynamicsWorld_debugDrawObject_3=function(){return(PC=b._emscripten_bind_btSoftRigidDynamicsWorld_debugDrawObject_3=b.asm.tA).apply(null,arguments)},QC=b._emscripten_bind_btSoftRigidDynamicsWorld_setGravity_1=function(){return(QC=b._emscripten_bind_btSoftRigidDynamicsWorld_setGravity_1=b.asm.uA).apply(null,arguments)},RC=b._emscripten_bind_btSoftRigidDynamicsWorld_getGravity_0=
|
||||
function(){return(RC=b._emscripten_bind_btSoftRigidDynamicsWorld_getGravity_0=b.asm.vA).apply(null,arguments)},SC=b._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_1=function(){return(SC=b._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_1=b.asm.wA).apply(null,arguments)},TC=b._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_3=function(){return(TC=b._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_3=b.asm.xA).apply(null,arguments)},UC=b._emscripten_bind_btSoftRigidDynamicsWorld_removeRigidBody_1=
|
||||
function(){return(UC=b._emscripten_bind_btSoftRigidDynamicsWorld_removeRigidBody_1=b.asm.yA).apply(null,arguments)},VC=b._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_1=function(){return(VC=b._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_1=b.asm.zA).apply(null,arguments)},WC=b._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_2=function(){return(WC=b._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_2=b.asm.AA).apply(null,arguments)},XC=b._emscripten_bind_btSoftRigidDynamicsWorld_removeConstraint_1=
|
||||
function(){return(XC=b._emscripten_bind_btSoftRigidDynamicsWorld_removeConstraint_1=b.asm.BA).apply(null,arguments)},YC=b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_1=function(){return(YC=b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_1=b.asm.CA).apply(null,arguments)},ZC=b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_2=function(){return(ZC=b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_2=b.asm.DA).apply(null,arguments)},$C=b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_3=
|
||||
function(){return($C=b._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_3=b.asm.EA).apply(null,arguments)},aD=b._emscripten_bind_btSoftRigidDynamicsWorld_setContactAddedCallback_1=function(){return(aD=b._emscripten_bind_btSoftRigidDynamicsWorld_setContactAddedCallback_1=b.asm.FA).apply(null,arguments)},bD=b._emscripten_bind_btSoftRigidDynamicsWorld_setContactProcessedCallback_1=function(){return(bD=b._emscripten_bind_btSoftRigidDynamicsWorld_setContactProcessedCallback_1=b.asm.GA).apply(null,
|
||||
arguments)},cD=b._emscripten_bind_btSoftRigidDynamicsWorld_setContactDestroyedCallback_1=function(){return(cD=b._emscripten_bind_btSoftRigidDynamicsWorld_setContactDestroyedCallback_1=b.asm.HA).apply(null,arguments)},dD=b._emscripten_bind_btSoftRigidDynamicsWorld_addAction_1=function(){return(dD=b._emscripten_bind_btSoftRigidDynamicsWorld_addAction_1=b.asm.IA).apply(null,arguments)},eD=b._emscripten_bind_btSoftRigidDynamicsWorld_removeAction_1=function(){return(eD=b._emscripten_bind_btSoftRigidDynamicsWorld_removeAction_1=
|
||||
b.asm.JA).apply(null,arguments)},fD=b._emscripten_bind_btSoftRigidDynamicsWorld_getSolverInfo_0=function(){return(fD=b._emscripten_bind_btSoftRigidDynamicsWorld_getSolverInfo_0=b.asm.KA).apply(null,arguments)},gD=b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_1=function(){return(gD=b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_1=b.asm.LA).apply(null,arguments)},hD=b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_2=function(){return(hD=
|
||||
b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_2=b.asm.MA).apply(null,arguments)},iD=b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_3=function(){return(iD=b._emscripten_bind_btSoftRigidDynamicsWorld_setInternalTickCallback_3=b.asm.NA).apply(null,arguments)},jD=b._emscripten_bind_btSoftRigidDynamicsWorld___destroy___0=function(){return(jD=b._emscripten_bind_btSoftRigidDynamicsWorld___destroy___0=b.asm.OA).apply(null,arguments)},kD=b._emscripten_bind_btSoftBodyHelpers_btSoftBodyHelpers_0=
|
||||
function(){return(kD=b._emscripten_bind_btSoftBodyHelpers_btSoftBodyHelpers_0=b.asm.PA).apply(null,arguments)},lD=b._emscripten_bind_btSoftBodyHelpers_CreateRope_5=function(){return(lD=b._emscripten_bind_btSoftBodyHelpers_CreateRope_5=b.asm.QA).apply(null,arguments)},mD=b._emscripten_bind_btSoftBodyHelpers_CreatePatch_9=function(){return(mD=b._emscripten_bind_btSoftBodyHelpers_CreatePatch_9=b.asm.RA).apply(null,arguments)},nD=b._emscripten_bind_btSoftBodyHelpers_CreatePatchUV_10=function(){return(nD=
|
||||
b._emscripten_bind_btSoftBodyHelpers_CreatePatchUV_10=b.asm.SA).apply(null,arguments)},oD=b._emscripten_bind_btSoftBodyHelpers_CreateEllipsoid_4=function(){return(oD=b._emscripten_bind_btSoftBodyHelpers_CreateEllipsoid_4=b.asm.TA).apply(null,arguments)},pD=b._emscripten_bind_btSoftBodyHelpers_CreateFromTriMesh_5=function(){return(pD=b._emscripten_bind_btSoftBodyHelpers_CreateFromTriMesh_5=b.asm.UA).apply(null,arguments)},qD=b._emscripten_bind_btSoftBodyHelpers_CreateFromConvexHull_4=function(){return(qD=
|
||||
b._emscripten_bind_btSoftBodyHelpers_CreateFromConvexHull_4=b.asm.VA).apply(null,arguments)},rD=b._emscripten_bind_btSoftBodyHelpers___destroy___0=function(){return(rD=b._emscripten_bind_btSoftBodyHelpers___destroy___0=b.asm.WA).apply(null,arguments)},sD=b._emscripten_enum_PHY_ScalarType_PHY_FLOAT=function(){return(sD=b._emscripten_enum_PHY_ScalarType_PHY_FLOAT=b.asm.XA).apply(null,arguments)},tD=b._emscripten_enum_PHY_ScalarType_PHY_DOUBLE=function(){return(tD=b._emscripten_enum_PHY_ScalarType_PHY_DOUBLE=
|
||||
b.asm.YA).apply(null,arguments)},uD=b._emscripten_enum_PHY_ScalarType_PHY_INTEGER=function(){return(uD=b._emscripten_enum_PHY_ScalarType_PHY_INTEGER=b.asm.ZA).apply(null,arguments)},vD=b._emscripten_enum_PHY_ScalarType_PHY_SHORT=function(){return(vD=b._emscripten_enum_PHY_ScalarType_PHY_SHORT=b.asm._A).apply(null,arguments)},wD=b._emscripten_enum_PHY_ScalarType_PHY_FIXEDPOINT88=function(){return(wD=b._emscripten_enum_PHY_ScalarType_PHY_FIXEDPOINT88=b.asm.$A).apply(null,arguments)},xD=b._emscripten_enum_PHY_ScalarType_PHY_UCHAR=
|
||||
function(){return(xD=b._emscripten_enum_PHY_ScalarType_PHY_UCHAR=b.asm.aB).apply(null,arguments)},yD=b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_COMPOUND_SHAPE=function(){return(yD=b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_COMPOUND_SHAPE=b.asm.bB).apply(null,arguments)},zD=b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_TRIMESH_SHAPE_PART=function(){return(zD=b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_TRIMESH_SHAPE_PART=b.asm.cB).apply(null,arguments)},AD=b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_TRIMESH_SHAPE=
|
||||
function(){return(AD=b._emscripten_enum_eGIMPACT_SHAPE_TYPE_CONST_GIMPACT_TRIMESH_SHAPE=b.asm.dB).apply(null,arguments)},BD=b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_ERP=function(){return(BD=b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_ERP=b.asm.eB).apply(null,arguments)},CD=b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_STOP_ERP=function(){return(CD=b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_STOP_ERP=b.asm.fB).apply(null,arguments)},DD=b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_CFM=
|
||||
function(){return(DD=b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_CFM=b.asm.gB).apply(null,arguments)},ED=b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_STOP_CFM=function(){return(ED=b._emscripten_enum_btConstraintParams_BT_CONSTRAINT_STOP_CFM=b.asm.hB).apply(null,arguments)};b._malloc=function(){return(b._malloc=b.asm.jB).apply(null,arguments)};b.___start_em_js=27240;b.___stop_em_js=27338;b.UTF8ToString=sa;
|
||||
b.addFunction=function(a,c){if(!Ua){Ua=new WeakMap;var d=ya.length;if(Ua)for(var e=0;e<0+d;e++){var g=e;var n=Ta[g];n||(g>=Ta.length&&(Ta.length=g+1),Ta[g]=n=ya.get(g));(g=n)&&Ua.set(g,e)}}if(d=Ua.get(a)||0)return d;if(Va.length)d=Va.pop();else{try{ya.grow(1)}catch(T){if(!(T instanceof RangeError))throw T;throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.";}d=ya.length-1}try{e=d,ya.set(e,a),Ta[e]=ya.get(e)}catch(T){if(!(T instanceof TypeError))throw T;if("function"==typeof WebAssembly.Function){e=
|
||||
WebAssembly.Function;g={i:"i32",j:"i32",f:"f32",d:"f64",p:"i32"};n={parameters:[],results:"v"==c[0]?[]:[g[c[0]]]};for(var z=1;z<c.length;++z)n.parameters.push(g[c[z]]),"j"===c[z]&&n.parameters.push("i32");c=new e(n,a)}else{e=[1];g=c.slice(0,1);c=c.slice(1);n={i:127,p:127,j:126,f:125,d:124};e.push(96);z=c.length;128>z?e.push(z):e.push(z%128|128,z>>7);for(z=0;z<c.length;++z)e.push(n[c[z]]);"v"==g?e.push(0):e.push(1,n[g]);c=[0,97,115,109,1,0,0,0,1];g=e.length;128>g?c.push(g):c.push(g%128|128,g>>7);c.push.apply(c,
|
||||
e);c.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);c=new WebAssembly.Module(new Uint8Array(c));c=(new WebAssembly.Instance(c,{e:{f:a}})).exports.f}e=d;ya.set(e,c);Ta[e]=ya.get(e)}Ua.set(a,d);return d};var FD;Ha=function GD(){FD||HD();FD||(Ha=GD)};
|
||||
function HD(){function a(){if(!FD&&(FD=!0,b.calledRun=!0,!qa)){Ca=!0;Qa(Aa);aa(b);if(b.onRuntimeInitialized)b.onRuntimeInitialized();if(b.postRun)for("function"==typeof b.postRun&&(b.postRun=[b.postRun]);b.postRun.length;){var c=b.postRun.shift();Ba.unshift(c)}Qa(Ba)}}if(!(0<Fa)){if(b.preRun)for("function"==typeof b.preRun&&(b.preRun=[b.preRun]);b.preRun.length;)Ea();Qa(za);0<Fa||(b.setStatus?(b.setStatus("Running..."),setTimeout(function(){setTimeout(function(){b.setStatus("")},1);a()},1)):a())}}
|
||||
if(b.preInit)for("function"==typeof b.preInit&&(b.preInit=[b.preInit]);0<b.preInit.length;)b.preInit.pop()();HD();function f(){}f.prototype=Object.create(f.prototype);f.prototype.constructor=f;f.prototype.lB=f;f.mB={};b.WrapperObject=f;function h(a){return(a||f).mB}b.getCache=h;function k(a,c){var d=h(c),e=d[a];if(e)return e;e=Object.create((c||f).prototype);e.kB=a;return d[a]=e}b.wrapPointer=k;b.castObject=function(a,c){return k(a.kB,c)};b.NULL=k(0);
|
||||
b.destroy=function(a){if(!a.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";a.__destroy__();delete h(a.lB)[a.kB]};b.compare=function(a,c){return a.kB===c.kB};b.getPointer=function(a){return a.kB};b.getClass=function(a){return a.lB};var ID=0,JD=0,KD=0,LD=[],MD=0;function ND(){if(MD){for(var a=0;a<LD.length;a++)b._free(LD[a]);LD.length=0;b._free(ID);ID=0;JD+=MD;MD=0}ID||(JD+=128,(ID=b._malloc(JD))||oa());KD=0}
|
||||
function OD(a,c){ID||oa();a=a.length*c.BYTES_PER_ELEMENT;a=a+7&-8;KD+a>=JD?(0<a||oa(),MD+=a,c=b._malloc(a),LD.push(c)):(c=ID+KD,KD+=a);return c}function PD(a,c,d){d>>>=0;switch(c.BYTES_PER_ELEMENT){case 2:d>>>=1;break;case 4:d>>>=2;break;case 8:d>>>=3}for(var e=0;e<a.length;e++)c[d+e]=a[e]}
|
||||
function QD(a){if("string"===typeof a){for(var c=0,d=0;d<a.length;++d){var e=a.charCodeAt(d);127>=e?c++:2047>=e?c+=2:55296<=e&&57343>=e?(c+=4,++d):c+=3}c=Array(c+1);e=c.length;d=0;if(0<e){e=d+e-1;for(var g=0;g<a.length;++g){var n=a.charCodeAt(g);if(55296<=n&&57343>=n){var z=a.charCodeAt(++g);n=65536+((n&1023)<<10)|z&1023}if(127>=n){if(d>=e)break;c[d++]=n}else{if(2047>=n){if(d+1>=e)break;c[d++]=192|n>>6}else{if(65535>=n){if(d+2>=e)break;c[d++]=224|n>>12}else{if(d+3>=e)break;c[d++]=240|n>>18;c[d++]=
|
||||
128|n>>12&63}c[d++]=128|n>>6&63}c[d++]=128|n&63}}c[d]=0}a=OD(c,ua);PD(c,ua,a);return a}return a}function RD(a){if("object"===typeof a){var c=OD(a,wa);PD(a,wa,c);return c}return a}function l(){throw"cannot construct a btCollisionShape, no constructor in IDL";}l.prototype=Object.create(f.prototype);l.prototype.constructor=l;l.prototype.lB=l;l.mB={};b.btCollisionShape=l;l.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Xa(c,a)};
|
||||
l.prototype.getLocalScaling=function(){return k(Ya(this.kB),m)};l.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Za(d,a,c)};l.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$a(c,a)};l.prototype.getMargin=function(){return ab(this.kB)};l.prototype.__destroy__=function(){bb(this.kB)};function SD(){throw"cannot construct a btCollisionWorld, no constructor in IDL";}SD.prototype=Object.create(f.prototype);
|
||||
SD.prototype.constructor=SD;SD.prototype.lB=SD;SD.mB={};b.btCollisionWorld=SD;SD.prototype.getDispatcher=function(){return k(cb(this.kB),TD)};SD.prototype.rayTest=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);db(e,a,c,d)};SD.prototype.getPairCache=function(){return k(eb(this.kB),UD)};SD.prototype.getDispatchInfo=function(){return k(fb(this.kB),p)};
|
||||
SD.prototype.addCollisionObject=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?gb(e,a):void 0===d?hb(e,a,c):ib(e,a,c,d)};SD.prototype.removeCollisionObject=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jb(c,a)};SD.prototype.getBroadphase=function(){return k(kb(this.kB),VD)};
|
||||
SD.prototype.convexSweepTest=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);lb(n,a,c,d,e,g)};SD.prototype.contactPairTest=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);mb(e,a,c,d)};
|
||||
SD.prototype.contactTest=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);nb(d,a,c)};SD.prototype.updateSingleAabb=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ob(c,a)};SD.prototype.setDebugDrawer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pb(c,a)};SD.prototype.getDebugDrawer=function(){return k(qb(this.kB),WD)};SD.prototype.debugDrawWorld=function(){rb(this.kB)};
|
||||
SD.prototype.debugDrawObject=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);sb(e,a,c,d)};SD.prototype.__destroy__=function(){tb(this.kB)};function q(){throw"cannot construct a btCollisionObject, no constructor in IDL";}q.prototype=Object.create(f.prototype);q.prototype.constructor=q;q.prototype.lB=q;q.mB={};b.btCollisionObject=q;
|
||||
q.prototype.setAnisotropicFriction=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);ub(d,a,c)};q.prototype.getCollisionShape=function(){return k(vb(this.kB),l)};q.prototype.setContactProcessingThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);wb(c,a)};q.prototype.setActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xb(c,a)};
|
||||
q.prototype.forceActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yb(c,a)};q.prototype.activate=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);void 0===a?zb(c):Ab(c,a)};q.prototype.isActive=function(){return!!Bb(this.kB)};q.prototype.isKinematicObject=function(){return!!Cb(this.kB)};q.prototype.isStaticObject=function(){return!!Db(this.kB)};q.prototype.isStaticOrKinematicObject=function(){return!!Eb(this.kB)};q.prototype.getRestitution=function(){return Fb(this.kB)};
|
||||
q.prototype.getFriction=function(){return Gb(this.kB)};q.prototype.getRollingFriction=function(){return Hb(this.kB)};q.prototype.setRestitution=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ib(c,a)};q.prototype.setFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jb(c,a)};q.prototype.setRollingFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Kb(c,a)};q.prototype.getWorldTransform=function(){return k(Lb(this.kB),r)};q.prototype.getCollisionFlags=function(){return Mb(this.kB)};
|
||||
q.prototype.setCollisionFlags=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Nb(c,a)};q.prototype.setWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ob(c,a)};q.prototype.setCollisionShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Pb(c,a)};q.prototype.setCcdMotionThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Qb(c,a)};q.prototype.setCcdSweptSphereRadius=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Rb(c,a)};
|
||||
q.prototype.getUserIndex=function(){return Sb(this.kB)};q.prototype.setUserIndex=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Tb(c,a)};q.prototype.getUserPointer=function(){return k(Ub(this.kB),XD)};q.prototype.setUserPointer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vb(c,a)};q.prototype.getBroadphaseHandle=function(){return k(Wb(this.kB),YD)};q.prototype.__destroy__=function(){Xb(this.kB)};
|
||||
function ZD(){throw"cannot construct a btConcaveShape, no constructor in IDL";}ZD.prototype=Object.create(l.prototype);ZD.prototype.constructor=ZD;ZD.prototype.lB=ZD;ZD.mB={};b.btConcaveShape=ZD;ZD.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Yb(c,a)};ZD.prototype.getLocalScaling=function(){return k(Zb(this.kB),m)};ZD.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);$b(d,a,c)};
|
||||
ZD.prototype.__destroy__=function(){ac(this.kB)};function $D(){throw"cannot construct a btCollisionAlgorithm, no constructor in IDL";}$D.prototype=Object.create(f.prototype);$D.prototype.constructor=$D;$D.prototype.lB=$D;$D.mB={};b.btCollisionAlgorithm=$D;$D.prototype.__destroy__=function(){bc(this.kB)};function aE(){throw"cannot construct a btTypedConstraint, no constructor in IDL";}aE.prototype=Object.create(f.prototype);aE.prototype.constructor=aE;aE.prototype.lB=aE;aE.mB={};
|
||||
b.btTypedConstraint=aE;aE.prototype.enableFeedback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);cc(c,a)};aE.prototype.getBreakingImpulseThreshold=function(){return ec(this.kB)};aE.prototype.setBreakingImpulseThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fc(c,a)};aE.prototype.getParam=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return gc(d,a,c)};
|
||||
aE.prototype.setParam=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);hc(e,a,c,d)};aE.prototype.__destroy__=function(){ic(this.kB)};function bE(){throw"cannot construct a btDynamicsWorld, no constructor in IDL";}bE.prototype=Object.create(SD.prototype);bE.prototype.constructor=bE;bE.prototype.lB=bE;bE.mB={};b.btDynamicsWorld=bE;bE.prototype.addAction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jc(c,a)};
|
||||
bE.prototype.removeAction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);kc(c,a)};bE.prototype.getSolverInfo=function(){return k(lc(this.kB),t)};bE.prototype.setInternalTickCallback=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?mc(e,a):void 0===d?nc(e,a,c):oc(e,a,c,d)};bE.prototype.getDispatcher=function(){return k(pc(this.kB),TD)};
|
||||
bE.prototype.rayTest=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);qc(e,a,c,d)};bE.prototype.getPairCache=function(){return k(rc(this.kB),UD)};bE.prototype.getDispatchInfo=function(){return k(sc(this.kB),p)};
|
||||
bE.prototype.addCollisionObject=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?tc(e,a):void 0===d?uc(e,a,c):vc(e,a,c,d)};bE.prototype.removeCollisionObject=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);wc(c,a)};bE.prototype.getBroadphase=function(){return k(xc(this.kB),VD)};
|
||||
bE.prototype.convexSweepTest=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);yc(n,a,c,d,e,g)};bE.prototype.contactPairTest=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);zc(e,a,c,d)};
|
||||
bE.prototype.contactTest=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Ac(d,a,c)};bE.prototype.updateSingleAabb=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Bc(c,a)};bE.prototype.setDebugDrawer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Cc(c,a)};bE.prototype.getDebugDrawer=function(){return k(Dc(this.kB),WD)};bE.prototype.debugDrawWorld=function(){Ec(this.kB)};
|
||||
bE.prototype.debugDrawObject=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Fc(e,a,c,d)};bE.prototype.__destroy__=function(){Gc(this.kB)};function WD(){throw"cannot construct a btIDebugDraw, no constructor in IDL";}WD.prototype=Object.create(f.prototype);WD.prototype.constructor=WD;WD.prototype.lB=WD;WD.mB={};b.btIDebugDraw=WD;
|
||||
WD.prototype.drawLine=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Hc(e,a,c,d)};WD.prototype.drawContactPoint=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);Ic(n,a,c,d,e,g)};
|
||||
WD.prototype.reportErrorWarning=function(a){var c=this.kB;ND();a=a&&"object"===typeof a?a.kB:QD(a);Jc(c,a)};WD.prototype.draw3dText=function(a,c){var d=this.kB;ND();a&&"object"===typeof a&&(a=a.kB);c=c&&"object"===typeof c?c.kB:QD(c);Kc(d,a,c)};WD.prototype.setDebugMode=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Lc(c,a)};WD.prototype.getDebugMode=function(){return Mc(this.kB)};WD.prototype.__destroy__=function(){Nc(this.kB)};
|
||||
function m(a,c,d){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);this.kB=void 0===a?Oc():void 0===c?_emscripten_bind_btVector3_btVector3_1(a):void 0===d?_emscripten_bind_btVector3_btVector3_2(a,c):Pc(a,c,d);h(m)[this.kB]=this}m.prototype=Object.create(f.prototype);m.prototype.constructor=m;m.prototype.lB=m;m.mB={};b.btVector3=m;m.prototype.length=m.prototype.length=function(){return Qc(this.kB)};m.prototype.x=m.prototype.x=function(){return Rc(this.kB)};
|
||||
m.prototype.y=m.prototype.y=function(){return Sc(this.kB)};m.prototype.z=m.prototype.z=function(){return Tc(this.kB)};m.prototype.setX=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Uc(c,a)};m.prototype.setY=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vc(c,a)};m.prototype.setZ=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Wc(c,a)};
|
||||
m.prototype.setValue=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Xc(e,a,c,d)};m.prototype.normalize=m.prototype.normalize=function(){Yc(this.kB)};m.prototype.rotate=m.prototype.rotate=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return k(Zc(d,a,c),m)};m.prototype.dot=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return $c(c,a)};
|
||||
m.prototype.op_mul=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(ad(c,a),m)};m.prototype.op_add=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(bd(c,a),m)};m.prototype.op_sub=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(cd(c,a),m)};m.prototype.__destroy__=function(){dd(this.kB)};function cE(){throw"cannot construct a btQuadWord, no constructor in IDL";}cE.prototype=Object.create(f.prototype);cE.prototype.constructor=cE;
|
||||
cE.prototype.lB=cE;cE.mB={};b.btQuadWord=cE;cE.prototype.x=cE.prototype.x=function(){return ed(this.kB)};cE.prototype.y=cE.prototype.y=function(){return fd(this.kB)};cE.prototype.z=cE.prototype.z=function(){return gd(this.kB)};cE.prototype.w=cE.prototype.w=function(){return hd(this.kB)};cE.prototype.setX=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jd(c,a)};cE.prototype.setY=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);kd(c,a)};
|
||||
cE.prototype.setZ=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ld(c,a)};cE.prototype.setW=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);md(c,a)};cE.prototype.__destroy__=function(){nd(this.kB)};function dE(){throw"cannot construct a btMotionState, no constructor in IDL";}dE.prototype=Object.create(f.prototype);dE.prototype.constructor=dE;dE.prototype.lB=dE;dE.mB={};b.btMotionState=dE;
|
||||
dE.prototype.getWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);od(c,a)};dE.prototype.setWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pd(c,a)};dE.prototype.__destroy__=function(){qd(this.kB)};function u(){throw"cannot construct a RayResultCallback, no constructor in IDL";}u.prototype=Object.create(f.prototype);u.prototype.constructor=u;u.prototype.lB=u;u.mB={};b.RayResultCallback=u;u.prototype.hasHit=function(){return!!rd(this.kB)};
|
||||
u.prototype.get_m_collisionFilterGroup=u.prototype.nB=function(){return sd(this.kB)};u.prototype.set_m_collisionFilterGroup=u.prototype.pB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);td(c,a)};Object.defineProperty(u.prototype,"m_collisionFilterGroup",{get:u.prototype.nB,set:u.prototype.pB});u.prototype.get_m_collisionFilterMask=u.prototype.oB=function(){return ud(this.kB)};
|
||||
u.prototype.set_m_collisionFilterMask=u.prototype.qB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vd(c,a)};Object.defineProperty(u.prototype,"m_collisionFilterMask",{get:u.prototype.oB,set:u.prototype.qB});u.prototype.get_m_closestHitFraction=u.prototype.rB=function(){return wd(this.kB)};u.prototype.set_m_closestHitFraction=u.prototype.sB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xd(c,a)};Object.defineProperty(u.prototype,"m_closestHitFraction",{get:u.prototype.rB,set:u.prototype.sB});
|
||||
u.prototype.get_m_collisionObject=u.prototype.vB=function(){return k(yd(this.kB),q)};u.prototype.set_m_collisionObject=u.prototype.CB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zd(c,a)};Object.defineProperty(u.prototype,"m_collisionObject",{get:u.prototype.vB,set:u.prototype.CB});u.prototype.get_m_flags=u.prototype.tB=function(){return Ad(this.kB)};u.prototype.set_m_flags=u.prototype.uB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Bd(c,a)};
|
||||
Object.defineProperty(u.prototype,"m_flags",{get:u.prototype.tB,set:u.prototype.uB});u.prototype.__destroy__=function(){Cd(this.kB)};function eE(){throw"cannot construct a ContactResultCallback, no constructor in IDL";}eE.prototype=Object.create(f.prototype);eE.prototype.constructor=eE;eE.prototype.lB=eE;eE.mB={};b.ContactResultCallback=eE;
|
||||
eE.prototype.addSingleResult=function(a,c,d,e,g,n,z){var T=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);n&&"object"===typeof n&&(n=n.kB);z&&"object"===typeof z&&(z=z.kB);return Dd(T,a,c,d,e,g,n,z)};eE.prototype.__destroy__=function(){Ed(this.kB)};function v(){throw"cannot construct a ConvexResultCallback, no constructor in IDL";}v.prototype=Object.create(f.prototype);
|
||||
v.prototype.constructor=v;v.prototype.lB=v;v.mB={};b.ConvexResultCallback=v;v.prototype.hasHit=function(){return!!Fd(this.kB)};v.prototype.get_m_collisionFilterGroup=v.prototype.nB=function(){return Gd(this.kB)};v.prototype.set_m_collisionFilterGroup=v.prototype.pB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Hd(c,a)};Object.defineProperty(v.prototype,"m_collisionFilterGroup",{get:v.prototype.nB,set:v.prototype.pB});v.prototype.get_m_collisionFilterMask=v.prototype.oB=function(){return Id(this.kB)};
|
||||
v.prototype.set_m_collisionFilterMask=v.prototype.qB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jd(c,a)};Object.defineProperty(v.prototype,"m_collisionFilterMask",{get:v.prototype.oB,set:v.prototype.qB});v.prototype.get_m_closestHitFraction=v.prototype.rB=function(){return Kd(this.kB)};v.prototype.set_m_closestHitFraction=v.prototype.sB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ld(c,a)};Object.defineProperty(v.prototype,"m_closestHitFraction",{get:v.prototype.rB,set:v.prototype.sB});
|
||||
v.prototype.__destroy__=function(){Md(this.kB)};function fE(){throw"cannot construct a btConvexShape, no constructor in IDL";}fE.prototype=Object.create(l.prototype);fE.prototype.constructor=fE;fE.prototype.lB=fE;fE.mB={};b.btConvexShape=fE;fE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Nd(c,a)};fE.prototype.getLocalScaling=function(){return k(Od(this.kB),m)};
|
||||
fE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Pd(d,a,c)};fE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Qd(c,a)};fE.prototype.getMargin=function(){return Rd(this.kB)};fE.prototype.__destroy__=function(){Sd(this.kB)};function gE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=Td(a,c);h(gE)[this.kB]=this}gE.prototype=Object.create(l.prototype);
|
||||
gE.prototype.constructor=gE;gE.prototype.lB=gE;gE.mB={};b.btCapsuleShape=gE;gE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ud(c,a)};gE.prototype.getMargin=function(){return Vd(this.kB)};gE.prototype.getUpAxis=function(){return Wd(this.kB)};gE.prototype.getRadius=function(){return Xd(this.kB)};gE.prototype.getHalfHeight=function(){return Yd(this.kB)};gE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Zd(c,a)};
|
||||
gE.prototype.getLocalScaling=function(){return k($d(this.kB),m)};gE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);ae(d,a,c)};gE.prototype.__destroy__=function(){be(this.kB)};function hE(a){a&&"object"===typeof a&&(a=a.kB);this.kB=ce(a);h(hE)[this.kB]=this}hE.prototype=Object.create(l.prototype);hE.prototype.constructor=hE;hE.prototype.lB=hE;hE.mB={};b.btCylinderShape=hE;
|
||||
hE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);de(c,a)};hE.prototype.getMargin=function(){return ee(this.kB)};hE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fe(c,a)};hE.prototype.getLocalScaling=function(){return k(ge(this.kB),m)};hE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);he(d,a,c)};hE.prototype.__destroy__=function(){ie(this.kB)};
|
||||
function iE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=je(a,c);h(iE)[this.kB]=this}iE.prototype=Object.create(l.prototype);iE.prototype.constructor=iE;iE.prototype.lB=iE;iE.mB={};b.btConeShape=iE;iE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ke(c,a)};iE.prototype.getLocalScaling=function(){return k(le(this.kB),m)};
|
||||
iE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);me(d,a,c)};iE.prototype.__destroy__=function(){ne(this.kB)};function jE(){throw"cannot construct a btStridingMeshInterface, no constructor in IDL";}jE.prototype=Object.create(f.prototype);jE.prototype.constructor=jE;jE.prototype.lB=jE;jE.mB={};b.btStridingMeshInterface=jE;jE.prototype.setScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);oe(c,a)};
|
||||
jE.prototype.__destroy__=function(){pe(this.kB)};function kE(){throw"cannot construct a btTriangleMeshShape, no constructor in IDL";}kE.prototype=Object.create(ZD.prototype);kE.prototype.constructor=kE;kE.prototype.lB=kE;kE.mB={};b.btTriangleMeshShape=kE;kE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);qe(c,a)};kE.prototype.getLocalScaling=function(){return k(re(this.kB),m)};
|
||||
kE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);se(d,a,c)};kE.prototype.__destroy__=function(){te(this.kB)};function lE(){throw"cannot construct a btPrimitiveManagerBase, no constructor in IDL";}lE.prototype=Object.create(f.prototype);lE.prototype.constructor=lE;lE.prototype.lB=lE;lE.mB={};b.btPrimitiveManagerBase=lE;lE.prototype.is_trimesh=function(){return!!ue(this.kB)};lE.prototype.get_primitive_count=function(){return ve(this.kB)};
|
||||
lE.prototype.get_primitive_box=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);we(d,a,c)};lE.prototype.get_primitive_triangle=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);xe(d,a,c)};lE.prototype.__destroy__=function(){ye(this.kB)};function w(){throw"cannot construct a btGImpactShapeInterface, no constructor in IDL";}w.prototype=Object.create(ZD.prototype);w.prototype.constructor=w;w.prototype.lB=w;
|
||||
w.mB={};b.btGImpactShapeInterface=w;w.prototype.updateBound=function(){ze(this.kB)};w.prototype.postUpdate=function(){Ae(this.kB)};w.prototype.getShapeType=function(){return Be(this.kB)};w.prototype.getName=function(){return sa(Ce(this.kB))};w.prototype.getGImpactShapeType=function(){return De(this.kB)};w.prototype.getPrimitiveManager=function(){return k(Ee(this.kB),lE)};w.prototype.getNumChildShapes=function(){return Fe(this.kB)};w.prototype.childrenHasTransform=function(){return!!Ge(this.kB)};
|
||||
w.prototype.needsRetrieveTriangles=function(){return!!He(this.kB)};w.prototype.needsRetrieveTetrahedrons=function(){return!!Ie(this.kB)};w.prototype.getBulletTriangle=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Je(d,a,c)};w.prototype.getBulletTetrahedron=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Ke(d,a,c)};
|
||||
w.prototype.getChildShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Le(c,a),l)};w.prototype.getChildTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Me(c,a),r)};w.prototype.setChildTransform=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Ne(d,a,c)};w.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Oe(c,a)};
|
||||
w.prototype.getLocalScaling=function(){return k(Pe(this.kB),m)};w.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Qe(d,a,c)};w.prototype.__destroy__=function(){Re(this.kB)};function mE(){throw"cannot construct a btActivatingCollisionAlgorithm, no constructor in IDL";}mE.prototype=Object.create($D.prototype);mE.prototype.constructor=mE;mE.prototype.lB=mE;mE.mB={};b.btActivatingCollisionAlgorithm=mE;
|
||||
mE.prototype.__destroy__=function(){Se(this.kB)};function nE(a){a&&"object"===typeof a&&(a=a.kB);this.kB=void 0===a?Te():Ue(a);h(nE)[this.kB]=this}nE.prototype=Object.create(f.prototype);nE.prototype.constructor=nE;nE.prototype.lB=nE;nE.mB={};b.btDefaultCollisionConfiguration=nE;nE.prototype.__destroy__=function(){Ve(this.kB)};function TD(){throw"cannot construct a btDispatcher, no constructor in IDL";}TD.prototype=Object.create(f.prototype);TD.prototype.constructor=TD;TD.prototype.lB=TD;TD.mB={};
|
||||
b.btDispatcher=TD;TD.prototype.getNumManifolds=function(){return We(this.kB)};TD.prototype.getManifoldByIndexInternal=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Xe(c,a),oE)};TD.prototype.__destroy__=function(){Ye(this.kB)};
|
||||
function pE(a,c,d,e,g){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);this.kB=void 0===e?Ze(a,c,d):void 0===g?_emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_4(a,c,d,e):$e(a,c,d,e,g);h(pE)[this.kB]=this}pE.prototype=Object.create(aE.prototype);pE.prototype.constructor=pE;pE.prototype.lB=pE;pE.mB={};b.btGeneric6DofConstraint=pE;
|
||||
pE.prototype.setLinearLowerLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);af(c,a)};pE.prototype.setLinearUpperLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);bf(c,a)};pE.prototype.setAngularLowerLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);cf(c,a)};pE.prototype.setAngularUpperLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);df(c,a)};pE.prototype.getFrameOffsetA=function(){return k(ef(this.kB),r)};
|
||||
pE.prototype.enableFeedback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ff(c,a)};pE.prototype.getBreakingImpulseThreshold=function(){return gf(this.kB)};pE.prototype.setBreakingImpulseThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hf(c,a)};pE.prototype.getParam=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return jf(d,a,c)};
|
||||
pE.prototype.setParam=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);kf(e,a,c,d)};pE.prototype.__destroy__=function(){lf(this.kB)};function x(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=mf(a,c,d,e);h(x)[this.kB]=this}x.prototype=Object.create(bE.prototype);x.prototype.constructor=x;x.prototype.lB=x;x.mB={};
|
||||
b.btDiscreteDynamicsWorld=x;x.prototype.setGravity=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);nf(c,a)};x.prototype.getGravity=function(){return k(of(this.kB),m)};x.prototype.addRigidBody=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?pf(e,a):void 0===d?_emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_2(e,a,c):qf(e,a,c,d)};
|
||||
x.prototype.removeRigidBody=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);rf(c,a)};x.prototype.addConstraint=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);void 0===c?sf(d,a):tf(d,a,c)};x.prototype.removeConstraint=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);uf(c,a)};
|
||||
x.prototype.stepSimulation=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);return void 0===c?vf(e,a):void 0===d?wf(e,a,c):xf(e,a,c,d)};x.prototype.setContactAddedCallback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yf(c,a)};x.prototype.setContactProcessedCallback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zf(c,a)};
|
||||
x.prototype.setContactDestroyedCallback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Af(c,a)};x.prototype.getDispatcher=function(){return k(Bf(this.kB),TD)};x.prototype.rayTest=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Cf(e,a,c,d)};x.prototype.getPairCache=function(){return k(Df(this.kB),UD)};x.prototype.getDispatchInfo=function(){return k(Ef(this.kB),p)};
|
||||
x.prototype.addCollisionObject=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?Ff(e,a):void 0===d?Gf(e,a,c):Hf(e,a,c,d)};x.prototype.removeCollisionObject=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);If(c,a)};x.prototype.getBroadphase=function(){return k(Jf(this.kB),VD)};
|
||||
x.prototype.convexSweepTest=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);Kf(n,a,c,d,e,g)};x.prototype.contactPairTest=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Lf(e,a,c,d)};
|
||||
x.prototype.contactTest=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Mf(d,a,c)};x.prototype.updateSingleAabb=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Nf(c,a)};x.prototype.setDebugDrawer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Of(c,a)};x.prototype.getDebugDrawer=function(){return k(Pf(this.kB),WD)};x.prototype.debugDrawWorld=function(){Qf(this.kB)};
|
||||
x.prototype.debugDrawObject=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Rf(e,a,c,d)};x.prototype.addAction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Sf(c,a)};x.prototype.removeAction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Tf(c,a)};x.prototype.getSolverInfo=function(){return k(Uf(this.kB),t)};
|
||||
x.prototype.setInternalTickCallback=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?Vf(e,a):void 0===d?Wf(e,a,c):Xf(e,a,c,d)};x.prototype.__destroy__=function(){Yf(this.kB)};function qE(){throw"cannot construct a btVehicleRaycaster, no constructor in IDL";}qE.prototype=Object.create(f.prototype);qE.prototype.constructor=qE;qE.prototype.lB=qE;qE.mB={};b.btVehicleRaycaster=qE;
|
||||
qE.prototype.castRay=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Zf(e,a,c,d)};qE.prototype.__destroy__=function(){$f(this.kB)};function rE(){throw"cannot construct a btActionInterface, no constructor in IDL";}rE.prototype=Object.create(f.prototype);rE.prototype.constructor=rE;rE.prototype.lB=rE;rE.mB={};b.btActionInterface=rE;
|
||||
rE.prototype.updateAction=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);ag(d,a,c)};rE.prototype.__destroy__=function(){bg(this.kB)};function y(){this.kB=cg();h(y)[this.kB]=this}y.prototype=Object.create(q.prototype);y.prototype.constructor=y;y.prototype.lB=y;y.mB={};b.btGhostObject=y;y.prototype.getNumOverlappingObjects=function(){return dg(this.kB)};
|
||||
y.prototype.getOverlappingObject=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(eg(c,a),q)};y.prototype.setAnisotropicFriction=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);fg(d,a,c)};y.prototype.getCollisionShape=function(){return k(gg(this.kB),l)};y.prototype.setContactProcessingThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hg(c,a)};
|
||||
y.prototype.setActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ig(c,a)};y.prototype.forceActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jg(c,a)};y.prototype.activate=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);void 0===a?kg(c):lg(c,a)};y.prototype.isActive=function(){return!!mg(this.kB)};y.prototype.isKinematicObject=function(){return!!ng(this.kB)};y.prototype.isStaticObject=function(){return!!og(this.kB)};
|
||||
y.prototype.isStaticOrKinematicObject=function(){return!!pg(this.kB)};y.prototype.getRestitution=function(){return qg(this.kB)};y.prototype.getFriction=function(){return rg(this.kB)};y.prototype.getRollingFriction=function(){return sg(this.kB)};y.prototype.setRestitution=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);tg(c,a)};y.prototype.setFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ug(c,a)};
|
||||
y.prototype.setRollingFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vg(c,a)};y.prototype.getWorldTransform=function(){return k(wg(this.kB),r)};y.prototype.getCollisionFlags=function(){return xg(this.kB)};y.prototype.setCollisionFlags=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yg(c,a)};y.prototype.setWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zg(c,a)};
|
||||
y.prototype.setCollisionShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ag(c,a)};y.prototype.setCcdMotionThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Bg(c,a)};y.prototype.setCcdSweptSphereRadius=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Cg(c,a)};y.prototype.getUserIndex=function(){return Dg(this.kB)};y.prototype.setUserIndex=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Eg(c,a)};
|
||||
y.prototype.getUserPointer=function(){return k(Fg(this.kB),XD)};y.prototype.setUserPointer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Gg(c,a)};y.prototype.getBroadphaseHandle=function(){return k(Hg(this.kB),YD)};y.prototype.__destroy__=function(){Ig(this.kB)};function sE(){throw"cannot construct a btSoftBodySolver, no constructor in IDL";}sE.prototype=Object.create(f.prototype);sE.prototype.constructor=sE;sE.prototype.lB=sE;sE.mB={};b.btSoftBodySolver=sE;sE.prototype.__destroy__=function(){Jg(this.kB)};
|
||||
function XD(){throw"cannot construct a VoidPtr, no constructor in IDL";}XD.prototype=Object.create(f.prototype);XD.prototype.constructor=XD;XD.prototype.lB=XD;XD.mB={};b.VoidPtr=XD;XD.prototype.__destroy__=function(){Kg(this.kB)};function tE(){this.kB=Lg();h(tE)[this.kB]=this}tE.prototype=Object.create(WD.prototype);tE.prototype.constructor=tE;tE.prototype.lB=tE;tE.mB={};b.DebugDrawer=tE;
|
||||
tE.prototype.drawLine=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Mg(e,a,c,d)};tE.prototype.drawContactPoint=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);Ng(n,a,c,d,e,g)};
|
||||
tE.prototype.reportErrorWarning=function(a){var c=this.kB;ND();a=a&&"object"===typeof a?a.kB:QD(a);Og(c,a)};tE.prototype.draw3dText=function(a,c){var d=this.kB;ND();a&&"object"===typeof a&&(a=a.kB);c=c&&"object"===typeof c?c.kB:QD(c);Pg(d,a,c)};tE.prototype.setDebugMode=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Qg(c,a)};tE.prototype.getDebugMode=function(){return Rg(this.kB)};tE.prototype.__destroy__=function(){Sg(this.kB)};
|
||||
function A(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=void 0===a?Tg():void 0===c?_emscripten_bind_btVector4_btVector4_1(a):void 0===d?_emscripten_bind_btVector4_btVector4_2(a,c):void 0===e?_emscripten_bind_btVector4_btVector4_3(a,c,d):Ug(a,c,d,e);h(A)[this.kB]=this}A.prototype=Object.create(m.prototype);A.prototype.constructor=A;A.prototype.lB=A;A.mB={};b.btVector4=A;
|
||||
A.prototype.w=A.prototype.w=function(){return Vg(this.kB)};A.prototype.setValue=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);Wg(g,a,c,d,e)};A.prototype.length=A.prototype.length=function(){return Xg(this.kB)};A.prototype.x=A.prototype.x=function(){return Yg(this.kB)};A.prototype.y=A.prototype.y=function(){return Zg(this.kB)};A.prototype.z=A.prototype.z=function(){return $g(this.kB)};
|
||||
A.prototype.setX=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ah(c,a)};A.prototype.setY=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);bh(c,a)};A.prototype.setZ=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ch(c,a)};A.prototype.normalize=A.prototype.normalize=function(){dh(this.kB)};A.prototype.rotate=A.prototype.rotate=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return k(eh(d,a,c),m)};
|
||||
A.prototype.dot=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return fh(c,a)};A.prototype.op_mul=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(gh(c,a),m)};A.prototype.op_add=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(hh(c,a),m)};A.prototype.op_sub=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(ih(c,a),m)};A.prototype.__destroy__=function(){jh(this.kB)};
|
||||
function B(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=kh(a,c,d,e);h(B)[this.kB]=this}B.prototype=Object.create(cE.prototype);B.prototype.constructor=B;B.prototype.lB=B;B.mB={};b.btQuaternion=B;B.prototype.setValue=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);lh(g,a,c,d,e)};
|
||||
B.prototype.setEulerZYX=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);mh(e,a,c,d)};B.prototype.setRotation=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);nh(d,a,c)};B.prototype.normalize=B.prototype.normalize=function(){oh(this.kB)};B.prototype.length2=function(){return ph(this.kB)};B.prototype.length=B.prototype.length=function(){return qh(this.kB)};
|
||||
B.prototype.dot=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return rh(c,a)};B.prototype.normalized=function(){return k(sh(this.kB),B)};B.prototype.getAxis=function(){return k(th(this.kB),m)};B.prototype.inverse=B.prototype.inverse=function(){return k(uh(this.kB),B)};B.prototype.getAngle=function(){return vh(this.kB)};B.prototype.getAngleShortestPath=function(){return wh(this.kB)};
|
||||
B.prototype.angle=B.prototype.angle=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return xh(c,a)};B.prototype.angleShortestPath=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return yh(c,a)};B.prototype.op_add=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(zh(c,a),B)};B.prototype.op_sub=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Ah(c,a),B)};
|
||||
B.prototype.op_mul=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Bh(c,a),B)};B.prototype.op_mulq=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Ch(c,a),B)};B.prototype.op_div=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Dh(c,a),B)};B.prototype.x=B.prototype.x=function(){return Eh(this.kB)};B.prototype.y=B.prototype.y=function(){return Fh(this.kB)};B.prototype.z=B.prototype.z=function(){return Gh(this.kB)};
|
||||
B.prototype.w=B.prototype.w=function(){return Hh(this.kB)};B.prototype.setX=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ih(c,a)};B.prototype.setY=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jh(c,a)};B.prototype.setZ=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Kh(c,a)};B.prototype.setW=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Lh(c,a)};B.prototype.__destroy__=function(){Mh(this.kB)};
|
||||
function uE(){throw"cannot construct a btMatrix3x3, no constructor in IDL";}uE.prototype=Object.create(f.prototype);uE.prototype.constructor=uE;uE.prototype.lB=uE;uE.mB={};b.btMatrix3x3=uE;uE.prototype.setEulerZYX=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Nh(e,a,c,d)};uE.prototype.getRotation=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Oh(c,a)};
|
||||
uE.prototype.getRow=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Ph(c,a),m)};uE.prototype.__destroy__=function(){Qh(this.kB)};function r(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=void 0===a?Rh():void 0===c?_emscripten_bind_btTransform_btTransform_1(a):Sh(a,c);h(r)[this.kB]=this}r.prototype=Object.create(f.prototype);r.prototype.constructor=r;r.prototype.lB=r;r.mB={};b.btTransform=r;r.prototype.setIdentity=function(){Th(this.kB)};
|
||||
r.prototype.setOrigin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Uh(c,a)};r.prototype.setRotation=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vh(c,a)};r.prototype.getOrigin=function(){return k(Wh(this.kB),m)};r.prototype.getRotation=function(){return k(Xh(this.kB),B)};r.prototype.getBasis=function(){return k(Yh(this.kB),uE)};r.prototype.setFromOpenGLMatrix=function(a){var c=this.kB;ND();"object"==typeof a&&(a=RD(a));Zh(c,a)};
|
||||
r.prototype.inverse=r.prototype.inverse=function(){return k($h(this.kB),r)};r.prototype.op_mul=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(ai(c,a),r)};r.prototype.__destroy__=function(){bi(this.kB)};function vE(){this.kB=ci();h(vE)[this.kB]=this}vE.prototype=Object.create(dE.prototype);vE.prototype.constructor=vE;vE.prototype.lB=vE;vE.mB={};b.MotionState=vE;vE.prototype.getWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);di(c,a)};
|
||||
vE.prototype.setWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ei(c,a)};vE.prototype.__destroy__=function(){fi(this.kB)};function wE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=void 0===a?gi():void 0===c?hi(a):ii(a,c);h(wE)[this.kB]=this}wE.prototype=Object.create(dE.prototype);wE.prototype.constructor=wE;wE.prototype.lB=wE;wE.mB={};b.btDefaultMotionState=wE;
|
||||
wE.prototype.getWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ji(c,a)};wE.prototype.setWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ki(c,a)};wE.prototype.get_m_graphicsWorldTrans=wE.prototype.lD=function(){return k(li(this.kB),r)};wE.prototype.set_m_graphicsWorldTrans=wE.prototype.cG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);mi(c,a)};Object.defineProperty(wE.prototype,"m_graphicsWorldTrans",{get:wE.prototype.lD,set:wE.prototype.cG});
|
||||
wE.prototype.__destroy__=function(){ni(this.kB)};function xE(){throw"cannot construct a btCollisionObjectWrapper, no constructor in IDL";}xE.prototype=Object.create(f.prototype);xE.prototype.constructor=xE;xE.prototype.lB=xE;xE.mB={};b.btCollisionObjectWrapper=xE;xE.prototype.getWorldTransform=function(){return k(oi(this.kB),r)};xE.prototype.getCollisionObject=function(){return k(pi(this.kB),q)};xE.prototype.getCollisionShape=function(){return k(qi(this.kB),l)};
|
||||
function C(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=ri(a,c);h(C)[this.kB]=this}C.prototype=Object.create(u.prototype);C.prototype.constructor=C;C.prototype.lB=C;C.mB={};b.ClosestRayResultCallback=C;C.prototype.hasHit=function(){return!!si(this.kB)};C.prototype.get_m_rayFromWorld=C.prototype.NB=function(){return k(ti(this.kB),m)};C.prototype.set_m_rayFromWorld=C.prototype.XB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ui(c,a)};
|
||||
Object.defineProperty(C.prototype,"m_rayFromWorld",{get:C.prototype.NB,set:C.prototype.XB});C.prototype.get_m_rayToWorld=C.prototype.OB=function(){return k(vi(this.kB),m)};C.prototype.set_m_rayToWorld=C.prototype.YB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);wi(c,a)};Object.defineProperty(C.prototype,"m_rayToWorld",{get:C.prototype.OB,set:C.prototype.YB});C.prototype.get_m_hitNormalWorld=C.prototype.xB=function(){return k(xi(this.kB),m)};
|
||||
C.prototype.set_m_hitNormalWorld=C.prototype.EB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yi(c,a)};Object.defineProperty(C.prototype,"m_hitNormalWorld",{get:C.prototype.xB,set:C.prototype.EB});C.prototype.get_m_hitPointWorld=C.prototype.yB=function(){return k(zi(this.kB),m)};C.prototype.set_m_hitPointWorld=C.prototype.FB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ai(c,a)};Object.defineProperty(C.prototype,"m_hitPointWorld",{get:C.prototype.yB,set:C.prototype.FB});
|
||||
C.prototype.get_m_collisionFilterGroup=C.prototype.nB=function(){return Bi(this.kB)};C.prototype.set_m_collisionFilterGroup=C.prototype.pB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ci(c,a)};Object.defineProperty(C.prototype,"m_collisionFilterGroup",{get:C.prototype.nB,set:C.prototype.pB});C.prototype.get_m_collisionFilterMask=C.prototype.oB=function(){return Di(this.kB)};
|
||||
C.prototype.set_m_collisionFilterMask=C.prototype.qB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ei(c,a)};Object.defineProperty(C.prototype,"m_collisionFilterMask",{get:C.prototype.oB,set:C.prototype.qB});C.prototype.get_m_closestHitFraction=C.prototype.rB=function(){return Fi(this.kB)};C.prototype.set_m_closestHitFraction=C.prototype.sB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Gi(c,a)};Object.defineProperty(C.prototype,"m_closestHitFraction",{get:C.prototype.rB,set:C.prototype.sB});
|
||||
C.prototype.get_m_collisionObject=C.prototype.vB=function(){return k(Hi(this.kB),q)};C.prototype.set_m_collisionObject=C.prototype.CB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ii(c,a)};Object.defineProperty(C.prototype,"m_collisionObject",{get:C.prototype.vB,set:C.prototype.CB});C.prototype.get_m_flags=C.prototype.tB=function(){return Ji(this.kB)};C.prototype.set_m_flags=C.prototype.uB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ki(c,a)};
|
||||
Object.defineProperty(C.prototype,"m_flags",{get:C.prototype.tB,set:C.prototype.uB});C.prototype.__destroy__=function(){Li(this.kB)};function yE(){throw"cannot construct a btConstCollisionObjectArray, no constructor in IDL";}yE.prototype=Object.create(f.prototype);yE.prototype.constructor=yE;yE.prototype.lB=yE;yE.mB={};b.btConstCollisionObjectArray=yE;yE.prototype.size=yE.prototype.size=function(){return Mi(this.kB)};
|
||||
yE.prototype.at=yE.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Ni(c,a),q)};yE.prototype.__destroy__=function(){Oi(this.kB)};function zE(){throw"cannot construct a btScalarArray, no constructor in IDL";}zE.prototype=Object.create(f.prototype);zE.prototype.constructor=zE;zE.prototype.lB=zE;zE.mB={};b.btScalarArray=zE;zE.prototype.size=zE.prototype.size=function(){return Pi(this.kB)};
|
||||
zE.prototype.at=zE.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return Qi(c,a)};zE.prototype.__destroy__=function(){Ri(this.kB)};function D(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=Si(a,c);h(D)[this.kB]=this}D.prototype=Object.create(u.prototype);D.prototype.constructor=D;D.prototype.lB=D;D.mB={};b.AllHitsRayResultCallback=D;D.prototype.hasHit=function(){return!!Ti(this.kB)};
|
||||
D.prototype.get_m_collisionObjects=D.prototype.UC=function(){return k(Ui(this.kB),yE)};D.prototype.set_m_collisionObjects=D.prototype.LF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vi(c,a)};Object.defineProperty(D.prototype,"m_collisionObjects",{get:D.prototype.UC,set:D.prototype.LF});D.prototype.get_m_rayFromWorld=D.prototype.NB=function(){return k(Wi(this.kB),m)};D.prototype.set_m_rayFromWorld=D.prototype.XB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Xi(c,a)};
|
||||
Object.defineProperty(D.prototype,"m_rayFromWorld",{get:D.prototype.NB,set:D.prototype.XB});D.prototype.get_m_rayToWorld=D.prototype.OB=function(){return k(Yi(this.kB),m)};D.prototype.set_m_rayToWorld=D.prototype.YB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Zi(c,a)};Object.defineProperty(D.prototype,"m_rayToWorld",{get:D.prototype.OB,set:D.prototype.YB});D.prototype.get_m_hitNormalWorld=D.prototype.xB=function(){return k($i(this.kB),AE)};
|
||||
D.prototype.set_m_hitNormalWorld=D.prototype.EB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);aj(c,a)};Object.defineProperty(D.prototype,"m_hitNormalWorld",{get:D.prototype.xB,set:D.prototype.EB});D.prototype.get_m_hitPointWorld=D.prototype.yB=function(){return k(bj(this.kB),AE)};D.prototype.set_m_hitPointWorld=D.prototype.FB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);cj(c,a)};Object.defineProperty(D.prototype,"m_hitPointWorld",{get:D.prototype.yB,set:D.prototype.FB});
|
||||
D.prototype.get_m_hitFractions=D.prototype.qD=function(){return k(dj(this.kB),zE)};D.prototype.set_m_hitFractions=D.prototype.hG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ej(c,a)};Object.defineProperty(D.prototype,"m_hitFractions",{get:D.prototype.qD,set:D.prototype.hG});D.prototype.get_m_collisionFilterGroup=D.prototype.nB=function(){return fj(this.kB)};D.prototype.set_m_collisionFilterGroup=D.prototype.pB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);gj(c,a)};
|
||||
Object.defineProperty(D.prototype,"m_collisionFilterGroup",{get:D.prototype.nB,set:D.prototype.pB});D.prototype.get_m_collisionFilterMask=D.prototype.oB=function(){return hj(this.kB)};D.prototype.set_m_collisionFilterMask=D.prototype.qB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ij(c,a)};Object.defineProperty(D.prototype,"m_collisionFilterMask",{get:D.prototype.oB,set:D.prototype.qB});D.prototype.get_m_closestHitFraction=D.prototype.rB=function(){return jj(this.kB)};
|
||||
D.prototype.set_m_closestHitFraction=D.prototype.sB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);kj(c,a)};Object.defineProperty(D.prototype,"m_closestHitFraction",{get:D.prototype.rB,set:D.prototype.sB});D.prototype.get_m_collisionObject=D.prototype.vB=function(){return k(lj(this.kB),q)};D.prototype.set_m_collisionObject=D.prototype.CB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);mj(c,a)};Object.defineProperty(D.prototype,"m_collisionObject",{get:D.prototype.vB,set:D.prototype.CB});
|
||||
D.prototype.get_m_flags=D.prototype.tB=function(){return nj(this.kB)};D.prototype.set_m_flags=D.prototype.uB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);oj(c,a)};Object.defineProperty(D.prototype,"m_flags",{get:D.prototype.tB,set:D.prototype.uB});D.prototype.__destroy__=function(){pj(this.kB)};function E(){throw"cannot construct a btManifoldPoint, no constructor in IDL";}E.prototype=Object.create(f.prototype);E.prototype.constructor=E;E.prototype.lB=E;E.mB={};b.btManifoldPoint=E;
|
||||
E.prototype.getPositionWorldOnA=function(){return k(qj(this.kB),m)};E.prototype.getPositionWorldOnB=function(){return k(rj(this.kB),m)};E.prototype.getAppliedImpulse=function(){return sj(this.kB)};E.prototype.getDistance=function(){return tj(this.kB)};E.prototype.get_m_localPointA=E.prototype.GD=function(){return k(uj(this.kB),m)};E.prototype.set_m_localPointA=E.prototype.xG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vj(c,a)};
|
||||
Object.defineProperty(E.prototype,"m_localPointA",{get:E.prototype.GD,set:E.prototype.xG});E.prototype.get_m_localPointB=E.prototype.HD=function(){return k(wj(this.kB),m)};E.prototype.set_m_localPointB=E.prototype.yG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xj(c,a)};Object.defineProperty(E.prototype,"m_localPointB",{get:E.prototype.HD,set:E.prototype.yG});E.prototype.get_m_positionWorldOnB=E.prototype.YD=function(){return k(yj(this.kB),m)};
|
||||
E.prototype.set_m_positionWorldOnB=E.prototype.PG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zj(c,a)};Object.defineProperty(E.prototype,"m_positionWorldOnB",{get:E.prototype.YD,set:E.prototype.PG});E.prototype.get_m_positionWorldOnA=E.prototype.XD=function(){return k(Aj(this.kB),m)};E.prototype.set_m_positionWorldOnA=E.prototype.OG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Bj(c,a)};Object.defineProperty(E.prototype,"m_positionWorldOnA",{get:E.prototype.XD,set:E.prototype.OG});
|
||||
E.prototype.get_m_normalWorldOnB=E.prototype.SD=function(){return k(Cj(this.kB),m)};E.prototype.set_m_normalWorldOnB=E.prototype.JG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dj(c,a)};Object.defineProperty(E.prototype,"m_normalWorldOnB",{get:E.prototype.SD,set:E.prototype.JG});E.prototype.get_m_userPersistentData=E.prototype.zE=function(){return Ej(this.kB)};E.prototype.set_m_userPersistentData=E.prototype.rH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Fj(c,a)};
|
||||
Object.defineProperty(E.prototype,"m_userPersistentData",{get:E.prototype.zE,set:E.prototype.rH});E.prototype.__destroy__=function(){Gj(this.kB)};function BE(){this.kB=Hj();h(BE)[this.kB]=this}BE.prototype=Object.create(eE.prototype);BE.prototype.constructor=BE;BE.prototype.lB=BE;BE.mB={};b.ConcreteContactResultCallback=BE;
|
||||
BE.prototype.addSingleResult=function(a,c,d,e,g,n,z){var T=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);n&&"object"===typeof n&&(n=n.kB);z&&"object"===typeof z&&(z=z.kB);return Ij(T,a,c,d,e,g,n,z)};BE.prototype.__destroy__=function(){Jj(this.kB)};function CE(){throw"cannot construct a LocalShapeInfo, no constructor in IDL";}CE.prototype=Object.create(f.prototype);
|
||||
CE.prototype.constructor=CE;CE.prototype.lB=CE;CE.mB={};b.LocalShapeInfo=CE;CE.prototype.get_m_shapePart=CE.prototype.gE=function(){return Kj(this.kB)};CE.prototype.set_m_shapePart=CE.prototype.ZG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Lj(c,a)};Object.defineProperty(CE.prototype,"m_shapePart",{get:CE.prototype.gE,set:CE.prototype.ZG});CE.prototype.get_m_triangleIndex=CE.prototype.vE=function(){return Mj(this.kB)};
|
||||
CE.prototype.set_m_triangleIndex=CE.prototype.nH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Nj(c,a)};Object.defineProperty(CE.prototype,"m_triangleIndex",{get:CE.prototype.vE,set:CE.prototype.nH});CE.prototype.__destroy__=function(){Oj(this.kB)};function F(a,c,d,e,g){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);this.kB=Pj(a,c,d,e,g);h(F)[this.kB]=this}
|
||||
F.prototype=Object.create(f.prototype);F.prototype.constructor=F;F.prototype.lB=F;F.mB={};b.LocalConvexResult=F;F.prototype.get_m_hitCollisionObject=F.prototype.LB=function(){return k(Qj(this.kB),q)};F.prototype.set_m_hitCollisionObject=F.prototype.VB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Rj(c,a)};Object.defineProperty(F.prototype,"m_hitCollisionObject",{get:F.prototype.LB,set:F.prototype.VB});F.prototype.get_m_localShapeInfo=F.prototype.ID=function(){return k(Sj(this.kB),CE)};
|
||||
F.prototype.set_m_localShapeInfo=F.prototype.zG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Tj(c,a)};Object.defineProperty(F.prototype,"m_localShapeInfo",{get:F.prototype.ID,set:F.prototype.zG});F.prototype.get_m_hitNormalLocal=F.prototype.sD=function(){return k(Uj(this.kB),m)};F.prototype.set_m_hitNormalLocal=F.prototype.jG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vj(c,a)};Object.defineProperty(F.prototype,"m_hitNormalLocal",{get:F.prototype.sD,set:F.prototype.jG});
|
||||
F.prototype.get_m_hitPointLocal=F.prototype.uD=function(){return k(Wj(this.kB),m)};F.prototype.set_m_hitPointLocal=F.prototype.lG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Xj(c,a)};Object.defineProperty(F.prototype,"m_hitPointLocal",{get:F.prototype.uD,set:F.prototype.lG});F.prototype.get_m_hitFraction=F.prototype.pD=function(){return Yj(this.kB)};F.prototype.set_m_hitFraction=F.prototype.gG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Zj(c,a)};
|
||||
Object.defineProperty(F.prototype,"m_hitFraction",{get:F.prototype.pD,set:F.prototype.gG});F.prototype.__destroy__=function(){ak(this.kB)};function G(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=bk(a,c);h(G)[this.kB]=this}G.prototype=Object.create(v.prototype);G.prototype.constructor=G;G.prototype.lB=G;G.mB={};b.ClosestConvexResultCallback=G;G.prototype.hasHit=function(){return!!ck(this.kB)};
|
||||
G.prototype.get_m_hitCollisionObject=G.prototype.LB=function(){return k(dk(this.kB),q)};G.prototype.set_m_hitCollisionObject=G.prototype.VB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ek(c,a)};Object.defineProperty(G.prototype,"m_hitCollisionObject",{get:G.prototype.LB,set:G.prototype.VB});G.prototype.get_m_convexFromWorld=G.prototype.ZC=function(){return k(fk(this.kB),m)};
|
||||
G.prototype.set_m_convexFromWorld=G.prototype.QF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);gk(c,a)};Object.defineProperty(G.prototype,"m_convexFromWorld",{get:G.prototype.ZC,set:G.prototype.QF});G.prototype.get_m_convexToWorld=G.prototype.$C=function(){return k(hk(this.kB),m)};G.prototype.set_m_convexToWorld=G.prototype.RF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ik(c,a)};Object.defineProperty(G.prototype,"m_convexToWorld",{get:G.prototype.$C,set:G.prototype.RF});
|
||||
G.prototype.get_m_hitNormalWorld=G.prototype.xB=function(){return k(jk(this.kB),m)};G.prototype.set_m_hitNormalWorld=G.prototype.EB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);kk(c,a)};Object.defineProperty(G.prototype,"m_hitNormalWorld",{get:G.prototype.xB,set:G.prototype.EB});G.prototype.get_m_hitPointWorld=G.prototype.yB=function(){return k(lk(this.kB),m)};G.prototype.set_m_hitPointWorld=G.prototype.FB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);mk(c,a)};
|
||||
Object.defineProperty(G.prototype,"m_hitPointWorld",{get:G.prototype.yB,set:G.prototype.FB});G.prototype.get_m_collisionFilterGroup=G.prototype.nB=function(){return nk(this.kB)};G.prototype.set_m_collisionFilterGroup=G.prototype.pB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ok(c,a)};Object.defineProperty(G.prototype,"m_collisionFilterGroup",{get:G.prototype.nB,set:G.prototype.pB});G.prototype.get_m_collisionFilterMask=G.prototype.oB=function(){return pk(this.kB)};
|
||||
G.prototype.set_m_collisionFilterMask=G.prototype.qB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);qk(c,a)};Object.defineProperty(G.prototype,"m_collisionFilterMask",{get:G.prototype.oB,set:G.prototype.qB});G.prototype.get_m_closestHitFraction=G.prototype.rB=function(){return rk(this.kB)};G.prototype.set_m_closestHitFraction=G.prototype.sB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);sk(c,a)};Object.defineProperty(G.prototype,"m_closestHitFraction",{get:G.prototype.rB,set:G.prototype.sB});
|
||||
G.prototype.__destroy__=function(){tk(this.kB)};function DE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=void 0===c?uk(a):vk(a,c);h(DE)[this.kB]=this}DE.prototype=Object.create(fE.prototype);DE.prototype.constructor=DE;DE.prototype.lB=DE;DE.mB={};b.btConvexTriangleMeshShape=DE;DE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);wk(c,a)};DE.prototype.getLocalScaling=function(){return k(xk(this.kB),m)};
|
||||
DE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);yk(d,a,c)};DE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zk(c,a)};DE.prototype.getMargin=function(){return Ak(this.kB)};DE.prototype.__destroy__=function(){Bk(this.kB)};function EE(a){a&&"object"===typeof a&&(a=a.kB);this.kB=Ck(a);h(EE)[this.kB]=this}EE.prototype=Object.create(l.prototype);EE.prototype.constructor=EE;EE.prototype.lB=EE;
|
||||
EE.mB={};b.btBoxShape=EE;EE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dk(c,a)};EE.prototype.getMargin=function(){return Ek(this.kB)};EE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Fk(c,a)};EE.prototype.getLocalScaling=function(){return k(Gk(this.kB),m)};EE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Hk(d,a,c)};EE.prototype.__destroy__=function(){Ik(this.kB)};
|
||||
function FE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=Jk(a,c);h(FE)[this.kB]=this}FE.prototype=Object.create(gE.prototype);FE.prototype.constructor=FE;FE.prototype.lB=FE;FE.mB={};b.btCapsuleShapeX=FE;FE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Kk(c,a)};FE.prototype.getMargin=function(){return Lk(this.kB)};FE.prototype.getUpAxis=function(){return Mk(this.kB)};FE.prototype.getRadius=function(){return Nk(this.kB)};
|
||||
FE.prototype.getHalfHeight=function(){return Ok(this.kB)};FE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Pk(c,a)};FE.prototype.getLocalScaling=function(){return k(Qk(this.kB),m)};FE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Rk(d,a,c)};FE.prototype.__destroy__=function(){Sk(this.kB)};
|
||||
function GE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=Tk(a,c);h(GE)[this.kB]=this}GE.prototype=Object.create(gE.prototype);GE.prototype.constructor=GE;GE.prototype.lB=GE;GE.mB={};b.btCapsuleShapeZ=GE;GE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Uk(c,a)};GE.prototype.getMargin=function(){return Vk(this.kB)};GE.prototype.getUpAxis=function(){return Wk(this.kB)};GE.prototype.getRadius=function(){return Xk(this.kB)};
|
||||
GE.prototype.getHalfHeight=function(){return Yk(this.kB)};GE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Zk(c,a)};GE.prototype.getLocalScaling=function(){return k($k(this.kB),m)};GE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);al(d,a,c)};GE.prototype.__destroy__=function(){bl(this.kB)};function HE(a){a&&"object"===typeof a&&(a=a.kB);this.kB=cl(a);h(HE)[this.kB]=this}
|
||||
HE.prototype=Object.create(hE.prototype);HE.prototype.constructor=HE;HE.prototype.lB=HE;HE.mB={};b.btCylinderShapeX=HE;HE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);dl(c,a)};HE.prototype.getMargin=function(){return el(this.kB)};HE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fl(c,a)};HE.prototype.getLocalScaling=function(){return k(gl(this.kB),m)};
|
||||
HE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);hl(d,a,c)};HE.prototype.__destroy__=function(){il(this.kB)};function IE(a){a&&"object"===typeof a&&(a=a.kB);this.kB=jl(a);h(IE)[this.kB]=this}IE.prototype=Object.create(hE.prototype);IE.prototype.constructor=IE;IE.prototype.lB=IE;IE.mB={};b.btCylinderShapeZ=IE;IE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);kl(c,a)};
|
||||
IE.prototype.getMargin=function(){return ll(this.kB)};IE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ml(c,a)};IE.prototype.getLocalScaling=function(){return k(nl(this.kB),m)};IE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);ol(d,a,c)};IE.prototype.__destroy__=function(){pl(this.kB)};function JE(a){a&&"object"===typeof a&&(a=a.kB);this.kB=ql(a);h(JE)[this.kB]=this}JE.prototype=Object.create(l.prototype);
|
||||
JE.prototype.constructor=JE;JE.prototype.lB=JE;JE.mB={};b.btSphereShape=JE;JE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);rl(c,a)};JE.prototype.getMargin=function(){return sl(this.kB)};JE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);tl(c,a)};JE.prototype.getLocalScaling=function(){return k(ul(this.kB),m)};
|
||||
JE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);vl(d,a,c)};JE.prototype.__destroy__=function(){wl(this.kB)};function KE(a,c,d){ND();a&&"object"===typeof a&&(a=a.kB);"object"==typeof c&&(c=RD(c));d&&"object"===typeof d&&(d=d.kB);this.kB=xl(a,c,d);h(KE)[this.kB]=this}KE.prototype=Object.create(l.prototype);KE.prototype.constructor=KE;KE.prototype.lB=KE;KE.mB={};b.btMultiSphereShape=KE;
|
||||
KE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yl(c,a)};KE.prototype.getLocalScaling=function(){return k(zl(this.kB),m)};KE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Al(d,a,c)};KE.prototype.__destroy__=function(){Bl(this.kB)};function LE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=Cl(a,c);h(LE)[this.kB]=this}LE.prototype=Object.create(iE.prototype);
|
||||
LE.prototype.constructor=LE;LE.prototype.lB=LE;LE.mB={};b.btConeShapeX=LE;LE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dl(c,a)};LE.prototype.getLocalScaling=function(){return k(El(this.kB),m)};LE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Fl(d,a,c)};LE.prototype.__destroy__=function(){Gl(this.kB)};
|
||||
function ME(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=Hl(a,c);h(ME)[this.kB]=this}ME.prototype=Object.create(iE.prototype);ME.prototype.constructor=ME;ME.prototype.lB=ME;ME.mB={};b.btConeShapeZ=ME;ME.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Il(c,a)};ME.prototype.getLocalScaling=function(){return k(Jl(this.kB),m)};
|
||||
ME.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Kl(d,a,c)};ME.prototype.__destroy__=function(){Ll(this.kB)};function NE(){throw"cannot construct a btIntArray, no constructor in IDL";}NE.prototype=Object.create(f.prototype);NE.prototype.constructor=NE;NE.prototype.lB=NE;NE.mB={};b.btIntArray=NE;NE.prototype.size=NE.prototype.size=function(){return Ml(this.kB)};
|
||||
NE.prototype.at=NE.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return Nl(c,a)};NE.prototype.__destroy__=function(){Ol(this.kB)};function OE(){throw"cannot construct a btFace, no constructor in IDL";}OE.prototype=Object.create(f.prototype);OE.prototype.constructor=OE;OE.prototype.lB=OE;OE.mB={};b.btFace=OE;OE.prototype.get_m_indices=OE.prototype.xD=function(){return k(Pl(this.kB),NE)};
|
||||
OE.prototype.set_m_indices=OE.prototype.oG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ql(c,a)};Object.defineProperty(OE.prototype,"m_indices",{get:OE.prototype.xD,set:OE.prototype.oG});OE.prototype.get_m_plane=OE.prototype.WD=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return Rl(c,a)};OE.prototype.set_m_plane=OE.prototype.NG=function(a,c){var d=this.kB;ND();a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Sl(d,a,c)};
|
||||
Object.defineProperty(OE.prototype,"m_plane",{get:OE.prototype.WD,set:OE.prototype.NG});OE.prototype.__destroy__=function(){Tl(this.kB)};function AE(){throw"cannot construct a btVector3Array, no constructor in IDL";}AE.prototype=Object.create(f.prototype);AE.prototype.constructor=AE;AE.prototype.lB=AE;AE.mB={};b.btVector3Array=AE;AE.prototype.size=AE.prototype.size=function(){return Ul(this.kB)};
|
||||
AE.prototype.at=AE.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Vl(c,a),m)};AE.prototype.__destroy__=function(){Wl(this.kB)};function PE(){throw"cannot construct a btFaceArray, no constructor in IDL";}PE.prototype=Object.create(f.prototype);PE.prototype.constructor=PE;PE.prototype.lB=PE;PE.mB={};b.btFaceArray=PE;PE.prototype.size=PE.prototype.size=function(){return Xl(this.kB)};
|
||||
PE.prototype.at=PE.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Yl(c,a),OE)};PE.prototype.__destroy__=function(){Zl(this.kB)};function QE(){throw"cannot construct a btConvexPolyhedron, no constructor in IDL";}QE.prototype=Object.create(f.prototype);QE.prototype.constructor=QE;QE.prototype.lB=QE;QE.mB={};b.btConvexPolyhedron=QE;QE.prototype.get_m_vertices=QE.prototype.BE=function(){return k($l(this.kB),AE)};
|
||||
QE.prototype.set_m_vertices=QE.prototype.tH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);am(c,a)};Object.defineProperty(QE.prototype,"m_vertices",{get:QE.prototype.BE,set:QE.prototype.tH});QE.prototype.get_m_faces=QE.prototype.KB=function(){return k(bm(this.kB),PE)};QE.prototype.set_m_faces=QE.prototype.UB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);cm(c,a)};Object.defineProperty(QE.prototype,"m_faces",{get:QE.prototype.KB,set:QE.prototype.UB});
|
||||
QE.prototype.__destroy__=function(){dm(this.kB)};function RE(a,c){ND();"object"==typeof a&&(a=RD(a));c&&"object"===typeof c&&(c=c.kB);this.kB=void 0===a?em():void 0===c?fm(a):gm(a,c);h(RE)[this.kB]=this}RE.prototype=Object.create(l.prototype);RE.prototype.constructor=RE;RE.prototype.lB=RE;RE.mB={};b.btConvexHullShape=RE;RE.prototype.addPoint=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);void 0===c?hm(d,a):im(d,a,c)};
|
||||
RE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jm(c,a)};RE.prototype.getMargin=function(){return km(this.kB)};RE.prototype.getNumVertices=function(){return lm(this.kB)};RE.prototype.initializePolyhedralFeatures=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return!!mm(c,a)};RE.prototype.recalcLocalAabb=function(){nm(this.kB)};RE.prototype.getConvexPolyhedron=function(){return k(om(this.kB),QE)};
|
||||
RE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pm(c,a)};RE.prototype.getLocalScaling=function(){return k(qm(this.kB),m)};RE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);rm(d,a,c)};RE.prototype.__destroy__=function(){sm(this.kB)};function SE(a){a&&"object"===typeof a&&(a=a.kB);this.kB=tm(a);h(SE)[this.kB]=this}SE.prototype=Object.create(f.prototype);SE.prototype.constructor=SE;
|
||||
SE.prototype.lB=SE;SE.mB={};b.btShapeHull=SE;SE.prototype.buildHull=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return!!um(c,a)};SE.prototype.numVertices=function(){return wm(this.kB)};SE.prototype.getVertexPointer=function(){return k(xm(this.kB),m)};SE.prototype.__destroy__=function(){ym(this.kB)};function TE(a){a&&"object"===typeof a&&(a=a.kB);this.kB=void 0===a?zm():Am(a);h(TE)[this.kB]=this}TE.prototype=Object.create(l.prototype);TE.prototype.constructor=TE;TE.prototype.lB=TE;
|
||||
TE.mB={};b.btCompoundShape=TE;TE.prototype.addChildShape=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Bm(d,a,c)};TE.prototype.removeChildShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Cm(c,a)};TE.prototype.removeChildShapeByIndex=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dm(c,a)};TE.prototype.getNumChildShapes=function(){return Em(this.kB)};
|
||||
TE.prototype.getChildShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Fm(c,a),l)};TE.prototype.updateChildTransform=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===d?Gm(e,a,c):Hm(e,a,c,d)};TE.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Im(c,a)};TE.prototype.getMargin=function(){return Jm(this.kB)};
|
||||
TE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Km(c,a)};TE.prototype.getLocalScaling=function(){return k(Lm(this.kB),m)};TE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Mm(d,a,c)};TE.prototype.__destroy__=function(){Nm(this.kB)};function UE(){throw"cannot construct a btIndexedMesh, no constructor in IDL";}UE.prototype=Object.create(f.prototype);UE.prototype.constructor=UE;
|
||||
UE.prototype.lB=UE;UE.mB={};b.btIndexedMesh=UE;UE.prototype.get_m_numTriangles=UE.prototype.UD=function(){return Om(this.kB)};UE.prototype.set_m_numTriangles=UE.prototype.LG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Pm(c,a)};Object.defineProperty(UE.prototype,"m_numTriangles",{get:UE.prototype.UD,set:UE.prototype.LG});UE.prototype.__destroy__=function(){Qm(this.kB)};function VE(){throw"cannot construct a btIndexedMeshArray, no constructor in IDL";}VE.prototype=Object.create(f.prototype);
|
||||
VE.prototype.constructor=VE;VE.prototype.lB=VE;VE.mB={};b.btIndexedMeshArray=VE;VE.prototype.size=VE.prototype.size=function(){return Rm(this.kB)};VE.prototype.at=VE.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Sm(c,a),UE)};VE.prototype.__destroy__=function(){Tm(this.kB)};function WE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=void 0===a?Um():void 0===c?Vm(a):Wm(a,c);h(WE)[this.kB]=this}WE.prototype=Object.create(jE.prototype);
|
||||
WE.prototype.constructor=WE;WE.prototype.lB=WE;WE.mB={};b.btTriangleMesh=WE;WE.prototype.addTriangle=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);void 0===e?Xm(g,a,c,d):Ym(g,a,c,d,e)};WE.prototype.findOrAddVertex=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return Zm(d,a,c)};
|
||||
WE.prototype.addIndex=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$m(c,a)};WE.prototype.getIndexedMeshArray=function(){return k(an(this.kB),VE)};WE.prototype.setScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);bn(c,a)};WE.prototype.__destroy__=function(){cn(this.kB)};function XE(){this.kB=dn();h(XE)[this.kB]=this}XE.prototype=Object.create(ZD.prototype);XE.prototype.constructor=XE;XE.prototype.lB=XE;XE.mB={};b.btEmptyShape=XE;
|
||||
XE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);en(c,a)};XE.prototype.getLocalScaling=function(){return k(fn(this.kB),m)};XE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);gn(d,a,c)};XE.prototype.__destroy__=function(){hn(this.kB)};function YE(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=jn(a,c);h(YE)[this.kB]=this}YE.prototype=Object.create(ZD.prototype);
|
||||
YE.prototype.constructor=YE;YE.prototype.lB=YE;YE.mB={};b.btStaticPlaneShape=YE;YE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);kn(c,a)};YE.prototype.getLocalScaling=function(){return k(ln(this.kB),m)};YE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);mn(d,a,c)};YE.prototype.__destroy__=function(){nn(this.kB)};
|
||||
function ZE(a,c,d){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);this.kB=void 0===d?on(a,c):pn(a,c,d);h(ZE)[this.kB]=this}ZE.prototype=Object.create(kE.prototype);ZE.prototype.constructor=ZE;ZE.prototype.lB=ZE;ZE.mB={};b.btBvhTriangleMeshShape=ZE;ZE.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);qn(c,a)};ZE.prototype.getLocalScaling=function(){return k(rn(this.kB),m)};
|
||||
ZE.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);sn(d,a,c)};ZE.prototype.__destroy__=function(){tn(this.kB)};
|
||||
function $E(a,c,d,e,g,n,z,T,Da){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);n&&"object"===typeof n&&(n=n.kB);z&&"object"===typeof z&&(z=z.kB);T&&"object"===typeof T&&(T=T.kB);Da&&"object"===typeof Da&&(Da=Da.kB);this.kB=un(a,c,d,e,g,n,z,T,Da);h($E)[this.kB]=this}$E.prototype=Object.create(ZD.prototype);$E.prototype.constructor=$E;$E.prototype.lB=$E;$E.mB={};
|
||||
b.btHeightfieldTerrainShape=$E;$E.prototype.setMargin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vn(c,a)};$E.prototype.getMargin=function(){return wn(this.kB)};$E.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xn(c,a)};$E.prototype.getLocalScaling=function(){return k(yn(this.kB),m)};$E.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);zn(d,a,c)};
|
||||
$E.prototype.__destroy__=function(){An(this.kB)};function aF(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=Bn(a,c,d,e);h(aF)[this.kB]=this}aF.prototype=Object.create(f.prototype);aF.prototype.constructor=aF;aF.prototype.lB=aF;aF.mB={};b.btAABB=aF;aF.prototype.invalidate=function(){Cn(this.kB)};aF.prototype.increment_margin=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dn(c,a)};
|
||||
aF.prototype.copy_with_margin=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);En(d,a,c)};aF.prototype.__destroy__=function(){Fn(this.kB)};function bF(){this.kB=Gn();h(bF)[this.kB]=this}bF.prototype=Object.create(f.prototype);bF.prototype.constructor=bF;bF.prototype.lB=bF;bF.mB={};b.btPrimitiveTriangle=bF;bF.prototype.__destroy__=function(){Hn(this.kB)};
|
||||
function cF(a,c,d){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);this.kB=In(a,c,d);h(cF)[this.kB]=this}cF.prototype=Object.create(f.prototype);cF.prototype.constructor=cF;cF.prototype.lB=cF;cF.mB={};b.btTriangleShapeEx=cF;cF.prototype.getAabb=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Jn(e,a,c,d)};
|
||||
cF.prototype.applyTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Kn(c,a)};cF.prototype.buildTriPlane=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ln(c,a)};cF.prototype.__destroy__=function(){Mn(this.kB)};function dF(){this.kB=Nn();h(dF)[this.kB]=this}dF.prototype=Object.create(f.prototype);dF.prototype.constructor=dF;dF.prototype.lB=dF;dF.mB={};b.btTetrahedronShapeEx=dF;
|
||||
dF.prototype.setVertices=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);On(g,a,c,d,e)};dF.prototype.__destroy__=function(){Pn(this.kB)};function eF(){throw"cannot construct a CompoundPrimitiveManager, no constructor in IDL";}eF.prototype=Object.create(lE.prototype);eF.prototype.constructor=eF;eF.prototype.lB=eF;eF.mB={};b.CompoundPrimitiveManager=eF;
|
||||
eF.prototype.get_primitive_count=function(){return Qn(this.kB)};eF.prototype.get_primitive_box=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Rn(d,a,c)};eF.prototype.get_primitive_triangle=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Sn(d,a,c)};eF.prototype.is_trimesh=function(){return!!Tn(this.kB)};eF.prototype.get_m_compoundShape=eF.prototype.VC=function(){return k(Un(this.kB),H)};
|
||||
eF.prototype.set_m_compoundShape=eF.prototype.MF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vn(c,a)};Object.defineProperty(eF.prototype,"m_compoundShape",{get:eF.prototype.VC,set:eF.prototype.MF});eF.prototype.__destroy__=function(){Wn(this.kB)};function H(a){a&&"object"===typeof a&&(a=a.kB);this.kB=void 0===a?Xn():Yn(a);h(H)[this.kB]=this}H.prototype=Object.create(w.prototype);H.prototype.constructor=H;H.prototype.lB=H;H.mB={};b.btGImpactCompoundShape=H;
|
||||
H.prototype.childrenHasTransform=function(){return!!Zn(this.kB)};H.prototype.getPrimitiveManager=function(){return k($n(this.kB),lE)};H.prototype.getCompoundPrimitiveManager=function(){return k(ao(this.kB),eF)};H.prototype.getNumChildShapes=function(){return bo(this.kB)};H.prototype.addChildShape=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);co(d,a,c)};
|
||||
H.prototype.getChildShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(eo(c,a),l)};H.prototype.getChildAabb=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);fo(g,a,c,d,e)};H.prototype.getChildTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(go(c,a),r)};
|
||||
H.prototype.setChildTransform=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);ho(d,a,c)};H.prototype.calculateLocalInertia=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);io(d,a,c)};H.prototype.getName=function(){return sa(jo(this.kB))};H.prototype.getGImpactShapeType=function(){return ko(this.kB)};H.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);lo(c,a)};
|
||||
H.prototype.getLocalScaling=function(){return k(mo(this.kB),m)};H.prototype.updateBound=function(){no(this.kB)};H.prototype.postUpdate=function(){oo(this.kB)};H.prototype.getShapeType=function(){return po(this.kB)};H.prototype.needsRetrieveTriangles=function(){return!!qo(this.kB)};H.prototype.needsRetrieveTetrahedrons=function(){return!!ro(this.kB)};H.prototype.getBulletTriangle=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);so(d,a,c)};
|
||||
H.prototype.getBulletTetrahedron=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);to(d,a,c)};H.prototype.__destroy__=function(){uo(this.kB)};function I(a){a&&"object"===typeof a&&(a=a.kB);this.kB=void 0===a?vo():wo(a);h(I)[this.kB]=this}I.prototype=Object.create(lE.prototype);I.prototype.constructor=I;I.prototype.lB=I;I.mB={};b.TrimeshPrimitiveManager=I;I.prototype.lock=I.prototype.lock=function(){xo(this.kB)};I.prototype.unlock=I.prototype.unlock=function(){yo(this.kB)};
|
||||
I.prototype.is_trimesh=function(){return!!zo(this.kB)};I.prototype.get_vertex_count=function(){return Ao(this.kB)};I.prototype.get_indices=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);Bo(g,a,c,d,e)};I.prototype.get_vertex=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Co(d,a,c)};
|
||||
I.prototype.get_bullet_triangle=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Do(d,a,c)};I.prototype.get_m_margin=I.prototype.LD=function(){return Eo(this.kB)};I.prototype.set_m_margin=I.prototype.CG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Fo(c,a)};Object.defineProperty(I.prototype,"m_margin",{get:I.prototype.LD,set:I.prototype.CG});I.prototype.get_m_meshInterface=I.prototype.OD=function(){return k(Go(this.kB),jE)};
|
||||
I.prototype.set_m_meshInterface=I.prototype.FG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ho(c,a)};Object.defineProperty(I.prototype,"m_meshInterface",{get:I.prototype.OD,set:I.prototype.FG});I.prototype.get_m_part=I.prototype.VD=function(){return Io(this.kB)};I.prototype.set_m_part=I.prototype.MG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jo(c,a)};Object.defineProperty(I.prototype,"m_part",{get:I.prototype.VD,set:I.prototype.MG});
|
||||
I.prototype.get_m_lock_count=I.prototype.JD=function(){return Ko(this.kB)};I.prototype.set_m_lock_count=I.prototype.AG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Lo(c,a)};Object.defineProperty(I.prototype,"m_lock_count",{get:I.prototype.JD,set:I.prototype.AG});I.prototype.get_numverts=I.prototype.LE=function(){return Mo(this.kB)};I.prototype.set_numverts=I.prototype.DH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);No(c,a)};
|
||||
Object.defineProperty(I.prototype,"numverts",{get:I.prototype.LE,set:I.prototype.DH});I.prototype.get_type=I.prototype.PE=function(){return Oo(this.kB)};I.prototype.set_type=I.prototype.HH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Po(c,a)};Object.defineProperty(I.prototype,"type",{get:I.prototype.PE,set:I.prototype.HH});I.prototype.get_stride=I.prototype.NE=function(){return Qo(this.kB)};
|
||||
I.prototype.set_stride=I.prototype.FH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ro(c,a)};Object.defineProperty(I.prototype,"stride",{get:I.prototype.NE,set:I.prototype.FH});I.prototype.get_indexstride=I.prototype.gC=function(){return So(this.kB)};I.prototype.set_indexstride=I.prototype.YE=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);To(c,a)};Object.defineProperty(I.prototype,"indexstride",{get:I.prototype.gC,set:I.prototype.YE});
|
||||
I.prototype.get_numfaces=I.prototype.KE=function(){return Uo(this.kB)};I.prototype.set_numfaces=I.prototype.CH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vo(c,a)};Object.defineProperty(I.prototype,"numfaces",{get:I.prototype.KE,set:I.prototype.CH});I.prototype.get_indicestype=I.prototype.hC=function(){return Wo(this.kB)};I.prototype.set_indicestype=I.prototype.ZE=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Xo(c,a)};
|
||||
Object.defineProperty(I.prototype,"indicestype",{get:I.prototype.hC,set:I.prototype.ZE});I.prototype.__destroy__=function(){Yo(this.kB)};function fF(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=Zo(a,c);h(fF)[this.kB]=this}fF.prototype=Object.create(w.prototype);fF.prototype.constructor=fF;fF.prototype.lB=fF;fF.mB={};b.btGImpactMeshShapePart=fF;fF.prototype.getTrimeshPrimitiveManager=function(){return k($o(this.kB),I)};fF.prototype.getVertexCount=function(){return ap(this.kB)};
|
||||
fF.prototype.getVertex=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);bp(d,a,c)};fF.prototype.getPart=function(){return cp(this.kB)};fF.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);dp(c,a)};fF.prototype.getLocalScaling=function(){return k(ep(this.kB),m)};fF.prototype.updateBound=function(){fp(this.kB)};fF.prototype.postUpdate=function(){gp(this.kB)};fF.prototype.getShapeType=function(){return hp(this.kB)};
|
||||
fF.prototype.needsRetrieveTriangles=function(){return!!ip(this.kB)};fF.prototype.needsRetrieveTetrahedrons=function(){return!!jp(this.kB)};fF.prototype.getBulletTriangle=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);kp(d,a,c)};fF.prototype.getBulletTetrahedron=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);lp(d,a,c)};fF.prototype.__destroy__=function(){mp(this.kB)};
|
||||
function gF(a){a&&"object"===typeof a&&(a=a.kB);this.kB=np(a);h(gF)[this.kB]=this}gF.prototype=Object.create(w.prototype);gF.prototype.constructor=gF;gF.prototype.lB=gF;gF.mB={};b.btGImpactMeshShape=gF;gF.prototype.getMeshInterface=function(){return k(op(this.kB),jE)};gF.prototype.getMeshPartCount=function(){return pp(this.kB)};gF.prototype.getMeshPart=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(qp(c,a),fF)};gF.prototype.calculateSerializeBufferSize=function(){return rp(this.kB)};
|
||||
gF.prototype.setLocalScaling=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);sp(c,a)};gF.prototype.getLocalScaling=function(){return k(tp(this.kB),m)};gF.prototype.updateBound=function(){up(this.kB)};gF.prototype.postUpdate=function(){vp(this.kB)};gF.prototype.getShapeType=function(){return wp(this.kB)};gF.prototype.needsRetrieveTriangles=function(){return!!xp(this.kB)};gF.prototype.needsRetrieveTetrahedrons=function(){return!!yp(this.kB)};
|
||||
gF.prototype.getBulletTriangle=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);zp(d,a,c)};gF.prototype.getBulletTetrahedron=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Ap(d,a,c)};gF.prototype.__destroy__=function(){Bp(this.kB)};
|
||||
function hF(a,c){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);this.kB=void 0===a?Cp():void 0===c?_emscripten_bind_btCollisionAlgorithmConstructionInfo_btCollisionAlgorithmConstructionInfo_1(a):Dp(a,c);h(hF)[this.kB]=this}hF.prototype=Object.create(f.prototype);hF.prototype.constructor=hF;hF.prototype.lB=hF;hF.mB={};b.btCollisionAlgorithmConstructionInfo=hF;hF.prototype.get_m_dispatcher1=hF.prototype.eD=function(){return k(Ep(this.kB),TD)};
|
||||
hF.prototype.set_m_dispatcher1=hF.prototype.WF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Fp(c,a)};Object.defineProperty(hF.prototype,"m_dispatcher1",{get:hF.prototype.eD,set:hF.prototype.WF});hF.prototype.get_m_manifold=hF.prototype.KD=function(){return k(Gp(this.kB),oE)};hF.prototype.set_m_manifold=hF.prototype.BG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Hp(c,a)};Object.defineProperty(hF.prototype,"m_manifold",{get:hF.prototype.KD,set:hF.prototype.BG});
|
||||
hF.prototype.__destroy__=function(){Ip(this.kB)};function iF(a,c,d){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);this.kB=Jp(a,c,d);h(iF)[this.kB]=this}iF.prototype=Object.create(mE.prototype);iF.prototype.constructor=iF;iF.prototype.lB=iF;iF.mB={};b.btGImpactCollisionAlgorithm=iF;iF.prototype.registerAlgorithm=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Kp(c,a)};iF.prototype.__destroy__=function(){Lp(this.kB)};
|
||||
function jF(){this.kB=Mp();h(jF)[this.kB]=this}jF.prototype=Object.create(f.prototype);jF.prototype.constructor=jF;jF.prototype.lB=jF;jF.mB={};b.btDefaultCollisionConstructionInfo=jF;jF.prototype.__destroy__=function(){Np(this.kB)};function oE(){this.kB=Op();h(oE)[this.kB]=this}oE.prototype=Object.create(f.prototype);oE.prototype.constructor=oE;oE.prototype.lB=oE;oE.mB={};b.btPersistentManifold=oE;oE.prototype.getBody0=function(){return k(Pp(this.kB),q)};
|
||||
oE.prototype.getBody1=function(){return k(Qp(this.kB),q)};oE.prototype.getNumContacts=function(){return Rp(this.kB)};oE.prototype.getContactPoint=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Sp(c,a),E)};oE.prototype.__destroy__=function(){Tp(this.kB)};function kF(a){a&&"object"===typeof a&&(a=a.kB);this.kB=Up(a);h(kF)[this.kB]=this}kF.prototype=Object.create(TD.prototype);kF.prototype.constructor=kF;kF.prototype.lB=kF;kF.mB={};b.btCollisionDispatcher=kF;
|
||||
kF.prototype.getNumManifolds=function(){return Vp(this.kB)};kF.prototype.getManifoldByIndexInternal=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Wp(c,a),oE)};kF.prototype.__destroy__=function(){Xp(this.kB)};function lF(){throw"cannot construct a btOverlappingPairCallback, no constructor in IDL";}lF.prototype=Object.create(f.prototype);lF.prototype.constructor=lF;lF.prototype.lB=lF;lF.mB={};b.btOverlappingPairCallback=lF;lF.prototype.__destroy__=function(){Yp(this.kB)};
|
||||
function UD(){throw"cannot construct a btOverlappingPairCache, no constructor in IDL";}UD.prototype=Object.create(f.prototype);UD.prototype.constructor=UD;UD.prototype.lB=UD;UD.mB={};b.btOverlappingPairCache=UD;UD.prototype.setInternalGhostPairCallback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Zp(c,a)};UD.prototype.getNumOverlappingPairs=function(){return $p(this.kB)};UD.prototype.__destroy__=function(){aq(this.kB)};
|
||||
function mF(a,c,d,e,g){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);this.kB=void 0===d?bq(a,c):void 0===e?cq(a,c,d):void 0===g?dq(a,c,d,e):eq(a,c,d,e,g);h(mF)[this.kB]=this}mF.prototype=Object.create(f.prototype);mF.prototype.constructor=mF;mF.prototype.lB=mF;mF.mB={};b.btAxisSweep3=mF;mF.prototype.__destroy__=function(){fq(this.kB)};
|
||||
function VD(){throw"cannot construct a btBroadphaseInterface, no constructor in IDL";}VD.prototype=Object.create(f.prototype);VD.prototype.constructor=VD;VD.prototype.lB=VD;VD.mB={};b.btBroadphaseInterface=VD;VD.prototype.getOverlappingPairCache=function(){return k(gq(this.kB),UD)};VD.prototype.__destroy__=function(){hq(this.kB)};function nF(){throw"cannot construct a btCollisionConfiguration, no constructor in IDL";}nF.prototype=Object.create(f.prototype);nF.prototype.constructor=nF;
|
||||
nF.prototype.lB=nF;nF.mB={};b.btCollisionConfiguration=nF;nF.prototype.__destroy__=function(){iq(this.kB)};function oF(){this.kB=jq();h(oF)[this.kB]=this}oF.prototype=Object.create(f.prototype);oF.prototype.constructor=oF;oF.prototype.lB=oF;oF.mB={};b.btDbvtBroadphase=oF;oF.prototype.__destroy__=function(){kq(this.kB)};function YD(){throw"cannot construct a btBroadphaseProxy, no constructor in IDL";}YD.prototype=Object.create(f.prototype);YD.prototype.constructor=YD;YD.prototype.lB=YD;YD.mB={};
|
||||
b.btBroadphaseProxy=YD;YD.prototype.get_m_collisionFilterGroup=YD.prototype.nB=function(){return lq(this.kB)};YD.prototype.set_m_collisionFilterGroup=YD.prototype.pB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);mq(c,a)};Object.defineProperty(YD.prototype,"m_collisionFilterGroup",{get:YD.prototype.nB,set:YD.prototype.pB});YD.prototype.get_m_collisionFilterMask=YD.prototype.oB=function(){return nq(this.kB)};
|
||||
YD.prototype.set_m_collisionFilterMask=YD.prototype.qB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);oq(c,a)};Object.defineProperty(YD.prototype,"m_collisionFilterMask",{get:YD.prototype.oB,set:YD.prototype.qB});YD.prototype.__destroy__=function(){pq(this.kB)};function J(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=void 0===e?qq(a,c,d):rq(a,c,d,e);h(J)[this.kB]=this}J.prototype=Object.create(f.prototype);
|
||||
J.prototype.constructor=J;J.prototype.lB=J;J.mB={};b.btRigidBodyConstructionInfo=J;J.prototype.get_m_linearDamping=J.prototype.DD=function(){return sq(this.kB)};J.prototype.set_m_linearDamping=J.prototype.uG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);tq(c,a)};Object.defineProperty(J.prototype,"m_linearDamping",{get:J.prototype.DD,set:J.prototype.uG});J.prototype.get_m_angularDamping=J.prototype.HC=function(){return uq(this.kB)};
|
||||
J.prototype.set_m_angularDamping=J.prototype.yF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vq(c,a)};Object.defineProperty(J.prototype,"m_angularDamping",{get:J.prototype.HC,set:J.prototype.yF});J.prototype.get_m_friction=J.prototype.kD=function(){return wq(this.kB)};J.prototype.set_m_friction=J.prototype.bG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xq(c,a)};Object.defineProperty(J.prototype,"m_friction",{get:J.prototype.kD,set:J.prototype.bG});
|
||||
J.prototype.get_m_rollingFriction=J.prototype.dE=function(){return yq(this.kB)};J.prototype.set_m_rollingFriction=J.prototype.WG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zq(c,a)};Object.defineProperty(J.prototype,"m_rollingFriction",{get:J.prototype.dE,set:J.prototype.WG});J.prototype.get_m_restitution=J.prototype.bE=function(){return Aq(this.kB)};J.prototype.set_m_restitution=J.prototype.UG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Bq(c,a)};
|
||||
Object.defineProperty(J.prototype,"m_restitution",{get:J.prototype.bE,set:J.prototype.UG});J.prototype.get_m_linearSleepingThreshold=J.prototype.ED=function(){return Cq(this.kB)};J.prototype.set_m_linearSleepingThreshold=J.prototype.vG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dq(c,a)};Object.defineProperty(J.prototype,"m_linearSleepingThreshold",{get:J.prototype.ED,set:J.prototype.vG});J.prototype.get_m_angularSleepingThreshold=J.prototype.IC=function(){return Eq(this.kB)};
|
||||
J.prototype.set_m_angularSleepingThreshold=J.prototype.zF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Fq(c,a)};Object.defineProperty(J.prototype,"m_angularSleepingThreshold",{get:J.prototype.IC,set:J.prototype.zF});J.prototype.get_m_additionalDamping=J.prototype.CC=function(){return!!Gq(this.kB)};J.prototype.set_m_additionalDamping=J.prototype.tF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Hq(c,a)};
|
||||
Object.defineProperty(J.prototype,"m_additionalDamping",{get:J.prototype.CC,set:J.prototype.tF});J.prototype.get_m_additionalDampingFactor=J.prototype.DC=function(){return Iq(this.kB)};J.prototype.set_m_additionalDampingFactor=J.prototype.uF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jq(c,a)};Object.defineProperty(J.prototype,"m_additionalDampingFactor",{get:J.prototype.DC,set:J.prototype.uF});J.prototype.get_m_additionalLinearDampingThresholdSqr=J.prototype.EC=function(){return Kq(this.kB)};
|
||||
J.prototype.set_m_additionalLinearDampingThresholdSqr=J.prototype.vF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Lq(c,a)};Object.defineProperty(J.prototype,"m_additionalLinearDampingThresholdSqr",{get:J.prototype.EC,set:J.prototype.vF});J.prototype.get_m_additionalAngularDampingThresholdSqr=J.prototype.BC=function(){return Mq(this.kB)};J.prototype.set_m_additionalAngularDampingThresholdSqr=J.prototype.sF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Nq(c,a)};
|
||||
Object.defineProperty(J.prototype,"m_additionalAngularDampingThresholdSqr",{get:J.prototype.BC,set:J.prototype.sF});J.prototype.get_m_additionalAngularDampingFactor=J.prototype.AC=function(){return Oq(this.kB)};J.prototype.set_m_additionalAngularDampingFactor=J.prototype.rF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Pq(c,a)};Object.defineProperty(J.prototype,"m_additionalAngularDampingFactor",{get:J.prototype.AC,set:J.prototype.rF});J.prototype.__destroy__=function(){Qq(this.kB)};
|
||||
function K(a){a&&"object"===typeof a&&(a=a.kB);this.kB=Rq(a);h(K)[this.kB]=this}K.prototype=Object.create(q.prototype);K.prototype.constructor=K;K.prototype.lB=K;K.mB={};b.btRigidBody=K;K.prototype.getCenterOfMassTransform=function(){return k(Sq(this.kB),r)};K.prototype.setCenterOfMassTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Tq(c,a)};K.prototype.setSleepingThresholds=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Uq(d,a,c)};
|
||||
K.prototype.getLinearDamping=function(){return Vq(this.kB)};K.prototype.getAngularDamping=function(){return Wq(this.kB)};K.prototype.setDamping=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Xq(d,a,c)};K.prototype.setMassProps=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Yq(d,a,c)};K.prototype.getLinearFactor=function(){return k(Zq(this.kB),m)};
|
||||
K.prototype.setLinearFactor=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$q(c,a)};K.prototype.applyTorque=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ar(c,a)};K.prototype.applyLocalTorque=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);br(c,a)};K.prototype.applyForce=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);cr(d,a,c)};
|
||||
K.prototype.applyCentralForce=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);dr(c,a)};K.prototype.applyCentralLocalForce=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);er(c,a)};K.prototype.applyTorqueImpulse=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fr(c,a)};K.prototype.applyImpulse=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);gr(d,a,c)};
|
||||
K.prototype.applyCentralImpulse=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hr(c,a)};K.prototype.updateInertiaTensor=function(){ir(this.kB)};K.prototype.getLinearVelocity=function(){return k(jr(this.kB),m)};K.prototype.getAngularVelocity=function(){return k(kr(this.kB),m)};K.prototype.setLinearVelocity=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);lr(c,a)};K.prototype.setAngularVelocity=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);mr(c,a)};
|
||||
K.prototype.getMotionState=function(){return k(nr(this.kB),dE)};K.prototype.setMotionState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);or(c,a)};K.prototype.getAngularFactor=function(){return k(pr(this.kB),m)};K.prototype.setAngularFactor=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);qr(c,a)};K.prototype.upcast=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(rr(c,a),K)};
|
||||
K.prototype.getAabb=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);sr(d,a,c)};K.prototype.applyGravity=function(){tr(this.kB)};K.prototype.getGravity=function(){return k(ur(this.kB),m)};K.prototype.setGravity=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vr(c,a)};K.prototype.getBroadphaseProxy=function(){return k(wr(this.kB),YD)};K.prototype.clearForces=function(){xr(this.kB)};
|
||||
K.prototype.setFlags=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yr(c,a)};K.prototype.getFlags=function(){return zr(this.kB)};K.prototype.setAnisotropicFriction=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Ar(d,a,c)};K.prototype.getCollisionShape=function(){return k(Br(this.kB),l)};K.prototype.setContactProcessingThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Cr(c,a)};
|
||||
K.prototype.setActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dr(c,a)};K.prototype.forceActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Er(c,a)};K.prototype.activate=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);void 0===a?Fr(c):Gr(c,a)};K.prototype.isActive=function(){return!!Hr(this.kB)};K.prototype.isKinematicObject=function(){return!!Ir(this.kB)};K.prototype.isStaticObject=function(){return!!Jr(this.kB)};
|
||||
K.prototype.isStaticOrKinematicObject=function(){return!!Kr(this.kB)};K.prototype.getRestitution=function(){return Lr(this.kB)};K.prototype.getFriction=function(){return Mr(this.kB)};K.prototype.getRollingFriction=function(){return Nr(this.kB)};K.prototype.setRestitution=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Or(c,a)};K.prototype.setFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Pr(c,a)};
|
||||
K.prototype.setRollingFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Qr(c,a)};K.prototype.getWorldTransform=function(){return k(Rr(this.kB),r)};K.prototype.getCollisionFlags=function(){return Sr(this.kB)};K.prototype.setCollisionFlags=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Tr(c,a)};K.prototype.setWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ur(c,a)};
|
||||
K.prototype.setCollisionShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vr(c,a)};K.prototype.setCcdMotionThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Wr(c,a)};K.prototype.setCcdSweptSphereRadius=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Xr(c,a)};K.prototype.getUserIndex=function(){return Yr(this.kB)};K.prototype.setUserIndex=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Zr(c,a)};
|
||||
K.prototype.getUserPointer=function(){return k($r(this.kB),XD)};K.prototype.setUserPointer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);as(c,a)};K.prototype.getBroadphaseHandle=function(){return k(bs(this.kB),YD)};K.prototype.__destroy__=function(){cs(this.kB)};function L(){this.kB=ds();h(L)[this.kB]=this}L.prototype=Object.create(f.prototype);L.prototype.constructor=L;L.prototype.lB=L;L.mB={};b.btConstraintSetting=L;L.prototype.get_m_tau=L.prototype.sE=function(){return es(this.kB)};
|
||||
L.prototype.set_m_tau=L.prototype.kH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);gs(c,a)};Object.defineProperty(L.prototype,"m_tau",{get:L.prototype.sE,set:L.prototype.kH});L.prototype.get_m_damping=L.prototype.aD=function(){return hs(this.kB)};L.prototype.set_m_damping=L.prototype.SF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);is(c,a)};Object.defineProperty(L.prototype,"m_damping",{get:L.prototype.aD,set:L.prototype.SF});
|
||||
L.prototype.get_m_impulseClamp=L.prototype.wD=function(){return js(this.kB)};L.prototype.set_m_impulseClamp=L.prototype.nG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ks(c,a)};Object.defineProperty(L.prototype,"m_impulseClamp",{get:L.prototype.wD,set:L.prototype.nG});L.prototype.__destroy__=function(){ls(this.kB)};
|
||||
function pF(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=void 0===d?ms(a,c):void 0===e?_emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_3(a,c,d):ns(a,c,d,e);h(pF)[this.kB]=this}pF.prototype=Object.create(aE.prototype);pF.prototype.constructor=pF;pF.prototype.lB=pF;pF.mB={};b.btPoint2PointConstraint=pF;
|
||||
pF.prototype.setPivotA=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ps(c,a)};pF.prototype.setPivotB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);qs(c,a)};pF.prototype.getPivotInA=function(){return k(rs(this.kB),m)};pF.prototype.getPivotInB=function(){return k(ss(this.kB),m)};pF.prototype.enableFeedback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ts(c,a)};pF.prototype.getBreakingImpulseThreshold=function(){return us(this.kB)};
|
||||
pF.prototype.setBreakingImpulseThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vs(c,a)};pF.prototype.getParam=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return xs(d,a,c)};pF.prototype.setParam=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);ys(e,a,c,d)};pF.prototype.get_m_setting=pF.prototype.fE=function(){return k(zs(this.kB),L)};
|
||||
pF.prototype.set_m_setting=pF.prototype.YG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);As(c,a)};Object.defineProperty(pF.prototype,"m_setting",{get:pF.prototype.fE,set:pF.prototype.YG});pF.prototype.__destroy__=function(){Bs(this.kB)};
|
||||
function qF(a,c,d,e,g){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);this.kB=void 0===e?Cs(a,c,d):void 0===g?_emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_4(a,c,d,e):Ds(a,c,d,e,g);h(qF)[this.kB]=this}qF.prototype=Object.create(pE.prototype);qF.prototype.constructor=qF;qF.prototype.lB=qF;qF.mB={};b.btGeneric6DofSpringConstraint=qF;
|
||||
qF.prototype.enableSpring=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Es(d,a,c)};qF.prototype.setStiffness=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Fs(d,a,c)};qF.prototype.setDamping=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Gs(d,a,c)};
|
||||
qF.prototype.setEquilibriumPoint=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);void 0===a?Hs(d):void 0===c?Is(d,a):Js(d,a,c)};qF.prototype.setLinearLowerLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ks(c,a)};qF.prototype.setLinearUpperLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ls(c,a)};qF.prototype.setAngularLowerLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ms(c,a)};
|
||||
qF.prototype.setAngularUpperLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ns(c,a)};qF.prototype.getFrameOffsetA=function(){return k(Os(this.kB),r)};qF.prototype.enableFeedback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ps(c,a)};qF.prototype.getBreakingImpulseThreshold=function(){return Qs(this.kB)};qF.prototype.setBreakingImpulseThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Rs(c,a)};
|
||||
qF.prototype.getParam=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return Ss(d,a,c)};qF.prototype.setParam=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Ts(e,a,c,d)};qF.prototype.__destroy__=function(){Us(this.kB)};function rF(){this.kB=Vs();h(rF)[this.kB]=this}rF.prototype=Object.create(f.prototype);rF.prototype.constructor=rF;rF.prototype.lB=rF;rF.mB={};
|
||||
b.btSequentialImpulseConstraintSolver=rF;rF.prototype.__destroy__=function(){Ws(this.kB)};function sF(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=void 0===d?Xs(a,c):void 0===e?_emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_3(a,c,d):Ys(a,c,d,e);h(sF)[this.kB]=this}sF.prototype=Object.create(aE.prototype);sF.prototype.constructor=sF;sF.prototype.lB=sF;sF.mB={};
|
||||
b.btConeTwistConstraint=sF;sF.prototype.setLimit=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Zs(d,a,c)};sF.prototype.setAngularOnly=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$s(c,a)};sF.prototype.setDamping=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);at(c,a)};sF.prototype.enableMotor=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);bt(c,a)};
|
||||
sF.prototype.setMaxMotorImpulse=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ct(c,a)};sF.prototype.setMaxMotorImpulseNormalized=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);dt(c,a)};sF.prototype.setMotorTarget=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);et(c,a)};sF.prototype.setMotorTargetInConstraintSpace=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ft(c,a)};
|
||||
sF.prototype.enableFeedback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);gt(c,a)};sF.prototype.getBreakingImpulseThreshold=function(){return ht(this.kB)};sF.prototype.setBreakingImpulseThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);it(c,a)};sF.prototype.getParam=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return jt(d,a,c)};
|
||||
sF.prototype.setParam=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);kt(e,a,c,d)};sF.prototype.__destroy__=function(){lt(this.kB)};
|
||||
function tF(a,c,d,e,g,n,z){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);n&&"object"===typeof n&&(n=n.kB);z&&"object"===typeof z&&(z=z.kB);this.kB=void 0===d?mt(a,c):void 0===e?nt(a,c,d):void 0===g?ot(a,c,d,e):void 0===n?pt(a,c,d,e,g):void 0===z?qt(a,c,d,e,g,n):rt(a,c,d,e,g,n,z);h(tF)[this.kB]=this}tF.prototype=Object.create(aE.prototype);tF.prototype.constructor=tF;
|
||||
tF.prototype.lB=tF;tF.mB={};b.btHingeConstraint=tF;tF.prototype.getHingeAngle=function(){return st(this.kB)};tF.prototype.setLimit=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);void 0===g?tt(n,a,c,d,e):ut(n,a,c,d,e,g)};
|
||||
tF.prototype.enableAngularMotor=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);vt(e,a,c,d)};tF.prototype.setAngularOnly=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);wt(c,a)};tF.prototype.enableMotor=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xt(c,a)};tF.prototype.setMaxMotorImpulse=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yt(c,a)};
|
||||
tF.prototype.setMotorTarget=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);zt(d,a,c)};tF.prototype.enableFeedback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);At(c,a)};tF.prototype.getBreakingImpulseThreshold=function(){return Bt(this.kB)};tF.prototype.setBreakingImpulseThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ct(c,a)};
|
||||
tF.prototype.getParam=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return Dt(d,a,c)};tF.prototype.setParam=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Et(e,a,c,d)};tF.prototype.__destroy__=function(){Ft(this.kB)};
|
||||
function uF(a,c,d,e,g){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);this.kB=void 0===e?Gt(a,c,d):void 0===g?_emscripten_bind_btSliderConstraint_btSliderConstraint_4(a,c,d,e):Ht(a,c,d,e,g);h(uF)[this.kB]=this}uF.prototype=Object.create(aE.prototype);uF.prototype.constructor=uF;uF.prototype.lB=uF;uF.mB={};b.btSliderConstraint=uF;uF.prototype.getLinearPos=function(){return It(this.kB)};
|
||||
uF.prototype.getAngularPos=function(){return Jt(this.kB)};uF.prototype.setLowerLinLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Kt(c,a)};uF.prototype.setUpperLinLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Lt(c,a)};uF.prototype.setLowerAngLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Mt(c,a)};uF.prototype.setUpperAngLimit=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Nt(c,a)};
|
||||
uF.prototype.setPoweredLinMotor=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ot(c,a)};uF.prototype.setMaxLinMotorForce=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Pt(c,a)};uF.prototype.setTargetLinMotorVelocity=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Qt(c,a)};uF.prototype.enableFeedback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Rt(c,a)};uF.prototype.getBreakingImpulseThreshold=function(){return St(this.kB)};
|
||||
uF.prototype.setBreakingImpulseThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Tt(c,a)};uF.prototype.getParam=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return Ut(d,a,c)};uF.prototype.setParam=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);Vt(e,a,c,d)};uF.prototype.__destroy__=function(){Wt(this.kB)};
|
||||
function vF(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=Xt(a,c,d,e);h(vF)[this.kB]=this}vF.prototype=Object.create(aE.prototype);vF.prototype.constructor=vF;vF.prototype.lB=vF;vF.mB={};b.btFixedConstraint=vF;vF.prototype.enableFeedback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Yt(c,a)};vF.prototype.getBreakingImpulseThreshold=function(){return Zt(this.kB)};
|
||||
vF.prototype.setBreakingImpulseThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$t(c,a)};vF.prototype.getParam=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return au(d,a,c)};vF.prototype.setParam=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);bu(e,a,c,d)};vF.prototype.__destroy__=function(){cu(this.kB)};
|
||||
function wF(){throw"cannot construct a btConstraintSolver, no constructor in IDL";}wF.prototype=Object.create(f.prototype);wF.prototype.constructor=wF;wF.prototype.lB=wF;wF.mB={};b.btConstraintSolver=wF;wF.prototype.__destroy__=function(){du(this.kB)};function p(){throw"cannot construct a btDispatcherInfo, no constructor in IDL";}p.prototype=Object.create(f.prototype);p.prototype.constructor=p;p.prototype.lB=p;p.mB={};b.btDispatcherInfo=p;p.prototype.get_m_timeStep=p.prototype.uE=function(){return eu(this.kB)};
|
||||
p.prototype.set_m_timeStep=p.prototype.mH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fu(c,a)};Object.defineProperty(p.prototype,"m_timeStep",{get:p.prototype.uE,set:p.prototype.mH});p.prototype.get_m_stepCount=p.prototype.lE=function(){return gu(this.kB)};p.prototype.set_m_stepCount=p.prototype.dH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hu(c,a)};Object.defineProperty(p.prototype,"m_stepCount",{get:p.prototype.lE,set:p.prototype.dH});
|
||||
p.prototype.get_m_dispatchFunc=p.prototype.cD=function(){return iu(this.kB)};p.prototype.set_m_dispatchFunc=p.prototype.UF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ju(c,a)};Object.defineProperty(p.prototype,"m_dispatchFunc",{get:p.prototype.cD,set:p.prototype.UF});p.prototype.get_m_timeOfImpact=p.prototype.tE=function(){return ku(this.kB)};p.prototype.set_m_timeOfImpact=p.prototype.lH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);lu(c,a)};
|
||||
Object.defineProperty(p.prototype,"m_timeOfImpact",{get:p.prototype.tE,set:p.prototype.lH});p.prototype.get_m_useContinuous=p.prototype.wE=function(){return!!mu(this.kB)};p.prototype.set_m_useContinuous=p.prototype.oH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);nu(c,a)};Object.defineProperty(p.prototype,"m_useContinuous",{get:p.prototype.wE,set:p.prototype.oH});p.prototype.get_m_enableSatConvex=p.prototype.hD=function(){return!!ou(this.kB)};
|
||||
p.prototype.set_m_enableSatConvex=p.prototype.ZF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pu(c,a)};Object.defineProperty(p.prototype,"m_enableSatConvex",{get:p.prototype.hD,set:p.prototype.ZF});p.prototype.get_m_enableSPU=p.prototype.gD=function(){return!!qu(this.kB)};p.prototype.set_m_enableSPU=p.prototype.YF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ru(c,a)};Object.defineProperty(p.prototype,"m_enableSPU",{get:p.prototype.gD,set:p.prototype.YF});
|
||||
p.prototype.get_m_useEpa=p.prototype.yE=function(){return!!su(this.kB)};p.prototype.set_m_useEpa=p.prototype.qH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);tu(c,a)};Object.defineProperty(p.prototype,"m_useEpa",{get:p.prototype.yE,set:p.prototype.qH});p.prototype.get_m_allowedCcdPenetration=p.prototype.FC=function(){return uu(this.kB)};p.prototype.set_m_allowedCcdPenetration=p.prototype.wF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vu(c,a)};
|
||||
Object.defineProperty(p.prototype,"m_allowedCcdPenetration",{get:p.prototype.FC,set:p.prototype.wF});p.prototype.get_m_useConvexConservativeDistanceUtil=p.prototype.xE=function(){return!!wu(this.kB)};p.prototype.set_m_useConvexConservativeDistanceUtil=p.prototype.pH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xu(c,a)};Object.defineProperty(p.prototype,"m_useConvexConservativeDistanceUtil",{get:p.prototype.xE,set:p.prototype.pH});
|
||||
p.prototype.get_m_convexConservativeDistanceThreshold=p.prototype.YC=function(){return yu(this.kB)};p.prototype.set_m_convexConservativeDistanceThreshold=p.prototype.PF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zu(c,a)};Object.defineProperty(p.prototype,"m_convexConservativeDistanceThreshold",{get:p.prototype.YC,set:p.prototype.PF});p.prototype.__destroy__=function(){Au(this.kB)};function t(){throw"cannot construct a btContactSolverInfo, no constructor in IDL";}t.prototype=Object.create(f.prototype);
|
||||
t.prototype.constructor=t;t.prototype.lB=t;t.mB={};b.btContactSolverInfo=t;t.prototype.get_m_splitImpulse=t.prototype.iE=function(){return!!Bu(this.kB)};t.prototype.set_m_splitImpulse=t.prototype.aH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Cu(c,a)};Object.defineProperty(t.prototype,"m_splitImpulse",{get:t.prototype.iE,set:t.prototype.aH});t.prototype.get_m_splitImpulsePenetrationThreshold=t.prototype.jE=function(){return Du(this.kB)};
|
||||
t.prototype.set_m_splitImpulsePenetrationThreshold=t.prototype.bH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Eu(c,a)};Object.defineProperty(t.prototype,"m_splitImpulsePenetrationThreshold",{get:t.prototype.jE,set:t.prototype.bH});t.prototype.get_m_numIterations=t.prototype.TD=function(){return Fu(this.kB)};t.prototype.set_m_numIterations=t.prototype.KG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Gu(c,a)};
|
||||
Object.defineProperty(t.prototype,"m_numIterations",{get:t.prototype.TD,set:t.prototype.KG});t.prototype.__destroy__=function(){Hu(this.kB)};function M(){this.kB=Iu();h(M)[this.kB]=this}M.prototype=Object.create(f.prototype);M.prototype.constructor=M;M.prototype.lB=M;M.mB={};b.btVehicleTuning=M;M.prototype.get_m_suspensionStiffness=M.prototype.BB=function(){return Ju(this.kB)};M.prototype.set_m_suspensionStiffness=M.prototype.IB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ku(c,a)};
|
||||
Object.defineProperty(M.prototype,"m_suspensionStiffness",{get:M.prototype.BB,set:M.prototype.IB});M.prototype.get_m_suspensionCompression=M.prototype.mE=function(){return Lu(this.kB)};M.prototype.set_m_suspensionCompression=M.prototype.eH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Mu(c,a)};Object.defineProperty(M.prototype,"m_suspensionCompression",{get:M.prototype.mE,set:M.prototype.eH});M.prototype.get_m_suspensionDamping=M.prototype.nE=function(){return Nu(this.kB)};
|
||||
M.prototype.set_m_suspensionDamping=M.prototype.fH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ou(c,a)};Object.defineProperty(M.prototype,"m_suspensionDamping",{get:M.prototype.nE,set:M.prototype.fH});M.prototype.get_m_maxSuspensionTravelCm=M.prototype.AB=function(){return Pu(this.kB)};M.prototype.set_m_maxSuspensionTravelCm=M.prototype.HB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Qu(c,a)};
|
||||
Object.defineProperty(M.prototype,"m_maxSuspensionTravelCm",{get:M.prototype.AB,set:M.prototype.HB});M.prototype.get_m_frictionSlip=M.prototype.wB=function(){return Ru(this.kB)};M.prototype.set_m_frictionSlip=M.prototype.DB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Su(c,a)};Object.defineProperty(M.prototype,"m_frictionSlip",{get:M.prototype.wB,set:M.prototype.DB});M.prototype.get_m_maxSuspensionForce=M.prototype.zB=function(){return Tu(this.kB)};
|
||||
M.prototype.set_m_maxSuspensionForce=M.prototype.GB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Uu(c,a)};Object.defineProperty(M.prototype,"m_maxSuspensionForce",{get:M.prototype.zB,set:M.prototype.GB});function xF(){throw"cannot construct a btVehicleRaycasterResult, no constructor in IDL";}xF.prototype=Object.create(f.prototype);xF.prototype.constructor=xF;xF.prototype.lB=xF;xF.mB={};b.btVehicleRaycasterResult=xF;
|
||||
xF.prototype.get_m_hitPointInWorld=xF.prototype.tD=function(){return k(Vu(this.kB),m)};xF.prototype.set_m_hitPointInWorld=xF.prototype.kG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Wu(c,a)};Object.defineProperty(xF.prototype,"m_hitPointInWorld",{get:xF.prototype.tD,set:xF.prototype.kG});xF.prototype.get_m_hitNormalInWorld=xF.prototype.rD=function(){return k(Xu(this.kB),m)};
|
||||
xF.prototype.set_m_hitNormalInWorld=xF.prototype.iG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Yu(c,a)};Object.defineProperty(xF.prototype,"m_hitNormalInWorld",{get:xF.prototype.rD,set:xF.prototype.iG});xF.prototype.get_m_distFraction=xF.prototype.fD=function(){return Zu(this.kB)};xF.prototype.set_m_distFraction=xF.prototype.XF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$u(c,a)};Object.defineProperty(xF.prototype,"m_distFraction",{get:xF.prototype.fD,set:xF.prototype.XF});
|
||||
xF.prototype.__destroy__=function(){av(this.kB)};function yF(a){a&&"object"===typeof a&&(a=a.kB);this.kB=bv(a);h(yF)[this.kB]=this}yF.prototype=Object.create(qE.prototype);yF.prototype.constructor=yF;yF.prototype.lB=yF;yF.mB={};b.btDefaultVehicleRaycaster=yF;yF.prototype.castRay=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);cv(e,a,c,d)};yF.prototype.__destroy__=function(){dv(this.kB)};
|
||||
function N(){throw"cannot construct a RaycastInfo, no constructor in IDL";}N.prototype=Object.create(f.prototype);N.prototype.constructor=N;N.prototype.lB=N;N.mB={};b.RaycastInfo=N;N.prototype.get_m_contactNormalWS=N.prototype.WC=function(){return k(ev(this.kB),m)};N.prototype.set_m_contactNormalWS=N.prototype.NF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fv(c,a)};Object.defineProperty(N.prototype,"m_contactNormalWS",{get:N.prototype.WC,set:N.prototype.NF});
|
||||
N.prototype.get_m_contactPointWS=N.prototype.XC=function(){return k(gv(this.kB),m)};N.prototype.set_m_contactPointWS=N.prototype.OF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hv(c,a)};Object.defineProperty(N.prototype,"m_contactPointWS",{get:N.prototype.XC,set:N.prototype.OF});N.prototype.get_m_suspensionLength=N.prototype.oE=function(){return iv(this.kB)};N.prototype.set_m_suspensionLength=N.prototype.gH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jv(c,a)};
|
||||
Object.defineProperty(N.prototype,"m_suspensionLength",{get:N.prototype.oE,set:N.prototype.gH});N.prototype.get_m_hardPointWS=N.prototype.oD=function(){return k(kv(this.kB),m)};N.prototype.set_m_hardPointWS=N.prototype.fG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);lv(c,a)};Object.defineProperty(N.prototype,"m_hardPointWS",{get:N.prototype.oD,set:N.prototype.fG});N.prototype.get_m_wheelDirectionWS=N.prototype.DE=function(){return k(mv(this.kB),m)};
|
||||
N.prototype.set_m_wheelDirectionWS=N.prototype.vH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);nv(c,a)};Object.defineProperty(N.prototype,"m_wheelDirectionWS",{get:N.prototype.DE,set:N.prototype.vH});N.prototype.get_m_wheelAxleWS=N.prototype.CE=function(){return k(ov(this.kB),m)};N.prototype.set_m_wheelAxleWS=N.prototype.uH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pv(c,a)};Object.defineProperty(N.prototype,"m_wheelAxleWS",{get:N.prototype.CE,set:N.prototype.uH});
|
||||
N.prototype.get_m_isInContact=N.prototype.zD=function(){return!!qv(this.kB)};N.prototype.set_m_isInContact=N.prototype.qG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);rv(c,a)};Object.defineProperty(N.prototype,"m_isInContact",{get:N.prototype.zD,set:N.prototype.qG});N.prototype.get_m_groundObject=N.prototype.nD=function(){return sv(this.kB)};N.prototype.set_m_groundObject=N.prototype.eG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);tv(c,a)};
|
||||
Object.defineProperty(N.prototype,"m_groundObject",{get:N.prototype.nD,set:N.prototype.eG});N.prototype.__destroy__=function(){uv(this.kB)};function O(){throw"cannot construct a btWheelInfoConstructionInfo, no constructor in IDL";}O.prototype=Object.create(f.prototype);O.prototype.constructor=O;O.prototype.lB=O;O.mB={};b.btWheelInfoConstructionInfo=O;O.prototype.get_m_chassisConnectionCS=O.prototype.RC=function(){return k(vv(this.kB),m)};
|
||||
O.prototype.set_m_chassisConnectionCS=O.prototype.IF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);wv(c,a)};Object.defineProperty(O.prototype,"m_chassisConnectionCS",{get:O.prototype.RC,set:O.prototype.IF});O.prototype.get_m_wheelDirectionCS=O.prototype.QB=function(){return k(xv(this.kB),m)};O.prototype.set_m_wheelDirectionCS=O.prototype.$B=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yv(c,a)};Object.defineProperty(O.prototype,"m_wheelDirectionCS",{get:O.prototype.QB,set:O.prototype.$B});
|
||||
O.prototype.get_m_wheelAxleCS=O.prototype.PB=function(){return k(zv(this.kB),m)};O.prototype.set_m_wheelAxleCS=O.prototype.ZB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Av(c,a)};Object.defineProperty(O.prototype,"m_wheelAxleCS",{get:O.prototype.PB,set:O.prototype.ZB});O.prototype.get_m_suspensionRestLength=O.prototype.qE=function(){return Bv(this.kB)};O.prototype.set_m_suspensionRestLength=O.prototype.iH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Cv(c,a)};
|
||||
Object.defineProperty(O.prototype,"m_suspensionRestLength",{get:O.prototype.qE,set:O.prototype.iH});O.prototype.get_m_maxSuspensionTravelCm=O.prototype.AB=function(){return Dv(this.kB)};O.prototype.set_m_maxSuspensionTravelCm=O.prototype.HB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ev(c,a)};Object.defineProperty(O.prototype,"m_maxSuspensionTravelCm",{get:O.prototype.AB,set:O.prototype.HB});O.prototype.get_m_wheelRadius=O.prototype.EE=function(){return Fv(this.kB)};
|
||||
O.prototype.set_m_wheelRadius=O.prototype.wH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Gv(c,a)};Object.defineProperty(O.prototype,"m_wheelRadius",{get:O.prototype.EE,set:O.prototype.wH});O.prototype.get_m_suspensionStiffness=O.prototype.BB=function(){return Hv(this.kB)};O.prototype.set_m_suspensionStiffness=O.prototype.IB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Iv(c,a)};Object.defineProperty(O.prototype,"m_suspensionStiffness",{get:O.prototype.BB,set:O.prototype.IB});
|
||||
O.prototype.get_m_wheelsDampingCompression=O.prototype.RB=function(){return Jv(this.kB)};O.prototype.set_m_wheelsDampingCompression=O.prototype.aC=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Kv(c,a)};Object.defineProperty(O.prototype,"m_wheelsDampingCompression",{get:O.prototype.RB,set:O.prototype.aC});O.prototype.get_m_wheelsDampingRelaxation=O.prototype.SB=function(){return Lv(this.kB)};
|
||||
O.prototype.set_m_wheelsDampingRelaxation=O.prototype.bC=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Mv(c,a)};Object.defineProperty(O.prototype,"m_wheelsDampingRelaxation",{get:O.prototype.SB,set:O.prototype.bC});O.prototype.get_m_frictionSlip=O.prototype.wB=function(){return Nv(this.kB)};O.prototype.set_m_frictionSlip=O.prototype.DB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ov(c,a)};Object.defineProperty(O.prototype,"m_frictionSlip",{get:O.prototype.wB,set:O.prototype.DB});
|
||||
O.prototype.get_m_maxSuspensionForce=O.prototype.zB=function(){return Pv(this.kB)};O.prototype.set_m_maxSuspensionForce=O.prototype.GB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Qv(c,a)};Object.defineProperty(O.prototype,"m_maxSuspensionForce",{get:O.prototype.zB,set:O.prototype.GB});O.prototype.get_m_bIsFrontWheel=O.prototype.JB=function(){return!!Rv(this.kB)};O.prototype.set_m_bIsFrontWheel=O.prototype.TB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Sv(c,a)};
|
||||
Object.defineProperty(O.prototype,"m_bIsFrontWheel",{get:O.prototype.JB,set:O.prototype.TB});O.prototype.__destroy__=function(){Tv(this.kB)};function P(a){a&&"object"===typeof a&&(a=a.kB);this.kB=Uv(a);h(P)[this.kB]=this}P.prototype=Object.create(f.prototype);P.prototype.constructor=P;P.prototype.lB=P;P.mB={};b.btWheelInfo=P;P.prototype.getSuspensionRestLength=function(){return Vv(this.kB)};
|
||||
P.prototype.updateWheel=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Wv(d,a,c)};P.prototype.get_m_suspensionStiffness=P.prototype.BB=function(){return Xv(this.kB)};P.prototype.set_m_suspensionStiffness=P.prototype.IB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Yv(c,a)};Object.defineProperty(P.prototype,"m_suspensionStiffness",{get:P.prototype.BB,set:P.prototype.IB});P.prototype.get_m_frictionSlip=P.prototype.wB=function(){return Zv(this.kB)};
|
||||
P.prototype.set_m_frictionSlip=P.prototype.DB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$v(c,a)};Object.defineProperty(P.prototype,"m_frictionSlip",{get:P.prototype.wB,set:P.prototype.DB});P.prototype.get_m_engineForce=P.prototype.iD=function(){return aw(this.kB)};P.prototype.set_m_engineForce=P.prototype.$F=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);bw(c,a)};Object.defineProperty(P.prototype,"m_engineForce",{get:P.prototype.iD,set:P.prototype.$F});
|
||||
P.prototype.get_m_rollInfluence=P.prototype.cE=function(){return cw(this.kB)};P.prototype.set_m_rollInfluence=P.prototype.VG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);dw(c,a)};Object.defineProperty(P.prototype,"m_rollInfluence",{get:P.prototype.cE,set:P.prototype.VG});P.prototype.get_m_suspensionRestLength1=P.prototype.rE=function(){return ew(this.kB)};P.prototype.set_m_suspensionRestLength1=P.prototype.jH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fw(c,a)};
|
||||
Object.defineProperty(P.prototype,"m_suspensionRestLength1",{get:P.prototype.rE,set:P.prototype.jH});P.prototype.get_m_wheelsRadius=P.prototype.FE=function(){return gw(this.kB)};P.prototype.set_m_wheelsRadius=P.prototype.xH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hw(c,a)};Object.defineProperty(P.prototype,"m_wheelsRadius",{get:P.prototype.FE,set:P.prototype.xH});P.prototype.get_m_wheelsDampingCompression=P.prototype.RB=function(){return iw(this.kB)};
|
||||
P.prototype.set_m_wheelsDampingCompression=P.prototype.aC=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jw(c,a)};Object.defineProperty(P.prototype,"m_wheelsDampingCompression",{get:P.prototype.RB,set:P.prototype.aC});P.prototype.get_m_wheelsDampingRelaxation=P.prototype.SB=function(){return kw(this.kB)};P.prototype.set_m_wheelsDampingRelaxation=P.prototype.bC=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);lw(c,a)};
|
||||
Object.defineProperty(P.prototype,"m_wheelsDampingRelaxation",{get:P.prototype.SB,set:P.prototype.bC});P.prototype.get_m_steering=P.prototype.kE=function(){return mw(this.kB)};P.prototype.set_m_steering=P.prototype.cH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);nw(c,a)};Object.defineProperty(P.prototype,"m_steering",{get:P.prototype.kE,set:P.prototype.cH});P.prototype.get_m_maxSuspensionForce=P.prototype.zB=function(){return ow(this.kB)};
|
||||
P.prototype.set_m_maxSuspensionForce=P.prototype.GB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pw(c,a)};Object.defineProperty(P.prototype,"m_maxSuspensionForce",{get:P.prototype.zB,set:P.prototype.GB});P.prototype.get_m_maxSuspensionTravelCm=P.prototype.AB=function(){return qw(this.kB)};P.prototype.set_m_maxSuspensionTravelCm=P.prototype.HB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);rw(c,a)};
|
||||
Object.defineProperty(P.prototype,"m_maxSuspensionTravelCm",{get:P.prototype.AB,set:P.prototype.HB});P.prototype.get_m_wheelsSuspensionForce=P.prototype.GE=function(){return sw(this.kB)};P.prototype.set_m_wheelsSuspensionForce=P.prototype.yH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);tw(c,a)};Object.defineProperty(P.prototype,"m_wheelsSuspensionForce",{get:P.prototype.GE,set:P.prototype.yH});P.prototype.get_m_bIsFrontWheel=P.prototype.JB=function(){return!!uw(this.kB)};
|
||||
P.prototype.set_m_bIsFrontWheel=P.prototype.TB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vw(c,a)};Object.defineProperty(P.prototype,"m_bIsFrontWheel",{get:P.prototype.JB,set:P.prototype.TB});P.prototype.get_m_raycastInfo=P.prototype.aE=function(){return k(ww(this.kB),N)};P.prototype.set_m_raycastInfo=P.prototype.TG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xw(c,a)};Object.defineProperty(P.prototype,"m_raycastInfo",{get:P.prototype.aE,set:P.prototype.TG});
|
||||
P.prototype.get_m_chassisConnectionPointCS=P.prototype.SC=function(){return k(yw(this.kB),m)};P.prototype.set_m_chassisConnectionPointCS=P.prototype.JF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zw(c,a)};Object.defineProperty(P.prototype,"m_chassisConnectionPointCS",{get:P.prototype.SC,set:P.prototype.JF});P.prototype.get_m_worldTransform=P.prototype.HE=function(){return k(Aw(this.kB),r)};
|
||||
P.prototype.set_m_worldTransform=P.prototype.zH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Bw(c,a)};Object.defineProperty(P.prototype,"m_worldTransform",{get:P.prototype.HE,set:P.prototype.zH});P.prototype.get_m_wheelDirectionCS=P.prototype.QB=function(){return k(Cw(this.kB),m)};P.prototype.set_m_wheelDirectionCS=P.prototype.$B=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dw(c,a)};Object.defineProperty(P.prototype,"m_wheelDirectionCS",{get:P.prototype.QB,set:P.prototype.$B});
|
||||
P.prototype.get_m_wheelAxleCS=P.prototype.PB=function(){return k(Ew(this.kB),m)};P.prototype.set_m_wheelAxleCS=P.prototype.ZB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Fw(c,a)};Object.defineProperty(P.prototype,"m_wheelAxleCS",{get:P.prototype.PB,set:P.prototype.ZB});P.prototype.get_m_rotation=P.prototype.eE=function(){return Gw(this.kB)};P.prototype.set_m_rotation=P.prototype.XG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Hw(c,a)};
|
||||
Object.defineProperty(P.prototype,"m_rotation",{get:P.prototype.eE,set:P.prototype.XG});P.prototype.get_m_deltaRotation=P.prototype.bD=function(){return Iw(this.kB)};P.prototype.set_m_deltaRotation=P.prototype.TF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jw(c,a)};Object.defineProperty(P.prototype,"m_deltaRotation",{get:P.prototype.bD,set:P.prototype.TF});P.prototype.get_m_brake=P.prototype.LC=function(){return Kw(this.kB)};
|
||||
P.prototype.set_m_brake=P.prototype.CF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Lw(c,a)};Object.defineProperty(P.prototype,"m_brake",{get:P.prototype.LC,set:P.prototype.CF});P.prototype.get_m_clippedInvContactDotSuspension=P.prototype.TC=function(){return Mw(this.kB)};P.prototype.set_m_clippedInvContactDotSuspension=P.prototype.KF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Nw(c,a)};
|
||||
Object.defineProperty(P.prototype,"m_clippedInvContactDotSuspension",{get:P.prototype.TC,set:P.prototype.KF});P.prototype.get_m_suspensionRelativeVelocity=P.prototype.pE=function(){return Ow(this.kB)};P.prototype.set_m_suspensionRelativeVelocity=P.prototype.hH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Pw(c,a)};Object.defineProperty(P.prototype,"m_suspensionRelativeVelocity",{get:P.prototype.pE,set:P.prototype.hH});P.prototype.get_m_skidInfo=P.prototype.hE=function(){return Qw(this.kB)};
|
||||
P.prototype.set_m_skidInfo=P.prototype.$G=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Rw(c,a)};Object.defineProperty(P.prototype,"m_skidInfo",{get:P.prototype.hE,set:P.prototype.$G});P.prototype.__destroy__=function(){Sw(this.kB)};function zF(a,c,d,e){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);this.kB=void 0===e?Tw(a,c,d):Uw(a,c,d,e);h(zF)[this.kB]=this}zF.prototype=Object.create(rE.prototype);
|
||||
zF.prototype.constructor=zF;zF.prototype.lB=zF;zF.mB={};b.btKinematicCharacterController=zF;zF.prototype.setUpAxis=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vw(c,a)};zF.prototype.setWalkDirection=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ww(c,a)};zF.prototype.setVelocityForTimeInterval=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Xw(d,a,c)};
|
||||
zF.prototype.warp=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Yw(c,a)};zF.prototype.preStep=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Zw(c,a)};zF.prototype.playerStep=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);$w(d,a,c)};zF.prototype.setFallSpeed=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ax(c,a)};zF.prototype.setJumpSpeed=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);bx(c,a)};
|
||||
zF.prototype.setMaxJumpHeight=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);cx(c,a)};zF.prototype.canJump=function(){return!!dx(this.kB)};zF.prototype.jump=function(){ex(this.kB)};zF.prototype.setGravity=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fx(c,a)};zF.prototype.getGravity=function(){return gx(this.kB)};zF.prototype.setMaxSlope=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hx(c,a)};zF.prototype.getMaxSlope=function(){return ix(this.kB)};
|
||||
zF.prototype.getGhostObject=function(){return k(jx(this.kB),Q)};zF.prototype.setUseGhostSweepTest=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);kx(c,a)};zF.prototype.onGround=function(){return!!lx(this.kB)};zF.prototype.setUpInterpolate=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);mx(c,a)};zF.prototype.updateAction=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);nx(d,a,c)};zF.prototype.__destroy__=function(){ox(this.kB)};
|
||||
function R(a,c,d){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);this.kB=px(a,c,d);h(R)[this.kB]=this}R.prototype=Object.create(rE.prototype);R.prototype.constructor=R;R.prototype.lB=R;R.mB={};b.btRaycastVehicle=R;R.prototype.applyEngineForce=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);qx(d,a,c)};
|
||||
R.prototype.setSteeringValue=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);rx(d,a,c)};R.prototype.getWheelTransformWS=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(sx(c,a),r)};R.prototype.updateWheelTransform=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);tx(d,a,c)};
|
||||
R.prototype.addWheel=function(a,c,d,e,g,n,z){var T=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);n&&"object"===typeof n&&(n=n.kB);z&&"object"===typeof z&&(z=z.kB);return k(ux(T,a,c,d,e,g,n,z),P)};R.prototype.getNumWheels=function(){return vx(this.kB)};R.prototype.getRigidBody=function(){return k(wx(this.kB),K)};
|
||||
R.prototype.getWheelInfo=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(xx(c,a),P)};R.prototype.setBrake=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);yx(d,a,c)};R.prototype.setCoordinateSystem=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);zx(e,a,c,d)};R.prototype.getCurrentSpeedKmHour=function(){return Ax(this.kB)};
|
||||
R.prototype.getChassisWorldTransform=function(){return k(Bx(this.kB),r)};R.prototype.rayCast=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return Cx(c,a)};R.prototype.updateVehicle=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dx(c,a)};R.prototype.resetSuspension=function(){Ex(this.kB)};R.prototype.getSteeringValue=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return Fx(c,a)};
|
||||
R.prototype.updateWheelTransformsWS=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);void 0===c?Gx(d,a):Hx(d,a,c)};R.prototype.setPitchControl=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ix(c,a)};R.prototype.updateSuspension=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jx(c,a)};R.prototype.updateFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Kx(c,a)};R.prototype.getRightAxis=function(){return Lx(this.kB)};
|
||||
R.prototype.getUpAxis=function(){return Mx(this.kB)};R.prototype.getForwardAxis=function(){return Nx(this.kB)};R.prototype.getForwardVector=function(){return k(Ox(this.kB),m)};R.prototype.getUserConstraintType=function(){return Px(this.kB)};R.prototype.setUserConstraintType=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Qx(c,a)};R.prototype.setUserConstraintId=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Rx(c,a)};R.prototype.getUserConstraintId=function(){return Sx(this.kB)};
|
||||
R.prototype.updateAction=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Tx(d,a,c)};R.prototype.__destroy__=function(){Ux(this.kB)};function Q(){this.kB=Vx();h(Q)[this.kB]=this}Q.prototype=Object.create(y.prototype);Q.prototype.constructor=Q;Q.prototype.lB=Q;Q.mB={};b.btPairCachingGhostObject=Q;Q.prototype.setAnisotropicFriction=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Wx(d,a,c)};
|
||||
Q.prototype.getCollisionShape=function(){return k(Xx(this.kB),l)};Q.prototype.setContactProcessingThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Yx(c,a)};Q.prototype.setActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Zx(c,a)};Q.prototype.forceActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$x(c,a)};Q.prototype.activate=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);void 0===a?ay(c):by(c,a)};
|
||||
Q.prototype.isActive=function(){return!!cy(this.kB)};Q.prototype.isKinematicObject=function(){return!!dy(this.kB)};Q.prototype.isStaticObject=function(){return!!ey(this.kB)};Q.prototype.isStaticOrKinematicObject=function(){return!!fy(this.kB)};Q.prototype.getRestitution=function(){return gy(this.kB)};Q.prototype.getFriction=function(){return hy(this.kB)};Q.prototype.getRollingFriction=function(){return iy(this.kB)};
|
||||
Q.prototype.setRestitution=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jy(c,a)};Q.prototype.setFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ky(c,a)};Q.prototype.setRollingFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ly(c,a)};Q.prototype.getWorldTransform=function(){return k(my(this.kB),r)};Q.prototype.getCollisionFlags=function(){return ny(this.kB)};
|
||||
Q.prototype.setCollisionFlags=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);oy(c,a)};Q.prototype.setWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);py(c,a)};Q.prototype.setCollisionShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);qy(c,a)};Q.prototype.setCcdMotionThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ry(c,a)};Q.prototype.setCcdSweptSphereRadius=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);sy(c,a)};
|
||||
Q.prototype.getUserIndex=function(){return ty(this.kB)};Q.prototype.setUserIndex=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);uy(c,a)};Q.prototype.getUserPointer=function(){return k(vy(this.kB),XD)};Q.prototype.setUserPointer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);wy(c,a)};Q.prototype.getBroadphaseHandle=function(){return k(xy(this.kB),YD)};Q.prototype.getNumOverlappingObjects=function(){return yy(this.kB)};
|
||||
Q.prototype.getOverlappingObject=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(zy(c,a),q)};Q.prototype.__destroy__=function(){Ay(this.kB)};function AF(){this.kB=By();h(AF)[this.kB]=this}AF.prototype=Object.create(f.prototype);AF.prototype.constructor=AF;AF.prototype.lB=AF;AF.mB={};b.btGhostPairCallback=AF;AF.prototype.__destroy__=function(){Cy(this.kB)};function S(){this.kB=Dy();h(S)[this.kB]=this}S.prototype=Object.create(f.prototype);S.prototype.constructor=S;
|
||||
S.prototype.lB=S;S.mB={};b.btSoftBodyWorldInfo=S;S.prototype.get_air_density=S.prototype.cC=function(){return Ey(this.kB)};S.prototype.set_air_density=S.prototype.UE=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Fy(c,a)};Object.defineProperty(S.prototype,"air_density",{get:S.prototype.cC,set:S.prototype.UE});S.prototype.get_water_density=S.prototype.RE=function(){return Gy(this.kB)};
|
||||
S.prototype.set_water_density=S.prototype.JH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Hy(c,a)};Object.defineProperty(S.prototype,"water_density",{get:S.prototype.RE,set:S.prototype.JH});S.prototype.get_water_offset=S.prototype.TE=function(){return Iy(this.kB)};S.prototype.set_water_offset=S.prototype.LH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jy(c,a)};Object.defineProperty(S.prototype,"water_offset",{get:S.prototype.TE,set:S.prototype.LH});
|
||||
S.prototype.get_m_maxDisplacement=S.prototype.ND=function(){return Ky(this.kB)};S.prototype.set_m_maxDisplacement=S.prototype.EG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ly(c,a)};Object.defineProperty(S.prototype,"m_maxDisplacement",{get:S.prototype.ND,set:S.prototype.EG});S.prototype.get_water_normal=S.prototype.SE=function(){return k(My(this.kB),m)};S.prototype.set_water_normal=S.prototype.KH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ny(c,a)};
|
||||
Object.defineProperty(S.prototype,"water_normal",{get:S.prototype.SE,set:S.prototype.KH});S.prototype.get_m_broadphase=S.prototype.MC=function(){return k(Oy(this.kB),VD)};S.prototype.set_m_broadphase=S.prototype.DF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Py(c,a)};Object.defineProperty(S.prototype,"m_broadphase",{get:S.prototype.MC,set:S.prototype.DF});S.prototype.get_m_dispatcher=S.prototype.dD=function(){return k(Qy(this.kB),TD)};
|
||||
S.prototype.set_m_dispatcher=S.prototype.VF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ry(c,a)};Object.defineProperty(S.prototype,"m_dispatcher",{get:S.prototype.dD,set:S.prototype.VF});S.prototype.get_m_gravity=S.prototype.mD=function(){return k(Sy(this.kB),m)};S.prototype.set_m_gravity=S.prototype.dG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Ty(c,a)};Object.defineProperty(S.prototype,"m_gravity",{get:S.prototype.mD,set:S.prototype.dG});S.prototype.__destroy__=function(){Uy(this.kB)};
|
||||
function U(){throw"cannot construct a Face, no constructor in IDL";}U.prototype=Object.create(f.prototype);U.prototype.constructor=U;U.prototype.lB=U;U.mB={};b.Face=U;U.prototype.get_m_n=U.prototype.MB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Vy(c,a),Node)};U.prototype.set_m_n=U.prototype.WB=function(a,c){var d=this.kB;ND();a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);Wy(d,a,c)};Object.defineProperty(U.prototype,"m_n",{get:U.prototype.MB,set:U.prototype.WB});
|
||||
U.prototype.get_m_normal=U.prototype.RD=function(){return k(Xy(this.kB),m)};U.prototype.set_m_normal=U.prototype.IG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Yy(c,a)};Object.defineProperty(U.prototype,"m_normal",{get:U.prototype.RD,set:U.prototype.IG});U.prototype.get_m_ra=U.prototype.$D=function(){return Zy(this.kB)};U.prototype.set_m_ra=U.prototype.SG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$y(c,a)};
|
||||
Object.defineProperty(U.prototype,"m_ra",{get:U.prototype.$D,set:U.prototype.SG});U.prototype.__destroy__=function(){az(this.kB)};function BF(){throw"cannot construct a tFaceArray, no constructor in IDL";}BF.prototype=Object.create(f.prototype);BF.prototype.constructor=BF;BF.prototype.lB=BF;BF.mB={};b.tFaceArray=BF;BF.prototype.size=BF.prototype.size=function(){return bz(this.kB)};BF.prototype.at=BF.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(cz(c,a),U)};
|
||||
BF.prototype.__destroy__=function(){dz(this.kB)};function Node(){throw"cannot construct a Node, no constructor in IDL";}Node.prototype=Object.create(f.prototype);Node.prototype.constructor=Node;Node.prototype.lB=Node;Node.mB={};b.Node=Node;Node.prototype.get_m_x=Node.prototype.IE=function(){return k(ez(this.kB),m)};Node.prototype.set_m_x=Node.prototype.AH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fz(c,a)};Object.defineProperty(Node.prototype,"m_x",{get:Node.prototype.IE,set:Node.prototype.AH});
|
||||
Node.prototype.get_m_q=Node.prototype.ZD=function(){return k(gz(this.kB),m)};Node.prototype.set_m_q=Node.prototype.QG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hz(c,a)};Object.defineProperty(Node.prototype,"m_q",{get:Node.prototype.ZD,set:Node.prototype.QG});Node.prototype.get_m_v=Node.prototype.AE=function(){return k(iz(this.kB),m)};Node.prototype.set_m_v=Node.prototype.sH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jz(c,a)};
|
||||
Object.defineProperty(Node.prototype,"m_v",{get:Node.prototype.AE,set:Node.prototype.sH});Node.prototype.get_m_f=Node.prototype.jD=function(){return k(kz(this.kB),m)};Node.prototype.set_m_f=Node.prototype.aG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);lz(c,a)};Object.defineProperty(Node.prototype,"m_f",{get:Node.prototype.jD,set:Node.prototype.aG});Node.prototype.get_m_n=Node.prototype.MB=function(){return k(mz(this.kB),m)};
|
||||
Node.prototype.set_m_n=Node.prototype.WB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);nz(c,a)};Object.defineProperty(Node.prototype,"m_n",{get:Node.prototype.MB,set:Node.prototype.WB});Node.prototype.get_m_im=Node.prototype.vD=function(){return oz(this.kB)};Node.prototype.set_m_im=Node.prototype.mG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pz(c,a)};Object.defineProperty(Node.prototype,"m_im",{get:Node.prototype.vD,set:Node.prototype.mG});
|
||||
Node.prototype.get_m_area=Node.prototype.JC=function(){return qz(this.kB)};Node.prototype.set_m_area=Node.prototype.AF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);rz(c,a)};Object.defineProperty(Node.prototype,"m_area",{get:Node.prototype.JC,set:Node.prototype.AF});Node.prototype.__destroy__=function(){sz(this.kB)};function CF(){throw"cannot construct a tNodeArray, no constructor in IDL";}CF.prototype=Object.create(f.prototype);CF.prototype.constructor=CF;CF.prototype.lB=CF;CF.mB={};
|
||||
b.tNodeArray=CF;CF.prototype.size=CF.prototype.size=function(){return tz(this.kB)};CF.prototype.at=CF.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(uz(c,a),Node)};CF.prototype.__destroy__=function(){vz(this.kB)};function V(){throw"cannot construct a Material, no constructor in IDL";}V.prototype=Object.create(f.prototype);V.prototype.constructor=V;V.prototype.lB=V;V.mB={};b.Material=V;V.prototype.get_m_kLST=V.prototype.BD=function(){return wz(this.kB)};
|
||||
V.prototype.set_m_kLST=V.prototype.sG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xz(c,a)};Object.defineProperty(V.prototype,"m_kLST",{get:V.prototype.BD,set:V.prototype.sG});V.prototype.get_m_kAST=V.prototype.AD=function(){return yz(this.kB)};V.prototype.set_m_kAST=V.prototype.rG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zz(c,a)};Object.defineProperty(V.prototype,"m_kAST",{get:V.prototype.AD,set:V.prototype.rG});V.prototype.get_m_kVST=V.prototype.CD=function(){return Az(this.kB)};
|
||||
V.prototype.set_m_kVST=V.prototype.tG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Bz(c,a)};Object.defineProperty(V.prototype,"m_kVST",{get:V.prototype.CD,set:V.prototype.tG});V.prototype.get_m_flags=V.prototype.tB=function(){return Cz(this.kB)};V.prototype.set_m_flags=V.prototype.uB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Dz(c,a)};Object.defineProperty(V.prototype,"m_flags",{get:V.prototype.tB,set:V.prototype.uB});V.prototype.__destroy__=function(){Ez(this.kB)};
|
||||
function DF(){throw"cannot construct a tMaterialArray, no constructor in IDL";}DF.prototype=Object.create(f.prototype);DF.prototype.constructor=DF;DF.prototype.lB=DF;DF.mB={};b.tMaterialArray=DF;DF.prototype.size=DF.prototype.size=function(){return Fz(this.kB)};DF.prototype.at=DF.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Gz(c,a),V)};DF.prototype.__destroy__=function(){Hz(this.kB)};function W(){throw"cannot construct a Anchor, no constructor in IDL";}
|
||||
W.prototype=Object.create(f.prototype);W.prototype.constructor=W;W.prototype.lB=W;W.mB={};b.Anchor=W;W.prototype.get_m_node=W.prototype.PD=function(){return k(Iz(this.kB),Node)};W.prototype.set_m_node=W.prototype.GG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Jz(c,a)};Object.defineProperty(W.prototype,"m_node",{get:W.prototype.PD,set:W.prototype.GG});W.prototype.get_m_local=W.prototype.FD=function(){return k(Kz(this.kB),m)};
|
||||
W.prototype.set_m_local=W.prototype.wG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Lz(c,a)};Object.defineProperty(W.prototype,"m_local",{get:W.prototype.FD,set:W.prototype.wG});W.prototype.get_m_body=W.prototype.KC=function(){return k(Mz(this.kB),K)};W.prototype.set_m_body=W.prototype.BF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Nz(c,a)};Object.defineProperty(W.prototype,"m_body",{get:W.prototype.KC,set:W.prototype.BF});W.prototype.get_m_influence=W.prototype.yD=function(){return Oz(this.kB)};
|
||||
W.prototype.set_m_influence=W.prototype.pG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Pz(c,a)};Object.defineProperty(W.prototype,"m_influence",{get:W.prototype.yD,set:W.prototype.pG});W.prototype.get_m_c0=W.prototype.NC=function(){return k(Qz(this.kB),uE)};W.prototype.set_m_c0=W.prototype.EF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Rz(c,a)};Object.defineProperty(W.prototype,"m_c0",{get:W.prototype.NC,set:W.prototype.EF});
|
||||
W.prototype.get_m_c1=W.prototype.OC=function(){return k(Sz(this.kB),m)};W.prototype.set_m_c1=W.prototype.FF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Tz(c,a)};Object.defineProperty(W.prototype,"m_c1",{get:W.prototype.OC,set:W.prototype.FF});W.prototype.get_m_c2=W.prototype.PC=function(){return Uz(this.kB)};W.prototype.set_m_c2=W.prototype.GF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);Vz(c,a)};Object.defineProperty(W.prototype,"m_c2",{get:W.prototype.PC,set:W.prototype.GF});
|
||||
W.prototype.__destroy__=function(){Wz(this.kB)};function EF(){throw"cannot construct a tAnchorArray, no constructor in IDL";}EF.prototype=Object.create(f.prototype);EF.prototype.constructor=EF;EF.prototype.lB=EF;EF.mB={};b.tAnchorArray=EF;EF.prototype.size=EF.prototype.size=function(){return Xz(this.kB)};EF.prototype.at=EF.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(Yz(c,a),W)};EF.prototype.clear=EF.prototype.clear=function(){Zz(this.kB)};
|
||||
EF.prototype.push_back=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$z(c,a)};EF.prototype.pop_back=function(){aA(this.kB)};EF.prototype.__destroy__=function(){bA(this.kB)};function X(){throw"cannot construct a Config, no constructor in IDL";}X.prototype=Object.create(f.prototype);X.prototype.constructor=X;X.prototype.lB=X;X.mB={};b.Config=X;X.prototype.get_kVCF=X.prototype.zC=function(){return cA(this.kB)};
|
||||
X.prototype.set_kVCF=X.prototype.qF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);dA(c,a)};Object.defineProperty(X.prototype,"kVCF",{get:X.prototype.zC,set:X.prototype.qF});X.prototype.get_kDP=X.prototype.mC=function(){return eA(this.kB)};X.prototype.set_kDP=X.prototype.dF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);fA(c,a)};Object.defineProperty(X.prototype,"kDP",{get:X.prototype.mC,set:X.prototype.dF});X.prototype.get_kDG=X.prototype.lC=function(){return gA(this.kB)};
|
||||
X.prototype.set_kDG=X.prototype.cF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);hA(c,a)};Object.defineProperty(X.prototype,"kDG",{get:X.prototype.lC,set:X.prototype.cF});X.prototype.get_kLF=X.prototype.oC=function(){return iA(this.kB)};X.prototype.set_kLF=X.prototype.fF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);jA(c,a)};Object.defineProperty(X.prototype,"kLF",{get:X.prototype.oC,set:X.prototype.fF});X.prototype.get_kPR=X.prototype.qC=function(){return kA(this.kB)};
|
||||
X.prototype.set_kPR=X.prototype.hF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);lA(c,a)};Object.defineProperty(X.prototype,"kPR",{get:X.prototype.qC,set:X.prototype.hF});X.prototype.get_kVC=X.prototype.yC=function(){return mA(this.kB)};X.prototype.set_kVC=X.prototype.pF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);nA(c,a)};Object.defineProperty(X.prototype,"kVC",{get:X.prototype.yC,set:X.prototype.pF});X.prototype.get_kDF=X.prototype.kC=function(){return oA(this.kB)};
|
||||
X.prototype.set_kDF=X.prototype.bF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pA(c,a)};Object.defineProperty(X.prototype,"kDF",{get:X.prototype.kC,set:X.prototype.bF});X.prototype.get_kMT=X.prototype.pC=function(){return qA(this.kB)};X.prototype.set_kMT=X.prototype.gF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);rA(c,a)};Object.defineProperty(X.prototype,"kMT",{get:X.prototype.pC,set:X.prototype.gF});X.prototype.get_kCHR=X.prototype.jC=function(){return sA(this.kB)};
|
||||
X.prototype.set_kCHR=X.prototype.aF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);tA(c,a)};Object.defineProperty(X.prototype,"kCHR",{get:X.prototype.jC,set:X.prototype.aF});X.prototype.get_kKHR=X.prototype.nC=function(){return uA(this.kB)};X.prototype.set_kKHR=X.prototype.eF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);vA(c,a)};Object.defineProperty(X.prototype,"kKHR",{get:X.prototype.nC,set:X.prototype.eF});X.prototype.get_kSHR=X.prototype.rC=function(){return wA(this.kB)};
|
||||
X.prototype.set_kSHR=X.prototype.iF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xA(c,a)};Object.defineProperty(X.prototype,"kSHR",{get:X.prototype.rC,set:X.prototype.iF});X.prototype.get_kAHR=X.prototype.iC=function(){return yA(this.kB)};X.prototype.set_kAHR=X.prototype.$E=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);zA(c,a)};Object.defineProperty(X.prototype,"kAHR",{get:X.prototype.iC,set:X.prototype.$E});X.prototype.get_kSRHR_CL=X.prototype.uC=function(){return AA(this.kB)};
|
||||
X.prototype.set_kSRHR_CL=X.prototype.lF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);BA(c,a)};Object.defineProperty(X.prototype,"kSRHR_CL",{get:X.prototype.uC,set:X.prototype.lF});X.prototype.get_kSKHR_CL=X.prototype.sC=function(){return CA(this.kB)};X.prototype.set_kSKHR_CL=X.prototype.jF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);DA(c,a)};Object.defineProperty(X.prototype,"kSKHR_CL",{get:X.prototype.sC,set:X.prototype.jF});X.prototype.get_kSSHR_CL=X.prototype.wC=function(){return EA(this.kB)};
|
||||
X.prototype.set_kSSHR_CL=X.prototype.nF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);FA(c,a)};Object.defineProperty(X.prototype,"kSSHR_CL",{get:X.prototype.wC,set:X.prototype.nF});X.prototype.get_kSR_SPLT_CL=X.prototype.vC=function(){return GA(this.kB)};X.prototype.set_kSR_SPLT_CL=X.prototype.mF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);HA(c,a)};Object.defineProperty(X.prototype,"kSR_SPLT_CL",{get:X.prototype.vC,set:X.prototype.mF});
|
||||
X.prototype.get_kSK_SPLT_CL=X.prototype.tC=function(){return IA(this.kB)};X.prototype.set_kSK_SPLT_CL=X.prototype.kF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);JA(c,a)};Object.defineProperty(X.prototype,"kSK_SPLT_CL",{get:X.prototype.tC,set:X.prototype.kF});X.prototype.get_kSS_SPLT_CL=X.prototype.xC=function(){return KA(this.kB)};X.prototype.set_kSS_SPLT_CL=X.prototype.oF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);LA(c,a)};
|
||||
Object.defineProperty(X.prototype,"kSS_SPLT_CL",{get:X.prototype.xC,set:X.prototype.oF});X.prototype.get_maxvolume=X.prototype.JE=function(){return MA(this.kB)};X.prototype.set_maxvolume=X.prototype.BH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);NA(c,a)};Object.defineProperty(X.prototype,"maxvolume",{get:X.prototype.JE,set:X.prototype.BH});X.prototype.get_timescale=X.prototype.OE=function(){return OA(this.kB)};
|
||||
X.prototype.set_timescale=X.prototype.GH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);PA(c,a)};Object.defineProperty(X.prototype,"timescale",{get:X.prototype.OE,set:X.prototype.GH});X.prototype.get_viterations=X.prototype.QE=function(){return QA(this.kB)};X.prototype.set_viterations=X.prototype.IH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);RA(c,a)};Object.defineProperty(X.prototype,"viterations",{get:X.prototype.QE,set:X.prototype.IH});
|
||||
X.prototype.get_piterations=X.prototype.ME=function(){return SA(this.kB)};X.prototype.set_piterations=X.prototype.EH=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);TA(c,a)};Object.defineProperty(X.prototype,"piterations",{get:X.prototype.ME,set:X.prototype.EH});X.prototype.get_diterations=X.prototype.fC=function(){return UA(this.kB)};X.prototype.set_diterations=X.prototype.XE=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);VA(c,a)};
|
||||
Object.defineProperty(X.prototype,"diterations",{get:X.prototype.fC,set:X.prototype.XE});X.prototype.get_citerations=X.prototype.dC=function(){return WA(this.kB)};X.prototype.set_citerations=X.prototype.VE=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);XA(c,a)};Object.defineProperty(X.prototype,"citerations",{get:X.prototype.dC,set:X.prototype.VE});X.prototype.get_collisions=X.prototype.eC=function(){return YA(this.kB)};
|
||||
X.prototype.set_collisions=X.prototype.WE=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);ZA(c,a)};Object.defineProperty(X.prototype,"collisions",{get:X.prototype.eC,set:X.prototype.WE});X.prototype.__destroy__=function(){$A(this.kB)};function Y(a,c,d,e){ND();a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);"object"==typeof e&&(e=RD(e));this.kB=aB(a,c,d,e);h(Y)[this.kB]=this}Y.prototype=Object.create(q.prototype);
|
||||
Y.prototype.constructor=Y;Y.prototype.lB=Y;Y.mB={};b.btSoftBody=Y;Y.prototype.checkLink=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return!!bB(d,a,c)};Y.prototype.checkFace=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);return!!cB(e,a,c,d)};Y.prototype.appendMaterial=function(){return k(dB(this.kB),V)};
|
||||
Y.prototype.appendNode=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);eB(d,a,c)};Y.prototype.appendLink=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);fB(g,a,c,d,e)};
|
||||
Y.prototype.appendFace=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);gB(g,a,c,d,e)};Y.prototype.appendTetra=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);hB(n,a,c,d,e,g)};
|
||||
Y.prototype.appendAnchor=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);iB(g,a,c,d,e)};Y.prototype.addForce=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);void 0===c?jB(d,a):kB(d,a,c)};Y.prototype.addAeroForceToNode=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);lB(d,a,c)};
|
||||
Y.prototype.getTotalMass=function(){return mB(this.kB)};Y.prototype.setTotalMass=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);nB(d,a,c)};Y.prototype.setMass=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);oB(d,a,c)};Y.prototype.transform=Y.prototype.transform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);pB(c,a)};
|
||||
Y.prototype.translate=Y.prototype.translate=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);qB(c,a)};Y.prototype.rotate=Y.prototype.rotate=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);rB(c,a)};Y.prototype.scale=Y.prototype.scale=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);sB(c,a)};Y.prototype.generateClusters=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return void 0===c?tB(d,a):uB(d,a,c)};
|
||||
Y.prototype.generateBendingConstraints=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);return vB(d,a,c)};Y.prototype.upcast=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(wB(c,a),Y)};Y.prototype.getRestLengthScale=function(){return xB(this.kB)};Y.prototype.setRestLengthScale=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);yB(c,a)};
|
||||
Y.prototype.setAnisotropicFriction=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);zB(d,a,c)};Y.prototype.getCollisionShape=function(){return k(AB(this.kB),l)};Y.prototype.setContactProcessingThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);BB(c,a)};Y.prototype.setActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);CB(c,a)};
|
||||
Y.prototype.forceActivationState=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);DB(c,a)};Y.prototype.activate=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);void 0===a?EB(c):FB(c,a)};Y.prototype.isActive=function(){return!!GB(this.kB)};Y.prototype.isKinematicObject=function(){return!!HB(this.kB)};Y.prototype.isStaticObject=function(){return!!IB(this.kB)};Y.prototype.isStaticOrKinematicObject=function(){return!!JB(this.kB)};Y.prototype.getRestitution=function(){return KB(this.kB)};
|
||||
Y.prototype.getFriction=function(){return LB(this.kB)};Y.prototype.getRollingFriction=function(){return MB(this.kB)};Y.prototype.setRestitution=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);NB(c,a)};Y.prototype.setFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);OB(c,a)};Y.prototype.setRollingFriction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);PB(c,a)};Y.prototype.getWorldTransform=function(){return k(QB(this.kB),r)};Y.prototype.getCollisionFlags=function(){return RB(this.kB)};
|
||||
Y.prototype.setCollisionFlags=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);SB(c,a)};Y.prototype.setWorldTransform=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);TB(c,a)};Y.prototype.setCollisionShape=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);UB(c,a)};Y.prototype.setCcdMotionThreshold=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);VB(c,a)};Y.prototype.setCcdSweptSphereRadius=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);WB(c,a)};
|
||||
Y.prototype.getUserIndex=function(){return XB(this.kB)};Y.prototype.setUserIndex=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);YB(c,a)};Y.prototype.getUserPointer=function(){return k(ZB(this.kB),XD)};Y.prototype.setUserPointer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);$B(c,a)};Y.prototype.getBroadphaseHandle=function(){return k(aC(this.kB),YD)};Y.prototype.get_m_cfg=Y.prototype.QC=function(){return k(bC(this.kB),X)};
|
||||
Y.prototype.set_m_cfg=Y.prototype.HF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);cC(c,a)};Object.defineProperty(Y.prototype,"m_cfg",{get:Y.prototype.QC,set:Y.prototype.HF});Y.prototype.get_m_nodes=Y.prototype.QD=function(){return k(dC(this.kB),CF)};Y.prototype.set_m_nodes=Y.prototype.HG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);eC(c,a)};Object.defineProperty(Y.prototype,"m_nodes",{get:Y.prototype.QD,set:Y.prototype.HG});
|
||||
Y.prototype.get_m_faces=Y.prototype.KB=function(){return k(fC(this.kB),BF)};Y.prototype.set_m_faces=Y.prototype.UB=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);gC(c,a)};Object.defineProperty(Y.prototype,"m_faces",{get:Y.prototype.KB,set:Y.prototype.UB});Y.prototype.get_m_materials=Y.prototype.MD=function(){return k(hC(this.kB),DF)};Y.prototype.set_m_materials=Y.prototype.DG=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);iC(c,a)};
|
||||
Object.defineProperty(Y.prototype,"m_materials",{get:Y.prototype.MD,set:Y.prototype.DG});Y.prototype.get_m_anchors=Y.prototype.GC=function(){return k(jC(this.kB),EF)};Y.prototype.set_m_anchors=Y.prototype.xF=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);kC(c,a)};Object.defineProperty(Y.prototype,"m_anchors",{get:Y.prototype.GC,set:Y.prototype.xF});Y.prototype.__destroy__=function(){lC(this.kB)};
|
||||
function FF(a){a&&"object"===typeof a&&(a=a.kB);this.kB=void 0===a?mC():nC(a);h(FF)[this.kB]=this}FF.prototype=Object.create(nE.prototype);FF.prototype.constructor=FF;FF.prototype.lB=FF;FF.mB={};b.btSoftBodyRigidBodyCollisionConfiguration=FF;FF.prototype.__destroy__=function(){oC(this.kB)};function GF(){this.kB=pC();h(GF)[this.kB]=this}GF.prototype=Object.create(sE.prototype);GF.prototype.constructor=GF;GF.prototype.lB=GF;GF.mB={};b.btDefaultSoftBodySolver=GF;GF.prototype.__destroy__=function(){qC(this.kB)};
|
||||
function HF(){throw"cannot construct a btSoftBodyArray, no constructor in IDL";}HF.prototype=Object.create(f.prototype);HF.prototype.constructor=HF;HF.prototype.lB=HF;HF.mB={};b.btSoftBodyArray=HF;HF.prototype.size=HF.prototype.size=function(){return rC(this.kB)};HF.prototype.at=HF.prototype.at=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);return k(sC(c,a),Y)};HF.prototype.__destroy__=function(){tC(this.kB)};
|
||||
function Z(a,c,d,e,g){a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);this.kB=uC(a,c,d,e,g);h(Z)[this.kB]=this}Z.prototype=Object.create(x.prototype);Z.prototype.constructor=Z;Z.prototype.lB=Z;Z.mB={};b.btSoftRigidDynamicsWorld=Z;
|
||||
Z.prototype.addSoftBody=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);vC(e,a,c,d)};Z.prototype.removeSoftBody=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);wC(c,a)};Z.prototype.removeCollisionObject=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);xC(c,a)};Z.prototype.getWorldInfo=function(){return k(yC(this.kB),S)};Z.prototype.getSoftBodyArray=function(){return k(zC(this.kB),HF)};
|
||||
Z.prototype.getDispatcher=function(){return k(AC(this.kB),TD)};Z.prototype.rayTest=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);BC(e,a,c,d)};Z.prototype.getPairCache=function(){return k(CC(this.kB),UD)};Z.prototype.getDispatchInfo=function(){return k(DC(this.kB),p)};
|
||||
Z.prototype.addCollisionObject=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?EC(e,a):void 0===d?FC(e,a,c):GC(e,a,c,d)};Z.prototype.getBroadphase=function(){return k(HC(this.kB),VD)};
|
||||
Z.prototype.convexSweepTest=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);IC(n,a,c,d,e,g)};Z.prototype.contactPairTest=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);JC(e,a,c,d)};
|
||||
Z.prototype.contactTest=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);KC(d,a,c)};Z.prototype.updateSingleAabb=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);LC(c,a)};Z.prototype.setDebugDrawer=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);MC(c,a)};Z.prototype.getDebugDrawer=function(){return k(NC(this.kB),WD)};Z.prototype.debugDrawWorld=function(){OC(this.kB)};
|
||||
Z.prototype.debugDrawObject=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);PC(e,a,c,d)};Z.prototype.setGravity=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);QC(c,a)};Z.prototype.getGravity=function(){return k(RC(this.kB),m)};
|
||||
Z.prototype.addRigidBody=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?SC(e,a):void 0===d?_emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_2(e,a,c):TC(e,a,c,d)};Z.prototype.removeRigidBody=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);UC(c,a)};
|
||||
Z.prototype.addConstraint=function(a,c){var d=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);void 0===c?VC(d,a):WC(d,a,c)};Z.prototype.removeConstraint=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);XC(c,a)};Z.prototype.stepSimulation=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);return void 0===c?YC(e,a):void 0===d?ZC(e,a,c):$C(e,a,c,d)};
|
||||
Z.prototype.setContactAddedCallback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);aD(c,a)};Z.prototype.setContactProcessedCallback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);bD(c,a)};Z.prototype.setContactDestroyedCallback=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);cD(c,a)};Z.prototype.addAction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);dD(c,a)};Z.prototype.removeAction=function(a){var c=this.kB;a&&"object"===typeof a&&(a=a.kB);eD(c,a)};
|
||||
Z.prototype.getSolverInfo=function(){return k(fD(this.kB),t)};Z.prototype.setInternalTickCallback=function(a,c,d){var e=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);void 0===c?gD(e,a):void 0===d?hD(e,a,c):iD(e,a,c,d)};Z.prototype.__destroy__=function(){jD(this.kB)};function IF(){this.kB=kD();h(IF)[this.kB]=this}IF.prototype=Object.create(f.prototype);IF.prototype.constructor=IF;IF.prototype.lB=IF;IF.mB={};b.btSoftBodyHelpers=IF;
|
||||
IF.prototype.CreateRope=function(a,c,d,e,g){var n=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);return k(lD(n,a,c,d,e,g),Y)};
|
||||
IF.prototype.CreatePatch=function(a,c,d,e,g,n,z,T,Da){var dc=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);n&&"object"===typeof n&&(n=n.kB);z&&"object"===typeof z&&(z=z.kB);T&&"object"===typeof T&&(T=T.kB);Da&&"object"===typeof Da&&(Da=Da.kB);return k(mD(dc,a,c,d,e,g,n,z,T,Da),Y)};
|
||||
IF.prototype.CreatePatchUV=function(a,c,d,e,g,n,z,T,Da,dc){var JF=this.kB;ND();a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);n&&"object"===typeof n&&(n=n.kB);z&&"object"===typeof z&&(z=z.kB);T&&"object"===typeof T&&(T=T.kB);Da&&"object"===typeof Da&&(Da=Da.kB);"object"==typeof dc&&(dc=RD(dc));return k(nD(JF,a,c,d,e,g,n,z,T,Da,dc),Y)};
|
||||
IF.prototype.CreateEllipsoid=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);return k(oD(g,a,c,d,e),Y)};
|
||||
IF.prototype.CreateFromTriMesh=function(a,c,d,e,g){var n=this.kB;ND();a&&"object"===typeof a&&(a=a.kB);"object"==typeof c&&(c=RD(c));if("object"==typeof d&&"object"===typeof d){var z=OD(d,va);PD(d,va,z);d=z}e&&"object"===typeof e&&(e=e.kB);g&&"object"===typeof g&&(g=g.kB);return k(pD(n,a,c,d,e,g),Y)};
|
||||
IF.prototype.CreateFromConvexHull=function(a,c,d,e){var g=this.kB;a&&"object"===typeof a&&(a=a.kB);c&&"object"===typeof c&&(c=c.kB);d&&"object"===typeof d&&(d=d.kB);e&&"object"===typeof e&&(e=e.kB);return k(qD(g,a,c,d,e),Y)};IF.prototype.__destroy__=function(){rD(this.kB)};
|
||||
(function(){function a(){b.PHY_FLOAT=sD();b.PHY_DOUBLE=tD();b.PHY_INTEGER=uD();b.PHY_SHORT=vD();b.PHY_FIXEDPOINT88=wD();b.PHY_UCHAR=xD();b.CONST_GIMPACT_COMPOUND_SHAPE=yD();b.CONST_GIMPACT_TRIMESH_SHAPE_PART=zD();b.CONST_GIMPACT_TRIMESH_SHAPE=AD();b.BT_CONSTRAINT_ERP=BD();b.BT_CONSTRAINT_STOP_ERP=CD();b.BT_CONSTRAINT_CFM=DD();b.BT_CONSTRAINT_STOP_CFM=ED()}Ca?a():Aa.unshift(a)})();b.CONTACT_ADDED_CALLBACK_SIGNATURE="iiiiiiii";b.CONTACT_DESTROYED_CALLBACK_SIGNATURE="ii";
|
||||
b.CONTACT_PROCESSED_CALLBACK_SIGNATURE="iiii";b.INTERNAL_TICK_CALLBACK_SIGNATURE="vif";this.Ammo=b;
|
||||
|
||||
|
||||
return Ammo.ready
|
||||
}
|
||||
|
||||
);
|
||||
})();
|
||||
if (typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = Ammo;
|
||||
else if (typeof define === 'function' && define['amd'])
|
||||
define([], function() { return Ammo; });
|
||||
else if (typeof exports === 'object')
|
||||
exports["Ammo"] = Ammo;
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
# Draco glTF decoder 1.5.7
|
||||
|
||||
Vendored from Google's immutable versioned Draco decoder distribution for the
|
||||
PlayCanvas `DracoDecoderModule`. Runtime loading remains local to Mission Core.
|
||||
|
||||
- `draco_wasm_wrapper_gltf.js`: `8bb2952d2ba7d67e1414f8df819410cb0434a666be53f671fff75f68843d76f6`
|
||||
- `draco_decoder_gltf.wasm`: `712db3449ae2041d6e8a224c395bda6cedb49e51322fae38b7db9beb8b381889`
|
||||
- Upstream base: `https://www.gstatic.com/draco/versioned/decoders/1.5.7/`
|
||||
BIN
Binary file not shown.
+116
@@ -0,0 +1,116 @@
|
||||
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(h){var n=0;return function(){return n<h.length?{done:!1,value:h[n++]}:{done:!0}}};$jscomp.arrayIterator=function(h){return{next:$jscomp.arrayIteratorImpl(h)}};$jscomp.makeIterator=function(h){var n="undefined"!=typeof Symbol&&Symbol.iterator&&h[Symbol.iterator];return n?n.call(h):$jscomp.arrayIterator(h)};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;
|
||||
$jscomp.ISOLATE_POLYFILLS=!1;$jscomp.FORCE_POLYFILL_PROMISE=!1;$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION=!1;$jscomp.getGlobal=function(h){h=["object"==typeof globalThis&&globalThis,h,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var n=0;n<h.length;++n){var k=h[n];if(k&&k.Math==Math)return k}throw Error("Cannot find global object");};$jscomp.global=$jscomp.getGlobal(this);
|
||||
$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(h,n,k){if(h==Array.prototype||h==Object.prototype)return h;h[n]=k.value;return h};$jscomp.IS_SYMBOL_NATIVE="function"===typeof Symbol&&"symbol"===typeof Symbol("x");$jscomp.TRUST_ES6_POLYFILLS=!$jscomp.ISOLATE_POLYFILLS||$jscomp.IS_SYMBOL_NATIVE;$jscomp.polyfills={};$jscomp.propertyToPolyfillSymbol={};$jscomp.POLYFILL_PREFIX="$jscp$";
|
||||
var $jscomp$lookupPolyfilledValue=function(h,n){var k=$jscomp.propertyToPolyfillSymbol[n];if(null==k)return h[n];k=h[k];return void 0!==k?k:h[n]};$jscomp.polyfill=function(h,n,k,p){n&&($jscomp.ISOLATE_POLYFILLS?$jscomp.polyfillIsolated(h,n,k,p):$jscomp.polyfillUnisolated(h,n,k,p))};
|
||||
$jscomp.polyfillUnisolated=function(h,n,k,p){k=$jscomp.global;h=h.split(".");for(p=0;p<h.length-1;p++){var l=h[p];if(!(l in k))return;k=k[l]}h=h[h.length-1];p=k[h];n=n(p);n!=p&&null!=n&&$jscomp.defineProperty(k,h,{configurable:!0,writable:!0,value:n})};
|
||||
$jscomp.polyfillIsolated=function(h,n,k,p){var l=h.split(".");h=1===l.length;p=l[0];p=!h&&p in $jscomp.polyfills?$jscomp.polyfills:$jscomp.global;for(var y=0;y<l.length-1;y++){var f=l[y];if(!(f in p))return;p=p[f]}l=l[l.length-1];k=$jscomp.IS_SYMBOL_NATIVE&&"es6"===k?p[l]:null;n=n(k);null!=n&&(h?$jscomp.defineProperty($jscomp.polyfills,l,{configurable:!0,writable:!0,value:n}):n!==k&&(void 0===$jscomp.propertyToPolyfillSymbol[l]&&(k=1E9*Math.random()>>>0,$jscomp.propertyToPolyfillSymbol[l]=$jscomp.IS_SYMBOL_NATIVE?
|
||||
$jscomp.global.Symbol(l):$jscomp.POLYFILL_PREFIX+k+"$"+l),$jscomp.defineProperty(p,$jscomp.propertyToPolyfillSymbol[l],{configurable:!0,writable:!0,value:n})))};
|
||||
$jscomp.polyfill("Promise",function(h){function n(){this.batch_=null}function k(f){return f instanceof l?f:new l(function(q,u){q(f)})}if(h&&(!($jscomp.FORCE_POLYFILL_PROMISE||$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION&&"undefined"===typeof $jscomp.global.PromiseRejectionEvent)||!$jscomp.global.Promise||-1===$jscomp.global.Promise.toString().indexOf("[native code]")))return h;n.prototype.asyncExecute=function(f){if(null==this.batch_){this.batch_=[];var q=this;this.asyncExecuteFunction(function(){q.executeBatch_()})}this.batch_.push(f)};
|
||||
var p=$jscomp.global.setTimeout;n.prototype.asyncExecuteFunction=function(f){p(f,0)};n.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var f=this.batch_;this.batch_=[];for(var q=0;q<f.length;++q){var u=f[q];f[q]=null;try{u()}catch(A){this.asyncThrow_(A)}}}this.batch_=null};n.prototype.asyncThrow_=function(f){this.asyncExecuteFunction(function(){throw f;})};var l=function(f){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];this.isRejectionHandled_=!1;var q=this.createResolveAndReject_();
|
||||
try{f(q.resolve,q.reject)}catch(u){q.reject(u)}};l.prototype.createResolveAndReject_=function(){function f(A){return function(F){u||(u=!0,A.call(q,F))}}var q=this,u=!1;return{resolve:f(this.resolveTo_),reject:f(this.reject_)}};l.prototype.resolveTo_=function(f){if(f===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(f instanceof l)this.settleSameAsPromise_(f);else{a:switch(typeof f){case "object":var q=null!=f;break a;case "function":q=!0;break a;default:q=!1}q?this.resolveToNonPromiseObj_(f):
|
||||
this.fulfill_(f)}};l.prototype.resolveToNonPromiseObj_=function(f){var q=void 0;try{q=f.then}catch(u){this.reject_(u);return}"function"==typeof q?this.settleSameAsThenable_(q,f):this.fulfill_(f)};l.prototype.reject_=function(f){this.settle_(2,f)};l.prototype.fulfill_=function(f){this.settle_(1,f)};l.prototype.settle_=function(f,q){if(0!=this.state_)throw Error("Cannot settle("+f+", "+q+"): Promise already settled in state"+this.state_);this.state_=f;this.result_=q;2===this.state_&&this.scheduleUnhandledRejectionCheck_();
|
||||
this.executeOnSettledCallbacks_()};l.prototype.scheduleUnhandledRejectionCheck_=function(){var f=this;p(function(){if(f.notifyUnhandledRejection_()){var q=$jscomp.global.console;"undefined"!==typeof q&&q.error(f.result_)}},1)};l.prototype.notifyUnhandledRejection_=function(){if(this.isRejectionHandled_)return!1;var f=$jscomp.global.CustomEvent,q=$jscomp.global.Event,u=$jscomp.global.dispatchEvent;if("undefined"===typeof u)return!0;"function"===typeof f?f=new f("unhandledrejection",{cancelable:!0}):
|
||||
"function"===typeof q?f=new q("unhandledrejection",{cancelable:!0}):(f=$jscomp.global.document.createEvent("CustomEvent"),f.initCustomEvent("unhandledrejection",!1,!0,f));f.promise=this;f.reason=this.result_;return u(f)};l.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var f=0;f<this.onSettledCallbacks_.length;++f)y.asyncExecute(this.onSettledCallbacks_[f]);this.onSettledCallbacks_=null}};var y=new n;l.prototype.settleSameAsPromise_=function(f){var q=this.createResolveAndReject_();
|
||||
f.callWhenSettled_(q.resolve,q.reject)};l.prototype.settleSameAsThenable_=function(f,q){var u=this.createResolveAndReject_();try{f.call(q,u.resolve,u.reject)}catch(A){u.reject(A)}};l.prototype.then=function(f,q){function u(w,B){return"function"==typeof w?function(R){try{A(w(R))}catch(Z){F(Z)}}:B}var A,F,v=new l(function(w,B){A=w;F=B});this.callWhenSettled_(u(f,A),u(q,F));return v};l.prototype.catch=function(f){return this.then(void 0,f)};l.prototype.callWhenSettled_=function(f,q){function u(){switch(A.state_){case 1:f(A.result_);
|
||||
break;case 2:q(A.result_);break;default:throw Error("Unexpected state: "+A.state_);}}var A=this;null==this.onSettledCallbacks_?y.asyncExecute(u):this.onSettledCallbacks_.push(u);this.isRejectionHandled_=!0};l.resolve=k;l.reject=function(f){return new l(function(q,u){u(f)})};l.race=function(f){return new l(function(q,u){for(var A=$jscomp.makeIterator(f),F=A.next();!F.done;F=A.next())k(F.value).callWhenSettled_(q,u)})};l.all=function(f){var q=$jscomp.makeIterator(f),u=q.next();return u.done?k([]):new l(function(A,
|
||||
F){function v(R){return function(Z){w[R]=Z;B--;0==B&&A(w)}}var w=[],B=0;do w.push(void 0),B++,k(u.value).callWhenSettled_(v(w.length-1),F),u=q.next();while(!u.done)})};return l},"es6","es3");$jscomp.owns=function(h,n){return Object.prototype.hasOwnProperty.call(h,n)};$jscomp.assign=$jscomp.TRUST_ES6_POLYFILLS&&"function"==typeof Object.assign?Object.assign:function(h,n){for(var k=1;k<arguments.length;k++){var p=arguments[k];if(p)for(var l in p)$jscomp.owns(p,l)&&(h[l]=p[l])}return h};
|
||||
$jscomp.polyfill("Object.assign",function(h){return h||$jscomp.assign},"es6","es3");$jscomp.checkStringArgs=function(h,n,k){if(null==h)throw new TypeError("The 'this' value for String.prototype."+k+" must not be null or undefined");if(n instanceof RegExp)throw new TypeError("First argument to String.prototype."+k+" must not be a regular expression");return h+""};
|
||||
$jscomp.polyfill("String.prototype.startsWith",function(h){return h?h:function(n,k){var p=$jscomp.checkStringArgs(this,n,"startsWith");n+="";var l=p.length,y=n.length;k=Math.max(0,Math.min(k|0,p.length));for(var f=0;f<y&&k<l;)if(p[k++]!=n[f++])return!1;return f>=y}},"es6","es3");
|
||||
$jscomp.polyfill("Array.prototype.copyWithin",function(h){function n(k){k=Number(k);return Infinity===k||-Infinity===k?k:k|0}return h?h:function(k,p,l){var y=this.length;k=n(k);p=n(p);l=void 0===l?y:n(l);k=0>k?Math.max(y+k,0):Math.min(k,y);p=0>p?Math.max(y+p,0):Math.min(p,y);l=0>l?Math.max(y+l,0):Math.min(l,y);if(k<p)for(;p<l;)p in this?this[k++]=this[p++]:(delete this[k++],p++);else for(l=Math.min(l,y+p-k),k+=l-p;l>p;)--l in this?this[--k]=this[l]:delete this[--k];return this}},"es6","es3");
|
||||
$jscomp.typedArrayCopyWithin=function(h){return h?h:Array.prototype.copyWithin};$jscomp.polyfill("Int8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8ClampedArray.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");
|
||||
$jscomp.polyfill("Uint16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float64Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");
|
||||
var DracoDecoderModule=function(){var h="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(h=h||__filename);return function(n){function k(e){return a.locateFile?a.locateFile(e,U):U+e}function p(e,b){if(e){var c=ia;var d=e+b;for(b=e;c[b]&&!(b>=d);)++b;if(16<b-e&&c.buffer&&ra)c=ra.decode(c.subarray(e,b));else{for(d="";e<b;){var g=c[e++];if(g&128){var t=c[e++]&63;if(192==(g&224))d+=String.fromCharCode((g&31)<<6|t);else{var aa=c[e++]&
|
||||
63;g=224==(g&240)?(g&15)<<12|t<<6|aa:(g&7)<<18|t<<12|aa<<6|c[e++]&63;65536>g?d+=String.fromCharCode(g):(g-=65536,d+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else d+=String.fromCharCode(g)}c=d}}else c="";return c}function l(){var e=ja.buffer;a.HEAP8=W=new Int8Array(e);a.HEAP16=new Int16Array(e);a.HEAP32=ca=new Int32Array(e);a.HEAPU8=ia=new Uint8Array(e);a.HEAPU16=new Uint16Array(e);a.HEAPU32=Y=new Uint32Array(e);a.HEAPF32=new Float32Array(e);a.HEAPF64=new Float64Array(e)}function y(e){if(a.onAbort)a.onAbort(e);
|
||||
e="Aborted("+e+")";da(e);sa=!0;e=new WebAssembly.RuntimeError(e+". Build with -sASSERTIONS for more info.");ka(e);throw e;}function f(e){try{if(e==P&&ea)return new Uint8Array(ea);if(ma)return ma(e);throw"both async and sync fetching of the wasm failed";}catch(b){y(b)}}function q(){if(!ea&&(ta||fa)){if("function"==typeof fetch&&!P.startsWith("file://"))return fetch(P,{credentials:"same-origin"}).then(function(e){if(!e.ok)throw"failed to load wasm binary file at '"+P+"'";return e.arrayBuffer()}).catch(function(){return f(P)});
|
||||
if(na)return new Promise(function(e,b){na(P,function(c){e(new Uint8Array(c))},b)})}return Promise.resolve().then(function(){return f(P)})}function u(e){for(;0<e.length;)e.shift()(a)}function A(e){this.excPtr=e;this.ptr=e-24;this.set_type=function(b){Y[this.ptr+4>>2]=b};this.get_type=function(){return Y[this.ptr+4>>2]};this.set_destructor=function(b){Y[this.ptr+8>>2]=b};this.get_destructor=function(){return Y[this.ptr+8>>2]};this.set_refcount=function(b){ca[this.ptr>>2]=b};this.set_caught=function(b){W[this.ptr+
|
||||
12>>0]=b?1:0};this.get_caught=function(){return 0!=W[this.ptr+12>>0]};this.set_rethrown=function(b){W[this.ptr+13>>0]=b?1:0};this.get_rethrown=function(){return 0!=W[this.ptr+13>>0]};this.init=function(b,c){this.set_adjusted_ptr(0);this.set_type(b);this.set_destructor(c);this.set_refcount(0);this.set_caught(!1);this.set_rethrown(!1)};this.add_ref=function(){ca[this.ptr>>2]+=1};this.release_ref=function(){var b=ca[this.ptr>>2];ca[this.ptr>>2]=b-1;return 1===b};this.set_adjusted_ptr=function(b){Y[this.ptr+
|
||||
16>>2]=b};this.get_adjusted_ptr=function(){return Y[this.ptr+16>>2]};this.get_exception_ptr=function(){if(ua(this.get_type()))return Y[this.excPtr>>2];var b=this.get_adjusted_ptr();return 0!==b?b:this.excPtr}}function F(){function e(){if(!la&&(la=!0,a.calledRun=!0,!sa)){va=!0;u(oa);wa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)xa.unshift(a.postRun.shift());u(xa)}}if(!(0<ba)){if(a.preRun)for("function"==
|
||||
typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)ya.unshift(a.preRun.shift());u(ya);0<ba||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);e()},1)):e())}}function v(){}function w(e){return(e||v).__cache__}function B(e,b){var c=w(b),d=c[e];if(d)return d;d=Object.create((b||v).prototype);d.ptr=e;return c[e]=d}function R(e){if("string"===typeof e){for(var b=0,c=0;c<e.length;++c){var d=e.charCodeAt(c);127>=d?b++:2047>=d?b+=2:55296<=d&&57343>=
|
||||
d?(b+=4,++c):b+=3}b=Array(b+1);c=0;d=b.length;if(0<d){d=c+d-1;for(var g=0;g<e.length;++g){var t=e.charCodeAt(g);if(55296<=t&&57343>=t){var aa=e.charCodeAt(++g);t=65536+((t&1023)<<10)|aa&1023}if(127>=t){if(c>=d)break;b[c++]=t}else{if(2047>=t){if(c+1>=d)break;b[c++]=192|t>>6}else{if(65535>=t){if(c+2>=d)break;b[c++]=224|t>>12}else{if(c+3>=d)break;b[c++]=240|t>>18;b[c++]=128|t>>12&63}b[c++]=128|t>>6&63}b[c++]=128|t&63}}b[c]=0}e=r.alloc(b,W);r.copy(b,W,e);return e}return e}function Z(e){if("object"===
|
||||
typeof e){var b=r.alloc(e,W);r.copy(e,W,b);return b}return e}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function S(){this.ptr=za();w(S)[this.ptr]=this}function Q(){this.ptr=Aa();w(Q)[this.ptr]=this}function V(){this.ptr=Ba();w(V)[this.ptr]=this}function x(){this.ptr=Ca();w(x)[this.ptr]=this}function D(){this.ptr=Da();w(D)[this.ptr]=this}function G(){this.ptr=Ea();w(G)[this.ptr]=this}function H(){this.ptr=Fa();w(H)[this.ptr]=this}function E(){this.ptr=Ga();w(E)[this.ptr]=
|
||||
this}function T(){this.ptr=Ha();w(T)[this.ptr]=this}function C(){throw"cannot construct a Status, no constructor in IDL";}function I(){this.ptr=Ia();w(I)[this.ptr]=this}function J(){this.ptr=Ja();w(J)[this.ptr]=this}function K(){this.ptr=Ka();w(K)[this.ptr]=this}function L(){this.ptr=La();w(L)[this.ptr]=this}function M(){this.ptr=Ma();w(M)[this.ptr]=this}function N(){this.ptr=Na();w(N)[this.ptr]=this}function O(){this.ptr=Oa();w(O)[this.ptr]=this}function z(){this.ptr=Pa();w(z)[this.ptr]=this}function m(){this.ptr=
|
||||
Qa();w(m)[this.ptr]=this}n=void 0===n?{}:n;var a="undefined"!=typeof n?n:{},wa,ka;a.ready=new Promise(function(e,b){wa=e;ka=b});var Ra=!1,Sa=!1;a.onRuntimeInitialized=function(){Ra=!0;if(Sa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Sa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(e){if("string"!==typeof e)return!1;e=e.split(".");return 2>e.length||3<e.length?!1:1==e[0]&&0<=e[1]&&5>=e[1]?!0:0!=e[0]||10<
|
||||
e[1]?!1:!0};var Ta=Object.assign({},a),ta="object"==typeof window,fa="function"==typeof importScripts,Ua="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,U="";if(Ua){var Va=require("fs"),pa=require("path");U=fa?pa.dirname(U)+"/":__dirname+"/";var Wa=function(e,b){e=e.startsWith("file://")?new URL(e):pa.normalize(e);return Va.readFileSync(e,b?void 0:"utf8")};var ma=function(e){e=Wa(e,!0);e.buffer||(e=new Uint8Array(e));return e};var na=function(e,
|
||||
b,c){e=e.startsWith("file://")?new URL(e):pa.normalize(e);Va.readFile(e,function(d,g){d?c(d):b(g.buffer)})};1<process.argv.length&&process.argv[1].replace(/\\/g,"/");process.argv.slice(2);a.inspect=function(){return"[Emscripten Module object]"}}else if(ta||fa)fa?U=self.location.href:"undefined"!=typeof document&&document.currentScript&&(U=document.currentScript.src),h&&(U=h),U=0!==U.indexOf("blob:")?U.substr(0,U.replace(/[?#].*/,"").lastIndexOf("/")+1):"",Wa=function(e){var b=new XMLHttpRequest;b.open("GET",
|
||||
e,!1);b.send(null);return b.responseText},fa&&(ma=function(e){var b=new XMLHttpRequest;b.open("GET",e,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),na=function(e,b,c){var d=new XMLHttpRequest;d.open("GET",e,!0);d.responseType="arraybuffer";d.onload=function(){200==d.status||0==d.status&&d.response?b(d.response):c()};d.onerror=c;d.send(null)};a.print||console.log.bind(console);var da=a.printErr||console.warn.bind(console);Object.assign(a,Ta);Ta=null;var ea;a.wasmBinary&&
|
||||
(ea=a.wasmBinary);"object"!=typeof WebAssembly&&y("no native wasm support detected");var ja,sa=!1,ra="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,W,ia,ca,Y,ya=[],oa=[],xa=[],va=!1,ba=0,qa=null,ha=null;var P="draco_decoder_gltf.wasm";P.startsWith("data:application/octet-stream;base64,")||(P=k(P));var pd=0,qd={b:function(e,b,c){(new A(e)).init(b,c);pd++;throw e;},a:function(){y("")},d:function(e,b,c){ia.copyWithin(e,b,b+c)},c:function(e){var b=ia.length;e>>>=0;if(2147483648<e)return!1;
|
||||
for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,e+100663296);var g=Math;d=Math.max(e,d);g=g.min.call(g,2147483648,d+(65536-d%65536)%65536);a:{d=ja.buffer;try{ja.grow(g-d.byteLength+65535>>>16);l();var t=1;break a}catch(aa){}t=void 0}if(t)return!0}return!1}};(function(){function e(g,t){a.asm=g.exports;ja=a.asm.e;l();oa.unshift(a.asm.f);ba--;a.monitorRunDependencies&&a.monitorRunDependencies(ba);0==ba&&(null!==qa&&(clearInterval(qa),qa=null),ha&&(g=ha,ha=null,g()))}function b(g){e(g.instance)}
|
||||
function c(g){return q().then(function(t){return WebAssembly.instantiate(t,d)}).then(function(t){return t}).then(g,function(t){da("failed to asynchronously prepare wasm: "+t);y(t)})}var d={a:qd};ba++;a.monitorRunDependencies&&a.monitorRunDependencies(ba);if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(g){da("Module.instantiateWasm callback failed with error: "+g),ka(g)}(function(){return ea||"function"!=typeof WebAssembly.instantiateStreaming||P.startsWith("data:application/octet-stream;base64,")||
|
||||
P.startsWith("file://")||Ua||"function"!=typeof fetch?c(b):fetch(P,{credentials:"same-origin"}).then(function(g){return WebAssembly.instantiateStreaming(g,d).then(b,function(t){da("wasm streaming compile failed: "+t);da("falling back to ArrayBuffer instantiation");return c(b)})})})().catch(ka);return{}})();var Xa=a._emscripten_bind_VoidPtr___destroy___0=function(){return(Xa=a._emscripten_bind_VoidPtr___destroy___0=a.asm.h).apply(null,arguments)},za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=
|
||||
function(){return(za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=a.asm.i).apply(null,arguments)},Ya=a._emscripten_bind_DecoderBuffer_Init_2=function(){return(Ya=a._emscripten_bind_DecoderBuffer_Init_2=a.asm.j).apply(null,arguments)},Za=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return(Za=a._emscripten_bind_DecoderBuffer___destroy___0=a.asm.k).apply(null,arguments)},Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return(Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=
|
||||
a.asm.l).apply(null,arguments)},$a=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return($a=a._emscripten_bind_AttributeTransformData_transform_type_0=a.asm.m).apply(null,arguments)},ab=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return(ab=a._emscripten_bind_AttributeTransformData___destroy___0=a.asm.n).apply(null,arguments)},Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return(Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=
|
||||
a.asm.o).apply(null,arguments)},bb=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return(bb=a._emscripten_bind_GeometryAttribute___destroy___0=a.asm.p).apply(null,arguments)},Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return(Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=a.asm.q).apply(null,arguments)},cb=a._emscripten_bind_PointAttribute_size_0=function(){return(cb=a._emscripten_bind_PointAttribute_size_0=a.asm.r).apply(null,arguments)},db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=
|
||||
function(){return(db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=a.asm.s).apply(null,arguments)},eb=a._emscripten_bind_PointAttribute_attribute_type_0=function(){return(eb=a._emscripten_bind_PointAttribute_attribute_type_0=a.asm.t).apply(null,arguments)},fb=a._emscripten_bind_PointAttribute_data_type_0=function(){return(fb=a._emscripten_bind_PointAttribute_data_type_0=a.asm.u).apply(null,arguments)},gb=a._emscripten_bind_PointAttribute_num_components_0=function(){return(gb=a._emscripten_bind_PointAttribute_num_components_0=
|
||||
a.asm.v).apply(null,arguments)},hb=a._emscripten_bind_PointAttribute_normalized_0=function(){return(hb=a._emscripten_bind_PointAttribute_normalized_0=a.asm.w).apply(null,arguments)},ib=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return(ib=a._emscripten_bind_PointAttribute_byte_stride_0=a.asm.x).apply(null,arguments)},jb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return(jb=a._emscripten_bind_PointAttribute_byte_offset_0=a.asm.y).apply(null,arguments)},kb=a._emscripten_bind_PointAttribute_unique_id_0=
|
||||
function(){return(kb=a._emscripten_bind_PointAttribute_unique_id_0=a.asm.z).apply(null,arguments)},lb=a._emscripten_bind_PointAttribute___destroy___0=function(){return(lb=a._emscripten_bind_PointAttribute___destroy___0=a.asm.A).apply(null,arguments)},Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return(Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=a.asm.B).apply(null,arguments)},mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=
|
||||
function(){return(mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=a.asm.C).apply(null,arguments)},nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return(nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=a.asm.D).apply(null,arguments)},ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return(ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=a.asm.E).apply(null,arguments)},pb=
|
||||
a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return(pb=a._emscripten_bind_AttributeQuantizationTransform_range_0=a.asm.F).apply(null,arguments)},qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return(qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=a.asm.G).apply(null,arguments)},Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return(Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=
|
||||
a.asm.H).apply(null,arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return(rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=a.asm.I).apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return(sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=a.asm.J).apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return(tb=
|
||||
a._emscripten_bind_AttributeOctahedronTransform___destroy___0=a.asm.K).apply(null,arguments)},Fa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return(Fa=a._emscripten_bind_PointCloud_PointCloud_0=a.asm.L).apply(null,arguments)},ub=a._emscripten_bind_PointCloud_num_attributes_0=function(){return(ub=a._emscripten_bind_PointCloud_num_attributes_0=a.asm.M).apply(null,arguments)},vb=a._emscripten_bind_PointCloud_num_points_0=function(){return(vb=a._emscripten_bind_PointCloud_num_points_0=a.asm.N).apply(null,
|
||||
arguments)},wb=a._emscripten_bind_PointCloud___destroy___0=function(){return(wb=a._emscripten_bind_PointCloud___destroy___0=a.asm.O).apply(null,arguments)},Ga=a._emscripten_bind_Mesh_Mesh_0=function(){return(Ga=a._emscripten_bind_Mesh_Mesh_0=a.asm.P).apply(null,arguments)},xb=a._emscripten_bind_Mesh_num_faces_0=function(){return(xb=a._emscripten_bind_Mesh_num_faces_0=a.asm.Q).apply(null,arguments)},yb=a._emscripten_bind_Mesh_num_attributes_0=function(){return(yb=a._emscripten_bind_Mesh_num_attributes_0=
|
||||
a.asm.R).apply(null,arguments)},zb=a._emscripten_bind_Mesh_num_points_0=function(){return(zb=a._emscripten_bind_Mesh_num_points_0=a.asm.S).apply(null,arguments)},Ab=a._emscripten_bind_Mesh___destroy___0=function(){return(Ab=a._emscripten_bind_Mesh___destroy___0=a.asm.T).apply(null,arguments)},Ha=a._emscripten_bind_Metadata_Metadata_0=function(){return(Ha=a._emscripten_bind_Metadata_Metadata_0=a.asm.U).apply(null,arguments)},Bb=a._emscripten_bind_Metadata___destroy___0=function(){return(Bb=a._emscripten_bind_Metadata___destroy___0=
|
||||
a.asm.V).apply(null,arguments)},Cb=a._emscripten_bind_Status_code_0=function(){return(Cb=a._emscripten_bind_Status_code_0=a.asm.W).apply(null,arguments)},Db=a._emscripten_bind_Status_ok_0=function(){return(Db=a._emscripten_bind_Status_ok_0=a.asm.X).apply(null,arguments)},Eb=a._emscripten_bind_Status_error_msg_0=function(){return(Eb=a._emscripten_bind_Status_error_msg_0=a.asm.Y).apply(null,arguments)},Fb=a._emscripten_bind_Status___destroy___0=function(){return(Fb=a._emscripten_bind_Status___destroy___0=
|
||||
a.asm.Z).apply(null,arguments)},Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return(Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=a.asm._).apply(null,arguments)},Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return(Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=a.asm.$).apply(null,arguments)},Hb=a._emscripten_bind_DracoFloat32Array_size_0=function(){return(Hb=a._emscripten_bind_DracoFloat32Array_size_0=a.asm.aa).apply(null,arguments)},Ib=
|
||||
a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return(Ib=a._emscripten_bind_DracoFloat32Array___destroy___0=a.asm.ba).apply(null,arguments)},Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return(Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=a.asm.ca).apply(null,arguments)},Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return(Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=a.asm.da).apply(null,arguments)},Kb=a._emscripten_bind_DracoInt8Array_size_0=
|
||||
function(){return(Kb=a._emscripten_bind_DracoInt8Array_size_0=a.asm.ea).apply(null,arguments)},Lb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return(Lb=a._emscripten_bind_DracoInt8Array___destroy___0=a.asm.fa).apply(null,arguments)},Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return(Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=a.asm.ga).apply(null,arguments)},Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return(Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=
|
||||
a.asm.ha).apply(null,arguments)},Nb=a._emscripten_bind_DracoUInt8Array_size_0=function(){return(Nb=a._emscripten_bind_DracoUInt8Array_size_0=a.asm.ia).apply(null,arguments)},Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return(Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=a.asm.ja).apply(null,arguments)},La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return(La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=a.asm.ka).apply(null,arguments)},Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=
|
||||
function(){return(Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=a.asm.la).apply(null,arguments)},Qb=a._emscripten_bind_DracoInt16Array_size_0=function(){return(Qb=a._emscripten_bind_DracoInt16Array_size_0=a.asm.ma).apply(null,arguments)},Rb=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return(Rb=a._emscripten_bind_DracoInt16Array___destroy___0=a.asm.na).apply(null,arguments)},Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return(Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=
|
||||
a.asm.oa).apply(null,arguments)},Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return(Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=a.asm.pa).apply(null,arguments)},Tb=a._emscripten_bind_DracoUInt16Array_size_0=function(){return(Tb=a._emscripten_bind_DracoUInt16Array_size_0=a.asm.qa).apply(null,arguments)},Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return(Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=a.asm.ra).apply(null,arguments)},Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=
|
||||
function(){return(Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=a.asm.sa).apply(null,arguments)},Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return(Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=a.asm.ta).apply(null,arguments)},Wb=a._emscripten_bind_DracoInt32Array_size_0=function(){return(Wb=a._emscripten_bind_DracoInt32Array_size_0=a.asm.ua).apply(null,arguments)},Xb=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return(Xb=a._emscripten_bind_DracoInt32Array___destroy___0=
|
||||
a.asm.va).apply(null,arguments)},Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return(Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=a.asm.wa).apply(null,arguments)},Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return(Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=a.asm.xa).apply(null,arguments)},Zb=a._emscripten_bind_DracoUInt32Array_size_0=function(){return(Zb=a._emscripten_bind_DracoUInt32Array_size_0=a.asm.ya).apply(null,arguments)},$b=a._emscripten_bind_DracoUInt32Array___destroy___0=
|
||||
function(){return($b=a._emscripten_bind_DracoUInt32Array___destroy___0=a.asm.za).apply(null,arguments)},Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return(Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=a.asm.Aa).apply(null,arguments)},ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return(ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=a.asm.Ba).apply(null,arguments)},bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return(bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=
|
||||
a.asm.Ca).apply(null,arguments)},cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=function(){return(cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=a.asm.Da).apply(null,arguments)},dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return(dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=a.asm.Ea).apply(null,arguments)},ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return(ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=a.asm.Fa).apply(null,
|
||||
arguments)},fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return(fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=a.asm.Ga).apply(null,arguments)},gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return(gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=a.asm.Ha).apply(null,arguments)},hc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return(hc=a._emscripten_bind_MetadataQuerier___destroy___0=a.asm.Ia).apply(null,arguments)},Qa=a._emscripten_bind_Decoder_Decoder_0=
|
||||
function(){return(Qa=a._emscripten_bind_Decoder_Decoder_0=a.asm.Ja).apply(null,arguments)},ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=function(){return(ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=a.asm.Ka).apply(null,arguments)},jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=function(){return(jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=a.asm.La).apply(null,arguments)},kc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return(kc=a._emscripten_bind_Decoder_GetAttributeId_2=
|
||||
a.asm.Ma).apply(null,arguments)},lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return(lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=a.asm.Na).apply(null,arguments)},mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return(mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=a.asm.Oa).apply(null,arguments)},nc=a._emscripten_bind_Decoder_GetAttribute_2=function(){return(nc=a._emscripten_bind_Decoder_GetAttribute_2=a.asm.Pa).apply(null,arguments)},
|
||||
oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return(oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=a.asm.Qa).apply(null,arguments)},pc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return(pc=a._emscripten_bind_Decoder_GetMetadata_1=a.asm.Ra).apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return(qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=a.asm.Sa).apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=
|
||||
function(){return(rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=a.asm.Ta).apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return(sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=a.asm.Ua).apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return(tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=a.asm.Va).apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=function(){return(uc=
|
||||
a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=a.asm.Wa).apply(null,arguments)},vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return(vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=a.asm.Xa).apply(null,arguments)},wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return(wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=a.asm.Ya).apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return(xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=
|
||||
a.asm.Za).apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return(yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=a.asm._a).apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return(zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=a.asm.$a).apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return(Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=
|
||||
a.asm.ab).apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return(Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=a.asm.bb).apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return(Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=a.asm.cb).apply(null,arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return(Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=
|
||||
a.asm.db).apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=function(){return(Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=a.asm.eb).apply(null,arguments)},Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return(Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=a.asm.fb).apply(null,arguments)},Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=function(){return(Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=
|
||||
a.asm.gb).apply(null,arguments)},Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return(Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=a.asm.hb).apply(null,arguments)},Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return(Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=a.asm.ib).apply(null,arguments)},Jc=a._emscripten_bind_Decoder___destroy___0=function(){return(Jc=a._emscripten_bind_Decoder___destroy___0=a.asm.jb).apply(null,arguments)},Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=
|
||||
function(){return(Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=a.asm.kb).apply(null,arguments)},Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return(Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=a.asm.lb).apply(null,arguments)},Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return(Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=
|
||||
a.asm.mb).apply(null,arguments)},Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=function(){return(Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=a.asm.nb).apply(null,arguments)},Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return(Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=a.asm.ob).apply(null,arguments)},Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return(Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=
|
||||
a.asm.pb).apply(null,arguments)},Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return(Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=a.asm.qb).apply(null,arguments)},Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return(Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=a.asm.rb).apply(null,arguments)},Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return(Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=
|
||||
a.asm.sb).apply(null,arguments)},Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return(Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=a.asm.tb).apply(null,arguments)},Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return(Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=a.asm.ub).apply(null,arguments)},Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return(Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=
|
||||
a.asm.vb).apply(null,arguments)},Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return(Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=a.asm.wb).apply(null,arguments)},Xc=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return(Xc=a._emscripten_enum_draco_DataType_DT_INVALID=a.asm.xb).apply(null,arguments)},Yc=a._emscripten_enum_draco_DataType_DT_INT8=function(){return(Yc=a._emscripten_enum_draco_DataType_DT_INT8=a.asm.yb).apply(null,arguments)},Zc=
|
||||
a._emscripten_enum_draco_DataType_DT_UINT8=function(){return(Zc=a._emscripten_enum_draco_DataType_DT_UINT8=a.asm.zb).apply(null,arguments)},$c=a._emscripten_enum_draco_DataType_DT_INT16=function(){return($c=a._emscripten_enum_draco_DataType_DT_INT16=a.asm.Ab).apply(null,arguments)},ad=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return(ad=a._emscripten_enum_draco_DataType_DT_UINT16=a.asm.Bb).apply(null,arguments)},bd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return(bd=a._emscripten_enum_draco_DataType_DT_INT32=
|
||||
a.asm.Cb).apply(null,arguments)},cd=a._emscripten_enum_draco_DataType_DT_UINT32=function(){return(cd=a._emscripten_enum_draco_DataType_DT_UINT32=a.asm.Db).apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return(dd=a._emscripten_enum_draco_DataType_DT_INT64=a.asm.Eb).apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return(ed=a._emscripten_enum_draco_DataType_DT_UINT64=a.asm.Fb).apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=
|
||||
function(){return(fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=a.asm.Gb).apply(null,arguments)},gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return(gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=a.asm.Hb).apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return(hd=a._emscripten_enum_draco_DataType_DT_BOOL=a.asm.Ib).apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return(id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=
|
||||
a.asm.Jb).apply(null,arguments)},jd=a._emscripten_enum_draco_StatusCode_OK=function(){return(jd=a._emscripten_enum_draco_StatusCode_OK=a.asm.Kb).apply(null,arguments)},kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return(kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=a.asm.Lb).apply(null,arguments)},ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return(ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=a.asm.Mb).apply(null,arguments)},md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=
|
||||
function(){return(md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=a.asm.Nb).apply(null,arguments)},nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return(nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=a.asm.Ob).apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return(od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=a.asm.Pb).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.Qb).apply(null,arguments)};
|
||||
a._free=function(){return(a._free=a.asm.Rb).apply(null,arguments)};var ua=function(){return(ua=a.asm.Sb).apply(null,arguments)};a.___start_em_js=11660;a.___stop_em_js=11758;var la;ha=function b(){la||F();la||(ha=b)};if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();F();v.prototype=Object.create(v.prototype);v.prototype.constructor=v;v.prototype.__class__=v;v.__cache__={};a.WrapperObject=v;a.getCache=w;a.wrapPointer=B;a.castObject=function(b,
|
||||
c){return B(b.ptr,c)};a.NULL=B(0);a.destroy=function(b){if(!b.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";b.__destroy__();delete w(b.__class__)[b.ptr]};a.compare=function(b,c){return b.ptr===c.ptr};a.getPointer=function(b){return b.ptr};a.getClass=function(b){return b.__class__};var r={buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(r.needed){for(var b=0;b<r.temps.length;b++)a._free(r.temps[b]);r.temps.length=0;a._free(r.buffer);r.buffer=0;r.size+=
|
||||
r.needed;r.needed=0}r.buffer||(r.size+=128,r.buffer=a._malloc(r.size),r.buffer||y(void 0));r.pos=0},alloc:function(b,c){r.buffer||y(void 0);b=b.length*c.BYTES_PER_ELEMENT;b=b+7&-8;r.pos+b>=r.size?(0<b||y(void 0),r.needed+=b,c=a._malloc(b),r.temps.push(c)):(c=r.buffer+r.pos,r.pos+=b);return c},copy:function(b,c,d){d>>>=0;switch(c.BYTES_PER_ELEMENT){case 2:d>>>=1;break;case 4:d>>>=2;break;case 8:d>>>=3}for(var g=0;g<b.length;g++)c[d+g]=b[g]}};X.prototype=Object.create(v.prototype);X.prototype.constructor=
|
||||
X;X.prototype.__class__=X;X.__cache__={};a.VoidPtr=X;X.prototype.__destroy__=X.prototype.__destroy__=function(){Xa(this.ptr)};S.prototype=Object.create(v.prototype);S.prototype.constructor=S;S.prototype.__class__=S;S.__cache__={};a.DecoderBuffer=S;S.prototype.Init=S.prototype.Init=function(b,c){var d=this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);Ya(d,b,c)};S.prototype.__destroy__=S.prototype.__destroy__=function(){Za(this.ptr)};Q.prototype=Object.create(v.prototype);
|
||||
Q.prototype.constructor=Q;Q.prototype.__class__=Q;Q.__cache__={};a.AttributeTransformData=Q;Q.prototype.transform_type=Q.prototype.transform_type=function(){return $a(this.ptr)};Q.prototype.__destroy__=Q.prototype.__destroy__=function(){ab(this.ptr)};V.prototype=Object.create(v.prototype);V.prototype.constructor=V;V.prototype.__class__=V;V.__cache__={};a.GeometryAttribute=V;V.prototype.__destroy__=V.prototype.__destroy__=function(){bb(this.ptr)};x.prototype=Object.create(v.prototype);x.prototype.constructor=
|
||||
x;x.prototype.__class__=x;x.__cache__={};a.PointAttribute=x;x.prototype.size=x.prototype.size=function(){return cb(this.ptr)};x.prototype.GetAttributeTransformData=x.prototype.GetAttributeTransformData=function(){return B(db(this.ptr),Q)};x.prototype.attribute_type=x.prototype.attribute_type=function(){return eb(this.ptr)};x.prototype.data_type=x.prototype.data_type=function(){return fb(this.ptr)};x.prototype.num_components=x.prototype.num_components=function(){return gb(this.ptr)};x.prototype.normalized=
|
||||
x.prototype.normalized=function(){return!!hb(this.ptr)};x.prototype.byte_stride=x.prototype.byte_stride=function(){return ib(this.ptr)};x.prototype.byte_offset=x.prototype.byte_offset=function(){return jb(this.ptr)};x.prototype.unique_id=x.prototype.unique_id=function(){return kb(this.ptr)};x.prototype.__destroy__=x.prototype.__destroy__=function(){lb(this.ptr)};D.prototype=Object.create(v.prototype);D.prototype.constructor=D;D.prototype.__class__=D;D.__cache__={};a.AttributeQuantizationTransform=
|
||||
D;D.prototype.InitFromAttribute=D.prototype.InitFromAttribute=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return!!mb(c,b)};D.prototype.quantization_bits=D.prototype.quantization_bits=function(){return nb(this.ptr)};D.prototype.min_value=D.prototype.min_value=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return ob(c,b)};D.prototype.range=D.prototype.range=function(){return pb(this.ptr)};D.prototype.__destroy__=D.prototype.__destroy__=function(){qb(this.ptr)};G.prototype=
|
||||
Object.create(v.prototype);G.prototype.constructor=G;G.prototype.__class__=G;G.__cache__={};a.AttributeOctahedronTransform=G;G.prototype.InitFromAttribute=G.prototype.InitFromAttribute=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return!!rb(c,b)};G.prototype.quantization_bits=G.prototype.quantization_bits=function(){return sb(this.ptr)};G.prototype.__destroy__=G.prototype.__destroy__=function(){tb(this.ptr)};H.prototype=Object.create(v.prototype);H.prototype.constructor=H;H.prototype.__class__=
|
||||
H;H.__cache__={};a.PointCloud=H;H.prototype.num_attributes=H.prototype.num_attributes=function(){return ub(this.ptr)};H.prototype.num_points=H.prototype.num_points=function(){return vb(this.ptr)};H.prototype.__destroy__=H.prototype.__destroy__=function(){wb(this.ptr)};E.prototype=Object.create(v.prototype);E.prototype.constructor=E;E.prototype.__class__=E;E.__cache__={};a.Mesh=E;E.prototype.num_faces=E.prototype.num_faces=function(){return xb(this.ptr)};E.prototype.num_attributes=E.prototype.num_attributes=
|
||||
function(){return yb(this.ptr)};E.prototype.num_points=E.prototype.num_points=function(){return zb(this.ptr)};E.prototype.__destroy__=E.prototype.__destroy__=function(){Ab(this.ptr)};T.prototype=Object.create(v.prototype);T.prototype.constructor=T;T.prototype.__class__=T;T.__cache__={};a.Metadata=T;T.prototype.__destroy__=T.prototype.__destroy__=function(){Bb(this.ptr)};C.prototype=Object.create(v.prototype);C.prototype.constructor=C;C.prototype.__class__=C;C.__cache__={};a.Status=C;C.prototype.code=
|
||||
C.prototype.code=function(){return Cb(this.ptr)};C.prototype.ok=C.prototype.ok=function(){return!!Db(this.ptr)};C.prototype.error_msg=C.prototype.error_msg=function(){return p(Eb(this.ptr))};C.prototype.__destroy__=C.prototype.__destroy__=function(){Fb(this.ptr)};I.prototype=Object.create(v.prototype);I.prototype.constructor=I;I.prototype.__class__=I;I.__cache__={};a.DracoFloat32Array=I;I.prototype.GetValue=I.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Gb(c,
|
||||
b)};I.prototype.size=I.prototype.size=function(){return Hb(this.ptr)};I.prototype.__destroy__=I.prototype.__destroy__=function(){Ib(this.ptr)};J.prototype=Object.create(v.prototype);J.prototype.constructor=J;J.prototype.__class__=J;J.__cache__={};a.DracoInt8Array=J;J.prototype.GetValue=J.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Jb(c,b)};J.prototype.size=J.prototype.size=function(){return Kb(this.ptr)};J.prototype.__destroy__=J.prototype.__destroy__=function(){Lb(this.ptr)};
|
||||
K.prototype=Object.create(v.prototype);K.prototype.constructor=K;K.prototype.__class__=K;K.__cache__={};a.DracoUInt8Array=K;K.prototype.GetValue=K.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Mb(c,b)};K.prototype.size=K.prototype.size=function(){return Nb(this.ptr)};K.prototype.__destroy__=K.prototype.__destroy__=function(){Ob(this.ptr)};L.prototype=Object.create(v.prototype);L.prototype.constructor=L;L.prototype.__class__=L;L.__cache__={};a.DracoInt16Array=
|
||||
L;L.prototype.GetValue=L.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Pb(c,b)};L.prototype.size=L.prototype.size=function(){return Qb(this.ptr)};L.prototype.__destroy__=L.prototype.__destroy__=function(){Rb(this.ptr)};M.prototype=Object.create(v.prototype);M.prototype.constructor=M;M.prototype.__class__=M;M.__cache__={};a.DracoUInt16Array=M;M.prototype.GetValue=M.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Sb(c,b)};
|
||||
M.prototype.size=M.prototype.size=function(){return Tb(this.ptr)};M.prototype.__destroy__=M.prototype.__destroy__=function(){Ub(this.ptr)};N.prototype=Object.create(v.prototype);N.prototype.constructor=N;N.prototype.__class__=N;N.__cache__={};a.DracoInt32Array=N;N.prototype.GetValue=N.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Vb(c,b)};N.prototype.size=N.prototype.size=function(){return Wb(this.ptr)};N.prototype.__destroy__=N.prototype.__destroy__=function(){Xb(this.ptr)};
|
||||
O.prototype=Object.create(v.prototype);O.prototype.constructor=O;O.prototype.__class__=O;O.__cache__={};a.DracoUInt32Array=O;O.prototype.GetValue=O.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Yb(c,b)};O.prototype.size=O.prototype.size=function(){return Zb(this.ptr)};O.prototype.__destroy__=O.prototype.__destroy__=function(){$b(this.ptr)};z.prototype=Object.create(v.prototype);z.prototype.constructor=z;z.prototype.__class__=z;z.__cache__={};a.MetadataQuerier=
|
||||
z;z.prototype.HasEntry=z.prototype.HasEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return!!ac(d,b,c)};z.prototype.GetIntEntry=z.prototype.GetIntEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return bc(d,b,c)};z.prototype.GetIntEntryArray=z.prototype.GetIntEntryArray=function(b,c,d){var g=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===
|
||||
typeof c?c.ptr:R(c);d&&"object"===typeof d&&(d=d.ptr);cc(g,b,c,d)};z.prototype.GetDoubleEntry=z.prototype.GetDoubleEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return dc(d,b,c)};z.prototype.GetStringEntry=z.prototype.GetStringEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return p(ec(d,b,c))};z.prototype.NumEntries=z.prototype.NumEntries=function(b){var c=this.ptr;
|
||||
b&&"object"===typeof b&&(b=b.ptr);return fc(c,b)};z.prototype.GetEntryName=z.prototype.GetEntryName=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return p(gc(d,b,c))};z.prototype.__destroy__=z.prototype.__destroy__=function(){hc(this.ptr)};m.prototype=Object.create(v.prototype);m.prototype.constructor=m;m.prototype.__class__=m;m.__cache__={};a.Decoder=m;m.prototype.DecodeArrayToPointCloud=m.prototype.DecodeArrayToPointCloud=function(b,c,d){var g=
|
||||
this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return B(ic(g,b,c,d),C)};m.prototype.DecodeArrayToMesh=m.prototype.DecodeArrayToMesh=function(b,c,d){var g=this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return B(jc(g,b,c,d),C)};m.prototype.GetAttributeId=m.prototype.GetAttributeId=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&
|
||||
(c=c.ptr);return kc(d,b,c)};m.prototype.GetAttributeIdByName=m.prototype.GetAttributeIdByName=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return lc(d,b,c)};m.prototype.GetAttributeIdByMetadataEntry=m.prototype.GetAttributeIdByMetadataEntry=function(b,c,d){var g=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);d=d&&"object"===typeof d?d.ptr:R(d);return mc(g,b,c,d)};m.prototype.GetAttribute=
|
||||
m.prototype.GetAttribute=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(nc(d,b,c),x)};m.prototype.GetAttributeByUniqueId=m.prototype.GetAttributeByUniqueId=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(oc(d,b,c),x)};m.prototype.GetMetadata=m.prototype.GetMetadata=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return B(pc(c,b),T)};m.prototype.GetAttributeMetadata=m.prototype.GetAttributeMetadata=
|
||||
function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(qc(d,b,c),T)};m.prototype.GetFaceFromMesh=m.prototype.GetFaceFromMesh=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!rc(g,b,c,d)};m.prototype.GetTriangleStripsFromMesh=m.prototype.GetTriangleStripsFromMesh=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);
|
||||
return sc(d,b,c)};m.prototype.GetTrianglesUInt16Array=m.prototype.GetTrianglesUInt16Array=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!tc(g,b,c,d)};m.prototype.GetTrianglesUInt32Array=m.prototype.GetTrianglesUInt32Array=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!uc(g,b,c,d)};m.prototype.GetAttributeFloat=m.prototype.GetAttributeFloat=
|
||||
function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!vc(g,b,c,d)};m.prototype.GetAttributeFloatForAllPoints=m.prototype.GetAttributeFloatForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!wc(g,b,c,d)};m.prototype.GetAttributeIntForAllPoints=m.prototype.GetAttributeIntForAllPoints=function(b,c,d){var g=this.ptr;
|
||||
b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!xc(g,b,c,d)};m.prototype.GetAttributeInt8ForAllPoints=m.prototype.GetAttributeInt8ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!yc(g,b,c,d)};m.prototype.GetAttributeUInt8ForAllPoints=m.prototype.GetAttributeUInt8ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=
|
||||
b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!zc(g,b,c,d)};m.prototype.GetAttributeInt16ForAllPoints=m.prototype.GetAttributeInt16ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ac(g,b,c,d)};m.prototype.GetAttributeUInt16ForAllPoints=m.prototype.GetAttributeUInt16ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&
|
||||
(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Bc(g,b,c,d)};m.prototype.GetAttributeInt32ForAllPoints=m.prototype.GetAttributeInt32ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Cc(g,b,c,d)};m.prototype.GetAttributeUInt32ForAllPoints=m.prototype.GetAttributeUInt32ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===
|
||||
typeof d&&(d=d.ptr);return!!Dc(g,b,c,d)};m.prototype.GetAttributeDataArrayForAllPoints=m.prototype.GetAttributeDataArrayForAllPoints=function(b,c,d,g,t){var aa=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);g&&"object"===typeof g&&(g=g.ptr);t&&"object"===typeof t&&(t=t.ptr);return!!Ec(aa,b,c,d,g,t)};m.prototype.SkipAttributeTransform=m.prototype.SkipAttributeTransform=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);Fc(c,
|
||||
b)};m.prototype.GetEncodedGeometryType_Deprecated=m.prototype.GetEncodedGeometryType_Deprecated=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Gc(c,b)};m.prototype.DecodeBufferToPointCloud=m.prototype.DecodeBufferToPointCloud=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(Hc(d,b,c),C)};m.prototype.DecodeBufferToMesh=m.prototype.DecodeBufferToMesh=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===
|
||||
typeof c&&(c=c.ptr);return B(Ic(d,b,c),C)};m.prototype.__destroy__=m.prototype.__destroy__=function(){Jc(this.ptr)};(function(){function b(){a.ATTRIBUTE_INVALID_TRANSFORM=Kc();a.ATTRIBUTE_NO_TRANSFORM=Lc();a.ATTRIBUTE_QUANTIZATION_TRANSFORM=Mc();a.ATTRIBUTE_OCTAHEDRON_TRANSFORM=Nc();a.INVALID=Oc();a.POSITION=Pc();a.NORMAL=Qc();a.COLOR=Rc();a.TEX_COORD=Sc();a.GENERIC=Tc();a.INVALID_GEOMETRY_TYPE=Uc();a.POINT_CLOUD=Vc();a.TRIANGULAR_MESH=Wc();a.DT_INVALID=Xc();a.DT_INT8=Yc();a.DT_UINT8=Zc();a.DT_INT16=
|
||||
$c();a.DT_UINT16=ad();a.DT_INT32=bd();a.DT_UINT32=cd();a.DT_INT64=dd();a.DT_UINT64=ed();a.DT_FLOAT32=fd();a.DT_FLOAT64=gd();a.DT_BOOL=hd();a.DT_TYPES_COUNT=id();a.OK=jd();a.DRACO_ERROR=kd();a.IO_ERROR=ld();a.INVALID_PARAMETER=md();a.UNSUPPORTED_VERSION=nd();a.UNKNOWN_VERSION=od()}va?b():oa.unshift(b)})();if("function"===typeof a.onModuleParsed)a.onModuleParsed();a.Decoder.prototype.GetEncodedGeometryType=function(b){if(b.__class__&&b.__class__===a.DecoderBuffer)return a.Decoder.prototype.GetEncodedGeometryType_Deprecated(b);
|
||||
if(8>b.byteLength)return a.INVALID_GEOMETRY_TYPE;switch(b[7]){case 0:return a.POINT_CLOUD;case 1:return a.TRIANGULAR_MESH;default:return a.INVALID_GEOMETRY_TYPE}};return n.ready}}();"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule);
|
||||
@@ -352,6 +352,7 @@ interface RecordedSegmentStreamRuntime {
|
||||
target: RecordedSegmentTarget | null;
|
||||
fetchAbort: AbortController | null;
|
||||
notifiedRevision: number;
|
||||
hasPresentedFrame: boolean;
|
||||
pumping: boolean;
|
||||
disposed: boolean;
|
||||
onTargetBuffered: ((target: RecordedSegmentTarget) => void) | null;
|
||||
@@ -944,6 +945,7 @@ export function RecordedFmp4Player({
|
||||
target: null,
|
||||
fetchAbort: null,
|
||||
notifiedRevision: 0,
|
||||
hasPresentedFrame: false,
|
||||
pumping: false,
|
||||
disposed: false,
|
||||
onTargetBuffered: null,
|
||||
@@ -1090,8 +1092,13 @@ export function RecordedFmp4Player({
|
||||
runtime.fetchAbort?.abort();
|
||||
runtime.target = target;
|
||||
const alreadyBuffered = recordedSegmentTargetBuffered(runtime, target);
|
||||
const retainForwardFrame = Boolean(
|
||||
runtime.hasPresentedFrame
|
||||
&& previousTarget
|
||||
&& candidateTarget.sequence >= previousTarget.sequence,
|
||||
);
|
||||
video.pause();
|
||||
if (!alreadyBuffered) {
|
||||
if (!alreadyBuffered && !retainForwardFrame) {
|
||||
setReadyGeneration(null);
|
||||
setState("loading");
|
||||
}
|
||||
@@ -1119,6 +1126,7 @@ export function RecordedFmp4Player({
|
||||
|| runtime.target?.revision !== bufferedTarget.revision
|
||||
) return;
|
||||
setBufferRevision((revision) => revision + 1);
|
||||
runtime.hasPresentedFrame = true;
|
||||
setReadyGeneration(runtime.generation);
|
||||
setState("ready");
|
||||
reportAdmission({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
forwardRef,
|
||||
type CSSProperties,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
@@ -26,6 +27,7 @@ export interface LaboratoryMetricObstacleVisual {
|
||||
state: "current" | "retained" | "held" | "expired";
|
||||
centroidBodyXyzM: LaboratoryMetricPoint3;
|
||||
cellCentersBodyXyzM: readonly LaboratoryMetricPoint3[];
|
||||
occupancySource?: "baseline" | "mixed" | "additive-low-step";
|
||||
}
|
||||
|
||||
export interface LaboratoryMetricRigVisual {
|
||||
@@ -40,11 +42,41 @@ export interface LaboratoryMetricCorridorVisual {
|
||||
halfWidthM: number;
|
||||
}
|
||||
|
||||
export type LaboratoryMetricCellState =
|
||||
| "unobserved"
|
||||
| "ground-support"
|
||||
| "nonground-occupied"
|
||||
| "unknown-rejected";
|
||||
|
||||
export interface LaboratoryMetricCellEvidence {
|
||||
centerBodyXyM: readonly [number, number];
|
||||
zBoundsM: readonly [number | null, number | null];
|
||||
state: LaboratoryMetricCellState;
|
||||
}
|
||||
|
||||
export interface LaboratoryMetricPackedCellEvidence {
|
||||
centersBodyXyM: Float32Array;
|
||||
zBoundsM: Float32Array;
|
||||
stateCodes: Uint8Array;
|
||||
}
|
||||
|
||||
export interface LaboratoryMetricLegendEntry {
|
||||
id: LaboratoryMetricDecision | "context" | "local-surface" | "rolling";
|
||||
id: LaboratoryMetricDecision
|
||||
| LaboratoryMetricCellState
|
||||
| "context"
|
||||
| "local-surface"
|
||||
| "rolling"
|
||||
| "low-step";
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface LaboratoryMetricRenderStats {
|
||||
frameMs: number;
|
||||
drawCalls: number;
|
||||
triangles: number;
|
||||
pixelRatio: number;
|
||||
}
|
||||
|
||||
export function laboratoryMetricLegendEntries({
|
||||
pointCloudCount,
|
||||
localSurfaceCount,
|
||||
@@ -52,6 +84,7 @@ export function laboratoryMetricLegendEntries({
|
||||
showCurrentIncrement,
|
||||
showLocalSurface,
|
||||
showRollingMap,
|
||||
showLowStep = true,
|
||||
}: {
|
||||
pointCloudCount: number;
|
||||
localSurfaceCount: number;
|
||||
@@ -59,19 +92,29 @@ export function laboratoryMetricLegendEntries({
|
||||
showCurrentIncrement: boolean;
|
||||
showLocalSurface: boolean;
|
||||
showRollingMap: boolean;
|
||||
showLowStep?: boolean;
|
||||
}): readonly LaboratoryMetricLegendEntry[] {
|
||||
const visibleObstacles = obstacles.filter((obstacle) => (
|
||||
obstacle.state === "current"
|
||||
(showLowStep || obstacle.occupancySource === undefined || obstacle.occupancySource === "baseline")
|
||||
&& (obstacle.state === "current"
|
||||
? showCurrentIncrement
|
||||
: obstacle.state === "retained"
|
||||
? showRollingMap
|
||||
: false
|
||||
: false)
|
||||
));
|
||||
const decisions = new Set(visibleObstacles.map(({ decision }) => decision));
|
||||
const entries: LaboratoryMetricLegendEntry[] = [];
|
||||
if (decisions.has("threat")) entries.push({ id: "threat", label: "Угроза" });
|
||||
if (decisions.has("not-threat")) entries.push({ id: "not-threat", label: "Вне коридора" });
|
||||
if (decisions.has("unknown")) entries.push({ id: "unknown", label: "Неизвестно" });
|
||||
if (
|
||||
showLowStep
|
||||
&& visibleObstacles.some((obstacle) => (
|
||||
obstacle.occupancySource !== undefined && obstacle.occupancySource !== "baseline"
|
||||
))
|
||||
) {
|
||||
entries.push({ id: "low-step", label: "LOW-STEP · добавлено системой" });
|
||||
}
|
||||
if (showCurrentIncrement && pointCloudCount > 0) {
|
||||
entries.push({ id: "context", label: "Текущий кадр" });
|
||||
}
|
||||
@@ -140,6 +183,47 @@ function positions(points: readonly LaboratoryMetricPoint3[]): Float32Array {
|
||||
return result;
|
||||
}
|
||||
|
||||
function updatePointPositions(
|
||||
geometry: THREE.BufferGeometry,
|
||||
points: readonly LaboratoryMetricPoint3[],
|
||||
): void {
|
||||
const requiredValues = points.length * 3;
|
||||
let attribute = geometry.getAttribute("position") as THREE.BufferAttribute | undefined;
|
||||
if (!attribute || attribute.array.length < requiredValues) {
|
||||
let capacity = 3;
|
||||
while (capacity < requiredValues) capacity *= 2;
|
||||
attribute = new THREE.BufferAttribute(new Float32Array(capacity), 3);
|
||||
attribute.setUsage(THREE.DynamicDrawUsage);
|
||||
geometry.setAttribute("position", attribute);
|
||||
}
|
||||
const values = attribute.array as Float32Array;
|
||||
points.forEach((point, index) => {
|
||||
const [x, y, z] = scenePoint(point);
|
||||
const offset = index * 3;
|
||||
values[offset] = x;
|
||||
values[offset + 1] = y;
|
||||
values[offset + 2] = z;
|
||||
});
|
||||
attribute.needsUpdate = true;
|
||||
geometry.setDrawRange(0, points.length);
|
||||
}
|
||||
|
||||
function ensurePointColors(
|
||||
geometry: THREE.BufferGeometry,
|
||||
pointCount: number,
|
||||
): THREE.BufferAttribute {
|
||||
const requiredValues = pointCount * 3;
|
||||
let attribute = geometry.getAttribute("color") as THREE.BufferAttribute | undefined;
|
||||
if (!attribute || attribute.array.length < requiredValues) {
|
||||
let capacity = 3;
|
||||
while (capacity < requiredValues) capacity *= 2;
|
||||
attribute = new THREE.BufferAttribute(new Float32Array(capacity), 3);
|
||||
attribute.setUsage(THREE.DynamicDrawUsage);
|
||||
geometry.setAttribute("color", attribute);
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
|
||||
function decisionColor(
|
||||
host: HTMLElement,
|
||||
decision: LaboratoryMetricDecision,
|
||||
@@ -153,6 +237,16 @@ function decisionColor(
|
||||
return tokenColor(host, "--nodedc-warning-rgb", [255, 197, 92]);
|
||||
}
|
||||
|
||||
function obstacleColor(
|
||||
host: HTMLElement,
|
||||
obstacle: LaboratoryMetricObstacleVisual,
|
||||
): THREE.Color {
|
||||
if (obstacle.occupancySource !== "baseline") {
|
||||
return tokenColor(host, "--nodedc-accent-rgb", [232, 56, 126]);
|
||||
}
|
||||
return decisionColor(host, obstacle.decision);
|
||||
}
|
||||
|
||||
export interface LaboratoryMetricEvidenceSceneHandle {
|
||||
resetView: () => void;
|
||||
}
|
||||
@@ -171,9 +265,14 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
showCurrentIncrement: boolean;
|
||||
showLocalSurface: boolean;
|
||||
showRollingMap: boolean;
|
||||
showLowStep?: boolean;
|
||||
pointSemanticClassIds?: readonly (number | null)[];
|
||||
semanticClasses?: readonly RecordedEvidenceSemanticClass[];
|
||||
semanticPalette?: readonly RecordedEvidenceSemanticPaletteEntry[];
|
||||
classifiedCells?: readonly LaboratoryMetricCellEvidence[];
|
||||
classifiedPackedCells?: LaboratoryMetricPackedCellEvidence;
|
||||
classifiedCellSizeM?: number;
|
||||
showClassifiedCells?: boolean;
|
||||
}
|
||||
>(function LaboratoryMetricEvidenceScene({
|
||||
pointCloudBodyXyzM,
|
||||
@@ -187,9 +286,14 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
showCurrentIncrement,
|
||||
showLocalSurface,
|
||||
showRollingMap,
|
||||
showLowStep = true,
|
||||
pointSemanticClassIds,
|
||||
semanticClasses,
|
||||
semanticPalette,
|
||||
classifiedCells = [],
|
||||
classifiedPackedCells,
|
||||
classifiedCellSizeM = 0.45,
|
||||
showClassifiedCells = true,
|
||||
}, ref) {
|
||||
const hostRef = useRef<HTMLDivElement | null>(null);
|
||||
const sceneRef = useRef<THREE.Scene | null>(null);
|
||||
@@ -197,7 +301,19 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
const controlsRef = useRef<OrbitControls | null>(null);
|
||||
const staticContentRef = useRef<THREE.Group | null>(null);
|
||||
const dynamicContentRef = useRef<THREE.Group | null>(null);
|
||||
const classifiedContentRef = useRef<THREE.Group | null>(null);
|
||||
const localSurfacePointsRef = useRef<THREE.Points | null>(null);
|
||||
const currentIncrementPointsRef = useRef<THREE.Points | null>(null);
|
||||
const requestRenderRef = useRef<() => void>(() => undefined);
|
||||
const corridorForwardLengthRef = useRef(corridor.forwardLengthM);
|
||||
const modeRef = useRef(mode);
|
||||
const classifiedMeshesRef = useRef<ReadonlyMap<LaboratoryMetricCellState, THREE.InstancedMesh>>(
|
||||
new Map(),
|
||||
);
|
||||
const [renderError, setRenderError] = useState<string | null>(null);
|
||||
const [renderStats, setRenderStats] = useState<LaboratoryMetricRenderStats | null>(null);
|
||||
corridorForwardLengthRef.current = corridor.forwardLengthM;
|
||||
modeRef.current = mode;
|
||||
|
||||
useEffect(() => {
|
||||
const host = hostRef.current;
|
||||
@@ -231,12 +347,76 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
controls.maxDistance = 80;
|
||||
const staticContent = new THREE.Group();
|
||||
const dynamicContent = new THREE.Group();
|
||||
scene.add(staticContent, dynamicContent);
|
||||
const classifiedContent = new THREE.Group();
|
||||
const localSurfacePoints = new THREE.Points(
|
||||
new THREE.BufferGeometry(),
|
||||
new THREE.PointsMaterial({
|
||||
color: tokenColor(host, "--nodedc-accent-rgb", [247, 248, 244]),
|
||||
size: 1.3,
|
||||
sizeAttenuation: false,
|
||||
transparent: true,
|
||||
opacity: 0.42,
|
||||
depthWrite: false,
|
||||
}),
|
||||
);
|
||||
const currentIncrementPoints = new THREE.Points(
|
||||
new THREE.BufferGeometry(),
|
||||
new THREE.PointsMaterial({
|
||||
color: tokenColor(host, "--nodedc-text-muted", [147, 151, 159]),
|
||||
size: 1.55,
|
||||
sizeAttenuation: false,
|
||||
transparent: true,
|
||||
opacity: 0.58,
|
||||
depthWrite: false,
|
||||
}),
|
||||
);
|
||||
localSurfacePoints.visible = false;
|
||||
localSurfacePoints.frustumCulled = false;
|
||||
currentIncrementPoints.visible = false;
|
||||
currentIncrementPoints.frustumCulled = false;
|
||||
scene.add(
|
||||
staticContent,
|
||||
localSurfacePoints,
|
||||
currentIncrementPoints,
|
||||
dynamicContent,
|
||||
classifiedContent,
|
||||
);
|
||||
sceneRef.current = scene;
|
||||
cameraRef.current = camera;
|
||||
controlsRef.current = controls;
|
||||
staticContentRef.current = staticContent;
|
||||
dynamicContentRef.current = dynamicContent;
|
||||
classifiedContentRef.current = classifiedContent;
|
||||
localSurfacePointsRef.current = localSurfacePoints;
|
||||
currentIncrementPointsRef.current = currentIncrementPoints;
|
||||
|
||||
let animationFrame: number | null = null;
|
||||
let lastStatsAt = Number.NEGATIVE_INFINITY;
|
||||
const render = () => {
|
||||
animationFrame = null;
|
||||
// OrbitControls emits another change while damping is still settling, so
|
||||
// this remains smooth during interaction without rendering forever while
|
||||
// the evidence scene is idle.
|
||||
controls.update();
|
||||
const startedAt = performance.now();
|
||||
renderer.render(scene, camera);
|
||||
const completedAt = performance.now();
|
||||
if (completedAt - lastStatsAt >= 1_000) {
|
||||
lastStatsAt = completedAt;
|
||||
setRenderStats({
|
||||
frameMs: completedAt - startedAt,
|
||||
drawCalls: renderer.info.render.calls,
|
||||
triangles: renderer.info.render.triangles,
|
||||
pixelRatio: renderer.getPixelRatio(),
|
||||
});
|
||||
}
|
||||
};
|
||||
const requestRender = () => {
|
||||
if (animationFrame !== null) return;
|
||||
animationFrame = window.requestAnimationFrame(render);
|
||||
};
|
||||
requestRenderRef.current = requestRender;
|
||||
controls.addEventListener("change", requestRender);
|
||||
|
||||
const resize = () => {
|
||||
const width = Math.max(host.clientWidth, 1);
|
||||
@@ -244,21 +424,17 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
camera.aspect = width / height;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(width, height, false);
|
||||
requestRender();
|
||||
};
|
||||
const observer = new ResizeObserver(resize);
|
||||
observer.observe(host);
|
||||
resize();
|
||||
|
||||
let animationFrame = 0;
|
||||
const render = () => {
|
||||
animationFrame = window.requestAnimationFrame(render);
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
render();
|
||||
requestRender();
|
||||
return () => {
|
||||
window.cancelAnimationFrame(animationFrame);
|
||||
if (animationFrame !== null) window.cancelAnimationFrame(animationFrame);
|
||||
observer.disconnect();
|
||||
controls.removeEventListener("change", requestRender);
|
||||
controls.dispose();
|
||||
scene.traverse(disposeRenderable);
|
||||
renderer.dispose();
|
||||
@@ -268,6 +444,11 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
controlsRef.current = null;
|
||||
staticContentRef.current = null;
|
||||
dynamicContentRef.current = null;
|
||||
classifiedContentRef.current = null;
|
||||
localSurfacePointsRef.current = null;
|
||||
currentIncrementPointsRef.current = null;
|
||||
requestRenderRef.current = () => undefined;
|
||||
classifiedMeshesRef.current = new Map();
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -276,82 +457,85 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
if (canvas) canvas.setAttribute("aria-label", label);
|
||||
}, [label]);
|
||||
|
||||
useEffect(() => {
|
||||
const points = localSurfacePointsRef.current;
|
||||
if (!points) return;
|
||||
points.visible = showLocalSurface && localSurfaceBodyXyzM.length > 0;
|
||||
if (points.visible) updatePointPositions(points.geometry, localSurfaceBodyXyzM);
|
||||
requestRenderRef.current();
|
||||
}, [localSurfaceBodyXyzM, showLocalSurface]);
|
||||
|
||||
useEffect(() => {
|
||||
const host = hostRef.current;
|
||||
const points = currentIncrementPointsRef.current;
|
||||
if (!host || !points) return;
|
||||
points.visible = showCurrentIncrement && pointCloudBodyXyzM.length > 0;
|
||||
if (!points.visible) {
|
||||
requestRenderRef.current();
|
||||
return;
|
||||
}
|
||||
updatePointPositions(points.geometry, pointCloudBodyXyzM);
|
||||
const material = points.material as THREE.PointsMaterial;
|
||||
const hasAlignedSemanticClasses =
|
||||
pointSemanticClassIds !== undefined
|
||||
&& pointSemanticClassIds.length === pointCloudBodyXyzM.length
|
||||
&& semanticClasses !== undefined
|
||||
&& semanticPalette !== undefined;
|
||||
if (!hasAlignedSemanticClasses) {
|
||||
if (material.vertexColors) {
|
||||
material.vertexColors = false;
|
||||
material.needsUpdate = true;
|
||||
}
|
||||
material.color.copy(tokenColor(host, "--nodedc-text-muted", [147, 151, 159]));
|
||||
requestRenderRef.current();
|
||||
return;
|
||||
}
|
||||
const declaredIds = new Set(semanticClasses.map((item) => item.id));
|
||||
const colorsByClassId = new Map<number, readonly [number, number, number]>();
|
||||
for (const entry of semanticPalette) {
|
||||
if (!declaredIds.has(entry.classId)) continue;
|
||||
const rgb = resolveRecordedEvidenceSemanticRgb(host, entry.color);
|
||||
if (rgb) colorsByClassId.set(entry.classId, rgb);
|
||||
}
|
||||
const context = tokenColor(host, "--nodedc-text-muted", [147, 151, 159]);
|
||||
const colorAttribute = ensurePointColors(points.geometry, pointCloudBodyXyzM.length);
|
||||
const pointColors = colorAttribute.array as Float32Array;
|
||||
pointSemanticClassIds.forEach((classId, index) => {
|
||||
const rgb = classId === null ? undefined : colorsByClassId.get(classId);
|
||||
const offset = index * 3;
|
||||
pointColors[offset] = rgb ? rgb[0] / 255 : context.r;
|
||||
pointColors[offset + 1] = rgb ? rgb[1] / 255 : context.g;
|
||||
pointColors[offset + 2] = rgb ? rgb[2] / 255 : context.b;
|
||||
});
|
||||
colorAttribute.needsUpdate = true;
|
||||
if (!material.vertexColors) {
|
||||
material.vertexColors = true;
|
||||
material.needsUpdate = true;
|
||||
}
|
||||
material.color.setRGB(1, 1, 1);
|
||||
requestRenderRef.current();
|
||||
}, [
|
||||
pointCloudBodyXyzM,
|
||||
pointSemanticClassIds,
|
||||
semanticClasses,
|
||||
semanticPalette,
|
||||
showCurrentIncrement,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const host = hostRef.current;
|
||||
const content = dynamicContentRef.current;
|
||||
if (!host || !content) return;
|
||||
clearGroup(content);
|
||||
|
||||
if (showLocalSurface) {
|
||||
const localSurfaceGeometry = new THREE.BufferGeometry();
|
||||
localSurfaceGeometry.setAttribute(
|
||||
"position",
|
||||
new THREE.BufferAttribute(positions(localSurfaceBodyXyzM), 3),
|
||||
);
|
||||
content.add(new THREE.Points(
|
||||
localSurfaceGeometry,
|
||||
new THREE.PointsMaterial({
|
||||
color: tokenColor(host, "--nodedc-accent-rgb", [247, 248, 244]),
|
||||
size: 1.3,
|
||||
sizeAttenuation: false,
|
||||
transparent: true,
|
||||
opacity: 0.42,
|
||||
depthWrite: false,
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
if (showCurrentIncrement) {
|
||||
const contextGeometry = new THREE.BufferGeometry();
|
||||
contextGeometry.setAttribute(
|
||||
"position",
|
||||
new THREE.BufferAttribute(positions(pointCloudBodyXyzM), 3),
|
||||
);
|
||||
const hasAlignedSemanticClasses =
|
||||
pointSemanticClassIds !== undefined
|
||||
&& pointSemanticClassIds.length === pointCloudBodyXyzM.length
|
||||
&& semanticClasses !== undefined
|
||||
&& semanticPalette !== undefined;
|
||||
if (hasAlignedSemanticClasses) {
|
||||
const declaredIds = new Set(semanticClasses.map((item) => item.id));
|
||||
const colorsByClassId = new Map<number, readonly [number, number, number]>();
|
||||
for (const entry of semanticPalette) {
|
||||
if (!declaredIds.has(entry.classId)) continue;
|
||||
const rgb = resolveRecordedEvidenceSemanticRgb(host, entry.color);
|
||||
if (rgb) colorsByClassId.set(entry.classId, rgb);
|
||||
}
|
||||
const context = tokenColor(host, "--nodedc-text-muted", [147, 151, 159]);
|
||||
const pointColors = new Float32Array(pointCloudBodyXyzM.length * 3);
|
||||
pointSemanticClassIds.forEach((classId, index) => {
|
||||
const rgb = classId === null ? undefined : colorsByClassId.get(classId);
|
||||
const offset = index * 3;
|
||||
pointColors[offset] = rgb ? rgb[0] / 255 : context.r;
|
||||
pointColors[offset + 1] = rgb ? rgb[1] / 255 : context.g;
|
||||
pointColors[offset + 2] = rgb ? rgb[2] / 255 : context.b;
|
||||
});
|
||||
contextGeometry.setAttribute(
|
||||
"color",
|
||||
new THREE.BufferAttribute(pointColors, 3),
|
||||
);
|
||||
}
|
||||
content.add(new THREE.Points(
|
||||
contextGeometry,
|
||||
new THREE.PointsMaterial({
|
||||
color: hasAlignedSemanticClasses
|
||||
? new THREE.Color(1, 1, 1)
|
||||
: tokenColor(host, "--nodedc-text-muted", [147, 151, 159]),
|
||||
vertexColors: hasAlignedSemanticClasses,
|
||||
size: 1.55,
|
||||
sizeAttenuation: false,
|
||||
transparent: true,
|
||||
opacity: 0.58,
|
||||
depthWrite: false,
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
for (const obstacle of obstacles) {
|
||||
if (
|
||||
(
|
||||
!showLowStep
|
||||
&& obstacle.occupancySource !== undefined
|
||||
&& obstacle.occupancySource !== "baseline"
|
||||
)
|
||||
||
|
||||
(obstacle.state === "current" && !showCurrentIncrement)
|
||||
|| (obstacle.state === "retained" && !showRollingMap)
|
||||
|| obstacle.state === "held"
|
||||
@@ -359,7 +543,7 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const color = decisionColor(host, obstacle.decision);
|
||||
const color = obstacleColor(host, obstacle);
|
||||
if (obstacle.state === "retained") {
|
||||
const geometry = new THREE.BoxGeometry(
|
||||
occupiedVoxelSizeM * 0.82,
|
||||
@@ -412,20 +596,150 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
content.add(centroid);
|
||||
}
|
||||
}
|
||||
|
||||
requestRenderRef.current();
|
||||
}, [
|
||||
obstacles,
|
||||
occupiedVoxelSizeM,
|
||||
localSurfaceBodyXyzM,
|
||||
pointCloudBodyXyzM,
|
||||
pointSemanticClassIds,
|
||||
semanticClasses,
|
||||
semanticPalette,
|
||||
showCurrentIncrement,
|
||||
showLocalSurface,
|
||||
showRollingMap,
|
||||
showLowStep,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const host = hostRef.current;
|
||||
const content = classifiedContentRef.current;
|
||||
if (!host || !content) return;
|
||||
const packedCellCount = classifiedPackedCells?.stateCodes.length ?? 0;
|
||||
const packedCellsValid = !classifiedPackedCells || (
|
||||
classifiedPackedCells.centersBodyXyM.length === packedCellCount * 2
|
||||
&& classifiedPackedCells.zBoundsM.length === packedCellCount * 2
|
||||
);
|
||||
const cellCount = packedCellsValid && classifiedPackedCells
|
||||
? packedCellCount
|
||||
: classifiedCells.length;
|
||||
content.visible = showClassifiedCells && cellCount > 0;
|
||||
if (!content.visible) {
|
||||
requestRenderRef.current();
|
||||
return;
|
||||
}
|
||||
|
||||
const requiredCapacity = cellCount;
|
||||
const currentMeshes = classifiedMeshesRef.current;
|
||||
const firstMesh = currentMeshes.values().next().value as THREE.InstancedMesh | undefined;
|
||||
const needsAllocation = !firstMesh
|
||||
|| Number(firstMesh.userData.capacity ?? 0) < requiredCapacity
|
||||
|| Number(firstMesh.userData.cellSizeM ?? 0) !== classifiedCellSizeM;
|
||||
if (needsAllocation) {
|
||||
clearGroup(content);
|
||||
const meshes = new Map<LaboratoryMetricCellState, THREE.InstancedMesh>();
|
||||
const states: readonly LaboratoryMetricCellState[] = [
|
||||
"unobserved",
|
||||
"ground-support",
|
||||
"nonground-occupied",
|
||||
"unknown-rejected",
|
||||
];
|
||||
for (const state of states) {
|
||||
const color = state === "ground-support"
|
||||
? tokenColor(host, "--nodedc-success-rgb", [181, 255, 90])
|
||||
: state === "nonground-occupied"
|
||||
? tokenColor(host, "--nodedc-danger-rgb", [255, 104, 112])
|
||||
: state === "unknown-rejected"
|
||||
? tokenColor(host, "--nodedc-warning-rgb", [255, 197, 92])
|
||||
: tokenColor(host, "--nodedc-text-muted", [96, 99, 106]);
|
||||
const mesh = new THREE.InstancedMesh(
|
||||
new THREE.BoxGeometry(classifiedCellSizeM * 0.92, 1, classifiedCellSizeM * 0.92),
|
||||
new THREE.MeshBasicMaterial({
|
||||
color,
|
||||
transparent: true,
|
||||
opacity: state === "unobserved" ? 0.035 : state === "ground-support" ? 0.12 : 0.24,
|
||||
depthWrite: false,
|
||||
}),
|
||||
requiredCapacity,
|
||||
);
|
||||
mesh.count = 0;
|
||||
mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
||||
mesh.frustumCulled = false;
|
||||
mesh.userData.capacity = requiredCapacity;
|
||||
mesh.userData.cellSizeM = classifiedCellSizeM;
|
||||
meshes.set(state, mesh);
|
||||
content.add(mesh);
|
||||
}
|
||||
classifiedMeshesRef.current = meshes;
|
||||
}
|
||||
|
||||
const meshes = classifiedMeshesRef.current;
|
||||
const counts = new Map<LaboratoryMetricCellState, number>();
|
||||
const matrix = new THREE.Matrix4();
|
||||
const position = new THREE.Vector3();
|
||||
const scale = new THREE.Vector3(1, 1, 1);
|
||||
const rotation = new THREE.Quaternion();
|
||||
const setCell = (
|
||||
state: LaboratoryMetricCellState,
|
||||
centerX: number,
|
||||
centerY: number,
|
||||
minimum: number | null,
|
||||
maximum: number | null,
|
||||
) => {
|
||||
const mesh = meshes.get(state);
|
||||
if (!mesh) return;
|
||||
const index = counts.get(state) ?? 0;
|
||||
const height = minimum === null || maximum === null
|
||||
? 0.018
|
||||
: Math.max(0.018, maximum - minimum);
|
||||
const centerZ = minimum === null || maximum === null
|
||||
? -0.012
|
||||
: (minimum + maximum) / 2;
|
||||
const [sceneX, sceneY, sceneZ] = scenePoint([
|
||||
centerX,
|
||||
centerY,
|
||||
centerZ,
|
||||
]);
|
||||
position.set(sceneX, sceneY, sceneZ);
|
||||
scale.set(1, height, 1);
|
||||
matrix.compose(position, rotation, scale);
|
||||
mesh.setMatrixAt(index, matrix);
|
||||
counts.set(state, index + 1);
|
||||
};
|
||||
if (packedCellsValid && classifiedPackedCells) {
|
||||
for (let cellIndex = 0; cellIndex < packedCellCount; cellIndex += 1) {
|
||||
const code = classifiedPackedCells.stateCodes[cellIndex];
|
||||
const state: LaboratoryMetricCellState = code === 1
|
||||
? "ground-support"
|
||||
: code === 2
|
||||
? "nonground-occupied"
|
||||
: code === 3
|
||||
? "unknown-rejected"
|
||||
: code === 0
|
||||
? "unobserved"
|
||||
: "unknown-rejected";
|
||||
const minimum = classifiedPackedCells.zBoundsM[cellIndex * 2]!;
|
||||
const maximum = classifiedPackedCells.zBoundsM[cellIndex * 2 + 1]!;
|
||||
setCell(
|
||||
state,
|
||||
classifiedPackedCells.centersBodyXyM[cellIndex * 2]!,
|
||||
classifiedPackedCells.centersBodyXyM[cellIndex * 2 + 1]!,
|
||||
Number.isFinite(minimum) ? minimum : null,
|
||||
Number.isFinite(maximum) ? maximum : null,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (const cell of classifiedCells) {
|
||||
setCell(
|
||||
cell.state,
|
||||
cell.centerBodyXyM[0],
|
||||
cell.centerBodyXyM[1],
|
||||
cell.zBoundsM[0],
|
||||
cell.zBoundsM[1],
|
||||
);
|
||||
}
|
||||
}
|
||||
for (const [state, mesh] of meshes) {
|
||||
mesh.count = counts.get(state) ?? 0;
|
||||
mesh.instanceMatrix.needsUpdate = true;
|
||||
}
|
||||
requestRenderRef.current();
|
||||
}, [classifiedCellSizeM, classifiedCells, classifiedPackedCells, showClassifiedCells]);
|
||||
|
||||
useEffect(() => {
|
||||
const host = hostRef.current;
|
||||
const content = staticContentRef.current;
|
||||
@@ -490,15 +804,24 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
material.depthWrite = false;
|
||||
});
|
||||
content.add(grid);
|
||||
}, [corridor, rig]);
|
||||
requestRenderRef.current();
|
||||
}, [
|
||||
corridor.forwardLengthM,
|
||||
corridor.halfWidthM,
|
||||
corridor.rearMarginM,
|
||||
rig.lengthM,
|
||||
rig.nominalSensorHeightM,
|
||||
rig.widthM,
|
||||
]);
|
||||
|
||||
const resetView = () => {
|
||||
const resetView = useCallback(() => {
|
||||
const camera = cameraRef.current;
|
||||
const controls = controlsRef.current;
|
||||
if (!camera || !controls) return;
|
||||
controls.target.set(corridor.forwardLengthM * 0.35, 0.6, 0);
|
||||
if (mode === "plan") {
|
||||
camera.position.set(corridor.forwardLengthM * 0.35, 15, 0.001);
|
||||
const forwardLengthM = corridorForwardLengthRef.current;
|
||||
controls.target.set(forwardLengthM * 0.35, 0.6, 0);
|
||||
if (modeRef.current === "plan") {
|
||||
camera.position.set(forwardLengthM * 0.35, 15, 0.001);
|
||||
camera.up.set(0, 0, -1);
|
||||
} else {
|
||||
camera.position.set(-4.5, 4.8, 8.5);
|
||||
@@ -506,10 +829,13 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
}
|
||||
camera.updateProjectionMatrix();
|
||||
controls.update();
|
||||
};
|
||||
requestRenderRef.current();
|
||||
}, []);
|
||||
|
||||
useEffect(resetView, [corridor.forwardLengthM, mode]);
|
||||
useImperativeHandle(ref, () => ({ resetView }));
|
||||
// Playback data and rig object identities must never reset an operator's
|
||||
// orbit. Only a deliberate 3D/PLAN mode transition chooses a default view.
|
||||
useEffect(() => resetView(), [mode, resetView]);
|
||||
useImperativeHandle(ref, () => ({ resetView }), [resetView]);
|
||||
|
||||
const semanticLegendEntries = (() => {
|
||||
if (
|
||||
@@ -532,13 +858,53 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
});
|
||||
})();
|
||||
const metricLegendEntries = laboratoryMetricLegendEntries({
|
||||
pointCloudCount: pointCloudBodyXyzM.length,
|
||||
pointCloudCount: pointSemanticClassIds?.every((item) => item !== null)
|
||||
? 0
|
||||
: pointCloudBodyXyzM.length,
|
||||
localSurfaceCount: localSurfaceBodyXyzM.length,
|
||||
obstacles,
|
||||
showCurrentIncrement,
|
||||
showLocalSurface,
|
||||
showRollingMap,
|
||||
showLowStep,
|
||||
});
|
||||
const classifiedLegendEntries = (() => {
|
||||
const states = new Set<LaboratoryMetricCellState>();
|
||||
if (classifiedPackedCells) {
|
||||
for (const code of classifiedPackedCells.stateCodes) {
|
||||
states.add(code === 1
|
||||
? "ground-support"
|
||||
: code === 2
|
||||
? "nonground-occupied"
|
||||
: code === 3
|
||||
? "unknown-rejected"
|
||||
: code === 0
|
||||
? "unobserved"
|
||||
: "unknown-rejected");
|
||||
}
|
||||
} else {
|
||||
classifiedCells.forEach((cell) => states.add(cell.state));
|
||||
}
|
||||
if (!showClassifiedCells || !states.size) return [];
|
||||
return [
|
||||
states.has("ground-support")
|
||||
? { id: "ground-support" as const, label: "Ground support" }
|
||||
: null,
|
||||
states.has("nonground-occupied")
|
||||
? { id: "nonground-occupied" as const, label: "Non-ground occupied" }
|
||||
: null,
|
||||
states.has("unknown-rejected")
|
||||
? { id: "unknown-rejected" as const, label: "Unknown / rejected" }
|
||||
: null,
|
||||
states.has("unobserved")
|
||||
? { id: "unobserved" as const, label: "Unobserved" }
|
||||
: null,
|
||||
]
|
||||
.filter((entry): entry is NonNullable<typeof entry> => entry !== null)
|
||||
.filter((entry) => !semanticLegendEntries.some(
|
||||
(semanticEntry) => semanticEntry.label === entry.label,
|
||||
));
|
||||
})();
|
||||
|
||||
return (
|
||||
<div className="laboratory-metric-evidence-scene">
|
||||
@@ -546,9 +912,22 @@ LaboratoryMetricEvidenceSceneHandle,
|
||||
{renderError ? <p>{renderError}</p> : null}
|
||||
</div>
|
||||
<div className="laboratory-metric-evidence-scene__legend">
|
||||
{renderStats ? (
|
||||
<span
|
||||
data-decision="performance"
|
||||
title="CPU-время отправки последнего WebGL render pass; это не GPU timer. В покое сцена не перерисовывается."
|
||||
>
|
||||
3D {renderStats.frameMs.toFixed(1)} ms · {renderStats.drawCalls} draw · {renderStats.triangles.toLocaleString("ru-RU")} tri · {(
|
||||
classifiedPackedCells?.stateCodes.length ?? classifiedCells.length
|
||||
).toLocaleString("ru-RU")} cells · {renderStats.pixelRatio.toFixed(1)}×
|
||||
</span>
|
||||
) : null}
|
||||
{metricLegendEntries.map((entry) => (
|
||||
<span key={entry.id} data-decision={entry.id}>{entry.label}</span>
|
||||
))}
|
||||
{classifiedLegendEntries.map((entry) => (
|
||||
<span key={entry.id} data-decision={entry.id}>{entry.label}</span>
|
||||
))}
|
||||
{semanticLegendEntries.map((entry) => (
|
||||
<span
|
||||
key={entry.id}
|
||||
|
||||
+8
-3
@@ -510,16 +510,21 @@ export function RecordedEvidenceSemanticMaskOverlay({
|
||||
}) {
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const rendererRef = useRef<SemanticMaskRenderer | null | undefined>(undefined);
|
||||
const lastReadyMaskRef = useRef<{ series: string; mask: DecodedSemanticMask } | null>(null);
|
||||
const [rendererMode, setRendererMode] = useState<"webgl" | "2d">("webgl");
|
||||
const [mask, setMask] = useState<DecodedSemanticMask | null>(null);
|
||||
const [failure, setFailure] = useState<string | null>(null);
|
||||
const expectedKey = semanticMaskKey(src, imageWidth, imageHeight);
|
||||
const prefetchSignature = prefetchSrcs.join("\n");
|
||||
const renderMask = failure
|
||||
const series = src.slice(0, Math.max(src.lastIndexOf("/"), 0));
|
||||
if (lastReadyMaskRef.current?.series !== series) lastReadyMaskRef.current = null;
|
||||
const exactMask = failure
|
||||
? null
|
||||
: mask?.key === expectedKey
|
||||
? mask
|
||||
: decodedMaskCache.get(expectedKey) ?? null;
|
||||
if (exactMask) lastReadyMaskRef.current = { series, mask: exactMask };
|
||||
const renderMask = exactMask ?? lastReadyMaskRef.current?.mask ?? null;
|
||||
|
||||
useEffect(() => {
|
||||
setFailure(null);
|
||||
@@ -627,8 +632,8 @@ export function RecordedEvidenceSemanticMaskOverlay({
|
||||
className="recorded-evidence-semantic-mask-overlay"
|
||||
role="img"
|
||||
aria-label={ariaLabel}
|
||||
aria-busy={!failure && !renderMask}
|
||||
data-state={failure ? "error" : renderMask ? "ready" : "loading"}
|
||||
aria-busy={!failure && !exactMask}
|
||||
data-state={failure ? "error" : exactMask ? "ready" : renderMask ? "stale" : "loading"}
|
||||
data-renderer={rendererMode}
|
||||
style={{ zIndex: 1 }}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,625 @@
|
||||
import {
|
||||
Application,
|
||||
Asset,
|
||||
BLEND_NONE,
|
||||
BLEND_NORMAL,
|
||||
Color,
|
||||
CULLFACE_NONE,
|
||||
Entity,
|
||||
FILLMODE_NONE,
|
||||
Mat4,
|
||||
Quat,
|
||||
RESOLUTION_AUTO,
|
||||
StandardMaterial,
|
||||
Vec2,
|
||||
Vec3,
|
||||
WasmModule,
|
||||
type ContainerResource,
|
||||
type ModelComponent,
|
||||
type ScriptType,
|
||||
} from "playcanvas";
|
||||
import { CameraControls } from "playcanvas/scripts/esm/camera-controls.mjs";
|
||||
|
||||
import {
|
||||
prepareSimulationPhysics,
|
||||
SimulationUgvController,
|
||||
type AmmoApi,
|
||||
} from "./SimulationUgvController";
|
||||
|
||||
import type {
|
||||
SimulationEulerRotation,
|
||||
SimulationUgvPreset,
|
||||
SimulationViewerQuality,
|
||||
SimulationWorldManifest,
|
||||
} from "../../core/simulation/projects";
|
||||
|
||||
export type SimulationViewMode = "visual" | "collision" | "combined";
|
||||
export type SimulationQuality = SimulationViewerQuality;
|
||||
export type SimulationLayer = "visual" | "collision";
|
||||
export type SimulationCameraAxis = "horizontal" | "vertical";
|
||||
export type SimulationControlMode = "free" | "ugv";
|
||||
|
||||
export function playCanvasEulerTransform(rotation: SimulationEulerRotation): number[] {
|
||||
return Array.from(new Mat4().setFromEulerAngles(rotation.x, rotation.y, rotation.z).data);
|
||||
}
|
||||
|
||||
export interface SimulationRuntime {
|
||||
mount(canvas: HTMLCanvasElement): Promise<void>;
|
||||
loadWorld(manifest: SimulationWorldManifest): Promise<void>;
|
||||
setViewMode(mode: SimulationViewMode): Promise<void>;
|
||||
setControlMode(mode: SimulationControlMode): Promise<void>;
|
||||
setUgvPreset(preset: SimulationUgvPreset): void;
|
||||
setQuality(quality: SimulationQuality): void;
|
||||
setLayerWorldTransform(layer: SimulationLayer, transform: number[]): void;
|
||||
setCameraInversion(axis: SimulationCameraAxis, inverted: boolean): void;
|
||||
home(): void;
|
||||
focusBounds(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
type DesktopCameraInput = {
|
||||
read(): { mouse: number[] } & Record<string, number[]>;
|
||||
};
|
||||
|
||||
type CameraController = ScriptType & Pick<CameraControls, "reset" | "focus"> & {
|
||||
_desktopInput?: DesktopCameraInput;
|
||||
_state?: {
|
||||
axis: Vec3;
|
||||
shift: number;
|
||||
ctrl: number;
|
||||
mouse: number[];
|
||||
touches: number;
|
||||
};
|
||||
};
|
||||
|
||||
const HOME_POSITION = new Vec3(0, 1, 0);
|
||||
const HOME_FOCUS = new Vec3(1, 1, 0);
|
||||
const DRACO_DECODER_ROOT = "/vendor/playcanvas/draco/1.5.7";
|
||||
|
||||
const QUALITY_PROFILES: Record<SimulationQuality, {
|
||||
lodBaseDistance: number;
|
||||
lodMultiplier: number;
|
||||
lodRangeMin: number;
|
||||
lodRangeMax: number;
|
||||
pixelRatio: number;
|
||||
splatBudget: number;
|
||||
targetFps: number;
|
||||
}> = {
|
||||
low: { lodBaseDistance: 5, lodMultiplier: 2, lodRangeMin: 3, lodRangeMax: 5, pixelRatio: 0.75, splatBudget: 350_000, targetFps: 30 },
|
||||
medium: { lodBaseDistance: 5, lodMultiplier: 2, lodRangeMin: 2, lodRangeMax: 5, pixelRatio: 1, splatBudget: 700_000, targetFps: 45 },
|
||||
high: { lodBaseDistance: 5, lodMultiplier: 3, lodRangeMin: 1, lodRangeMax: 5, pixelRatio: 1.25, splatBudget: 1_200_000, targetFps: 60 },
|
||||
ultra: { lodBaseDistance: 7, lodMultiplier: 3, lodRangeMin: 0, lodRangeMax: 5, pixelRatio: 1.5, splatBudget: 2_500_000, targetFps: 60 },
|
||||
maximum: { lodBaseDistance: 7, lodMultiplier: 3, lodRangeMin: 0, lodRangeMax: 5, pixelRatio: 2, splatBudget: 4_000_000, targetFps: 60 },
|
||||
};
|
||||
|
||||
export class PlayCanvasRuntime implements SimulationRuntime {
|
||||
private app: Application | null = null;
|
||||
private canvas: HTMLCanvasElement | null = null;
|
||||
private camera: Entity | null = null;
|
||||
private cameraController: CameraController | null = null;
|
||||
private visualEntity: Entity | null = null;
|
||||
private visualAsset: Asset | null = null;
|
||||
private collisionEntity: Entity | null = null;
|
||||
private collisionVisuals: ModelComponent[] = [];
|
||||
private collisionAsset: Asset | null = null;
|
||||
private collisionMaterial: StandardMaterial | null = null;
|
||||
private collisionSource: { meshUrl: string; projectId: string; worldTransform: number[] } | null = null;
|
||||
private collisionLoadPromise: Promise<void> | null = null;
|
||||
private resizeObserver: ResizeObserver | null = null;
|
||||
private viewMode: SimulationViewMode = "visual";
|
||||
private quality: SimulationQuality = "high";
|
||||
private cameraInversion = { horizontal: true, vertical: false };
|
||||
private controlMode: SimulationControlMode = "free";
|
||||
private controlRequestVersion = 0;
|
||||
private ugvController: SimulationUgvController | null = null;
|
||||
private readonly lastCameraPosition = new Vec3();
|
||||
private readonly lastCameraRotation = new Quat();
|
||||
private cameraSnapshotReady = false;
|
||||
private renderIntervalMs = 1000 / 60;
|
||||
private renderAccumulatorMs = 0;
|
||||
private disposed = false;
|
||||
private updateFrame = (deltaSeconds: number): void => {
|
||||
if (!this.app || !this.camera || this.disposed) return;
|
||||
this.ugvController?.update(deltaSeconds);
|
||||
const position = this.camera.getPosition();
|
||||
const rotation = this.camera.getRotation();
|
||||
const cameraChanged = !this.cameraSnapshotReady
|
||||
|| !position.equals(this.lastCameraPosition)
|
||||
|| !rotation.equals(this.lastCameraRotation);
|
||||
if (!cameraChanged && this.controlMode === "free") return;
|
||||
this.lastCameraPosition.copy(position);
|
||||
this.lastCameraRotation.copy(rotation);
|
||||
this.cameraSnapshotReady = true;
|
||||
this.renderAccumulatorMs += deltaSeconds * 1000;
|
||||
if (this.renderAccumulatorMs < this.renderIntervalMs) return;
|
||||
this.renderAccumulatorMs %= this.renderIntervalMs;
|
||||
this.app.renderNextFrame = true;
|
||||
};
|
||||
|
||||
async mount(canvas: HTMLCanvasElement): Promise<void> {
|
||||
if (this.app) throw new Error("Runtime сцены уже запущен.");
|
||||
this.disposed = false;
|
||||
this.renderAccumulatorMs = 0;
|
||||
this.canvas = canvas;
|
||||
configureDracoDecoder();
|
||||
const ammo: AmmoApi = await prepareSimulationPhysics();
|
||||
if (this.disposed) return;
|
||||
canvas.tabIndex = 0;
|
||||
canvas.addEventListener("contextmenu", preventContextMenu);
|
||||
canvas.addEventListener("pointerdown", focusCanvas, true);
|
||||
const app = new Application(canvas, {
|
||||
graphicsDeviceOptions: {
|
||||
antialias: true,
|
||||
alpha: false,
|
||||
preserveDrawingBuffer: false,
|
||||
powerPreference: "high-performance",
|
||||
},
|
||||
});
|
||||
this.app = app;
|
||||
app.autoRender = false;
|
||||
app.on("update", this.updateFrame);
|
||||
app.setCanvasFillMode(FILLMODE_NONE, 1, 1);
|
||||
app.setCanvasResolution(RESOLUTION_AUTO);
|
||||
app.scene.ambientLight = new Color(0.35, 0.37, 0.42);
|
||||
|
||||
const camera = new Entity("SimulationCamera");
|
||||
camera.addComponent("camera", {
|
||||
clearColor: new Color(0.025, 0.03, 0.04),
|
||||
nearClip: 0.02,
|
||||
farClip: 20_000,
|
||||
fov: 58,
|
||||
});
|
||||
camera.setPosition(HOME_POSITION);
|
||||
camera.lookAt(HOME_FOCUS);
|
||||
camera.addComponent("script");
|
||||
const controller = camera.script?.create(CameraControls, {
|
||||
properties: {
|
||||
enableOrbit: true,
|
||||
enableFly: true,
|
||||
focusPoint: new Vec3(0, 0, 0),
|
||||
zoomRange: new Vec2(0.05, 20_000),
|
||||
},
|
||||
}) as CameraController | null;
|
||||
if (controller) configureCameraDrag(controller, () => this.cameraInversion);
|
||||
app.root.addChild(camera);
|
||||
this.camera = camera;
|
||||
this.cameraController = controller;
|
||||
this.ugvController = new SimulationUgvController(app, canvas, camera, ammo);
|
||||
|
||||
const light = new Entity("SimulationSun");
|
||||
light.addComponent("light", {
|
||||
type: "directional",
|
||||
color: new Color(1, 0.97, 0.9),
|
||||
intensity: 1.1,
|
||||
castShadows: false,
|
||||
});
|
||||
light.setEulerAngles(42, 28, 0);
|
||||
app.root.addChild(light);
|
||||
|
||||
this.resizeObserver = new ResizeObserver(() => this.resize());
|
||||
this.resizeObserver.observe(canvas.parentElement ?? canvas);
|
||||
this.resize();
|
||||
app.start();
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
async loadWorld(manifest: SimulationWorldManifest): Promise<void> {
|
||||
const app = this.requiredApp();
|
||||
this.unloadWorld();
|
||||
const sourceUrl = manifest.visual.streamedSogUrl ?? manifest.visual.previewSogUrl;
|
||||
if (!sourceUrl) throw new Error("Манифест локации не содержит визуальный слой.");
|
||||
const asset = new Asset(`SimulationWorld:${manifest.projectId}`, "gsplat", { url: sourceUrl });
|
||||
app.assets.add(asset);
|
||||
this.visualAsset = asset;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const ready = (loaded: Asset) => {
|
||||
if (this.disposed || !this.app) {
|
||||
loaded.unload();
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const visual = new Entity("GaussianWorld");
|
||||
visual.enabled = false;
|
||||
applyWorldTransform(visual, manifest.transforms.worldFromVisual);
|
||||
app.root.addChild(visual);
|
||||
visual.addComponent("gsplat", {
|
||||
asset: loaded,
|
||||
unified: true,
|
||||
});
|
||||
visual.enabled = true;
|
||||
this.visualEntity = visual;
|
||||
this.applyQuality();
|
||||
this.applyViewMode();
|
||||
this.requestRender();
|
||||
resolve();
|
||||
};
|
||||
const failed = (_error: unknown) => {
|
||||
reject(new Error("Визуальный слой не загрузился."));
|
||||
};
|
||||
asset.ready(ready);
|
||||
asset.once("error", failed);
|
||||
app.assets.load(asset);
|
||||
});
|
||||
if (manifest.collision.available && manifest.collision.meshUrl) {
|
||||
this.collisionSource = {
|
||||
meshUrl: manifest.collision.meshUrl,
|
||||
projectId: manifest.projectId,
|
||||
worldTransform: manifest.transforms.worldFromCollision,
|
||||
};
|
||||
}
|
||||
this.applyViewMode();
|
||||
this.home();
|
||||
}
|
||||
|
||||
async setViewMode(mode: SimulationViewMode): Promise<void> {
|
||||
this.viewMode = mode;
|
||||
this.applyViewMode();
|
||||
try {
|
||||
if (mode !== "visual" && !this.collisionEntity) {
|
||||
await this.ensureCollision();
|
||||
this.applyViewMode();
|
||||
}
|
||||
} finally {
|
||||
this.requestRender();
|
||||
this.canvas?.focus({ preventScroll: true });
|
||||
}
|
||||
}
|
||||
|
||||
async setControlMode(mode: SimulationControlMode): Promise<void> {
|
||||
const requestVersion = ++this.controlRequestVersion;
|
||||
const controller = this.ugvController;
|
||||
if (!controller) throw new Error("Управление UGV ещё не готово.");
|
||||
|
||||
if (mode === "free") {
|
||||
controller.disable();
|
||||
this.controlMode = "free";
|
||||
if (this.cameraController) this.cameraController.enabled = true;
|
||||
this.home();
|
||||
return;
|
||||
}
|
||||
if (this.controlMode === "ugv" && controller.enabled) return;
|
||||
|
||||
try {
|
||||
await this.ensureCollision();
|
||||
if (requestVersion !== this.controlRequestVersion || this.disposed) return;
|
||||
const collisionWorld = this.collisionEntity;
|
||||
if (!collisionWorld) throw new Error("Физический слой UGV отсутствует.");
|
||||
if (this.cameraController) this.cameraController.enabled = false;
|
||||
await controller.enable(collisionWorld);
|
||||
if (requestVersion !== this.controlRequestVersion || this.disposed) {
|
||||
controller.disable();
|
||||
if (this.cameraController) this.cameraController.enabled = true;
|
||||
return;
|
||||
}
|
||||
this.controlMode = "ugv";
|
||||
this.cameraSnapshotReady = false;
|
||||
this.requestRender();
|
||||
} catch (error) {
|
||||
controller.disable();
|
||||
this.controlMode = "free";
|
||||
if (this.cameraController) this.cameraController.enabled = true;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
setQuality(quality: SimulationQuality): void {
|
||||
this.quality = quality;
|
||||
this.applyQuality();
|
||||
this.requestRender();
|
||||
}
|
||||
|
||||
setUgvPreset(preset: SimulationUgvPreset): void {
|
||||
this.ugvController?.configure(preset);
|
||||
this.cameraSnapshotReady = false;
|
||||
this.requestRender();
|
||||
}
|
||||
|
||||
setLayerWorldTransform(layer: SimulationLayer, transform: number[]): void {
|
||||
if (transform.length !== 16) {
|
||||
throw new Error("World transform должен содержать матрицу 4×4.");
|
||||
}
|
||||
if (layer === "visual") {
|
||||
if (this.visualEntity) applyWorldTransform(this.visualEntity, transform);
|
||||
this.requestRender();
|
||||
return;
|
||||
}
|
||||
if (this.collisionSource) this.collisionSource.worldTransform = [...transform];
|
||||
if (this.collisionEntity) applyWorldTransform(this.collisionEntity, transform);
|
||||
this.ugvController?.syncCollisionBodies();
|
||||
this.requestRender();
|
||||
}
|
||||
|
||||
setCameraInversion(axis: SimulationCameraAxis, inverted: boolean): void {
|
||||
this.cameraInversion[axis] = inverted;
|
||||
}
|
||||
|
||||
home(): void {
|
||||
if (this.controlMode === "ugv" && this.ugvController?.enabled) {
|
||||
this.ugvController.reset();
|
||||
this.cameraSnapshotReady = false;
|
||||
this.requestRender();
|
||||
return;
|
||||
}
|
||||
this.resetCameraInteraction();
|
||||
if (this.cameraController) {
|
||||
this.cameraController.reset(HOME_FOCUS, HOME_POSITION);
|
||||
} else if (this.camera) {
|
||||
this.camera.setPosition(HOME_POSITION);
|
||||
this.camera.lookAt(HOME_FOCUS);
|
||||
}
|
||||
this.requestRender();
|
||||
this.canvas?.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
focusBounds(): void {
|
||||
this.resetCameraInteraction();
|
||||
const bounds = this.visualEntity?.gsplat?.customAabb;
|
||||
const focus = bounds?.center.clone() ?? new Vec3(0, 0, 0);
|
||||
const radius = bounds?.halfExtents.length() ?? 3;
|
||||
const distance = Math.max(1, radius * 2.4);
|
||||
const position = new Vec3(1, 0.55, 1).normalize().mulScalar(distance).add(focus);
|
||||
if (this.cameraController) {
|
||||
this.cameraController.reset(focus, position);
|
||||
} else if (this.camera) {
|
||||
this.camera.setPosition(position);
|
||||
this.camera.lookAt(focus);
|
||||
}
|
||||
this.requestRender();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this.disposed) return;
|
||||
this.disposed = true;
|
||||
this.resizeObserver?.disconnect();
|
||||
this.resizeObserver = null;
|
||||
const webgl = this.canvas?.getContext("webgl2") ?? this.canvas?.getContext("webgl");
|
||||
this.unloadWorld();
|
||||
this.ugvController?.dispose();
|
||||
this.ugvController = null;
|
||||
if (this.app) {
|
||||
this.app.autoRender = false;
|
||||
this.app.renderNextFrame = false;
|
||||
this.app.off("update", this.updateFrame);
|
||||
this.app.destroy();
|
||||
}
|
||||
webgl?.getExtension("WEBGL_lose_context")?.loseContext();
|
||||
if (this.canvas) {
|
||||
this.canvas.width = 1;
|
||||
this.canvas.height = 1;
|
||||
}
|
||||
if (this.canvas) {
|
||||
this.canvas.removeEventListener("contextmenu", preventContextMenu);
|
||||
this.canvas.removeEventListener("pointerdown", focusCanvas, true);
|
||||
}
|
||||
this.app = null;
|
||||
this.canvas = null;
|
||||
this.camera = null;
|
||||
this.cameraController = null;
|
||||
this.controlMode = "free";
|
||||
this.cameraSnapshotReady = false;
|
||||
}
|
||||
|
||||
private requiredApp(): Application {
|
||||
if (!this.app) throw new Error("Runtime сцены не запущен.");
|
||||
return this.app;
|
||||
}
|
||||
|
||||
private requestRender(): void {
|
||||
if (this.app && !this.disposed) this.app.renderNextFrame = true;
|
||||
}
|
||||
|
||||
private resize(): void {
|
||||
if (!this.app || !this.canvas) return;
|
||||
const bounds = this.canvas.parentElement?.getBoundingClientRect();
|
||||
const width = Math.max(1, Math.round(bounds?.width ?? this.canvas.clientWidth));
|
||||
const height = Math.max(1, Math.round(bounds?.height ?? this.canvas.clientHeight));
|
||||
this.app.resizeCanvas(width, height);
|
||||
this.requestRender();
|
||||
}
|
||||
|
||||
private applyViewMode(): void {
|
||||
if (this.visualEntity) {
|
||||
this.visualEntity.enabled = this.viewMode !== "collision" || !this.collisionEntity;
|
||||
}
|
||||
if (this.collisionEntity) {
|
||||
// Physics bodies must stay active while their green debug geometry is hidden.
|
||||
this.collisionEntity.enabled = true;
|
||||
const visible = this.viewMode !== "visual";
|
||||
for (const model of this.collisionVisuals) model.enabled = visible;
|
||||
}
|
||||
if (this.collisionMaterial) {
|
||||
const combined = this.viewMode === "combined";
|
||||
this.collisionMaterial.opacity = combined ? 0.34 : 1;
|
||||
this.collisionMaterial.blendType = combined ? BLEND_NORMAL : BLEND_NONE;
|
||||
this.collisionMaterial.depthWrite = !combined;
|
||||
this.collisionMaterial.update();
|
||||
}
|
||||
this.requestRender();
|
||||
}
|
||||
|
||||
private resetCameraInteraction(): void {
|
||||
const controller = this.cameraController;
|
||||
if (!controller) return;
|
||||
// CameraControls owns pointer capture and its input-source lifecycle. Mutating
|
||||
// those private fields here left the source unable to claim the next drag
|
||||
// after a layer switch. The documented state event drains pending deltas.
|
||||
controller.fire("state");
|
||||
const state = controller._state;
|
||||
if (state) {
|
||||
state.axis.set(0, 0, 0);
|
||||
state.shift = 0;
|
||||
state.ctrl = 0;
|
||||
state.mouse.fill(0);
|
||||
state.touches = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private applyQuality(): void {
|
||||
const gsplat = this.visualEntity?.gsplat;
|
||||
const profile = QUALITY_PROFILES[this.quality];
|
||||
if (gsplat) {
|
||||
gsplat.lodBaseDistance = profile.lodBaseDistance;
|
||||
gsplat.lodMultiplier = profile.lodMultiplier;
|
||||
gsplat.lodRangeMin = profile.lodRangeMin;
|
||||
gsplat.lodRangeMax = profile.lodRangeMax;
|
||||
}
|
||||
if (this.app) {
|
||||
this.app.scene.gsplat.splatBudget = profile.splatBudget;
|
||||
this.renderIntervalMs = 1000 / profile.targetFps;
|
||||
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||
this.app.graphicsDevice.maxPixelRatio = Math.min(devicePixelRatio, profile.pixelRatio);
|
||||
this.resize();
|
||||
}
|
||||
}
|
||||
|
||||
private async loadCollision(meshUrl: string, projectId: string, worldTransform: number[]): Promise<void> {
|
||||
const app = this.requiredApp();
|
||||
const asset = new Asset(
|
||||
`SimulationCollision:${projectId}`,
|
||||
"container",
|
||||
{ url: meshUrl, filename: "scene.collision.glb" },
|
||||
);
|
||||
app.assets.add(asset);
|
||||
this.collisionAsset = asset;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
asset.ready((loaded) => {
|
||||
try {
|
||||
if (this.disposed || !this.app) {
|
||||
loaded.unload();
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const resource = loaded.resource as ContainerResource | null;
|
||||
if (!resource) throw new Error("Контейнер GLB не содержит ресурса.");
|
||||
const entity = resource.instantiateModelEntity({
|
||||
castShadows: false,
|
||||
receiveShadows: false,
|
||||
});
|
||||
entity.name = "CollisionWorld";
|
||||
entity.enabled = false;
|
||||
applyWorldTransform(entity, worldTransform);
|
||||
app.root.addChild(entity);
|
||||
|
||||
const material = new StandardMaterial();
|
||||
material.name = "SimulationCollisionMaterial";
|
||||
material.diffuse = new Color(0.2, 0.95, 0.42);
|
||||
material.emissive = new Color(0.08, 0.36, 0.14);
|
||||
material.opacity = 0.34;
|
||||
material.blendType = BLEND_NORMAL;
|
||||
material.depthWrite = false;
|
||||
material.cull = CULLFACE_NONE;
|
||||
material.update();
|
||||
const models = entity.findComponents("model") as ModelComponent[];
|
||||
for (const model of models) {
|
||||
for (const meshInstance of model.meshInstances ?? []) {
|
||||
meshInstance.material = material;
|
||||
}
|
||||
}
|
||||
this.collisionEntity = entity;
|
||||
this.collisionVisuals = models;
|
||||
this.collisionMaterial = material;
|
||||
this.applyViewMode();
|
||||
this.requestRender();
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(new Error(
|
||||
`Слой коллизий не открылся: ${error instanceof Error ? error.message : String(error)}`,
|
||||
));
|
||||
}
|
||||
});
|
||||
asset.once("error", (error: unknown) => {
|
||||
reject(new Error(`Слой коллизий не загрузился: ${String(error)}`));
|
||||
});
|
||||
app.assets.load(asset);
|
||||
});
|
||||
}
|
||||
|
||||
private async ensureCollision(): Promise<void> {
|
||||
if (this.collisionEntity) return;
|
||||
if (!this.collisionSource) {
|
||||
throw new Error("Слой коллизий отсутствует в манифесте локации.");
|
||||
}
|
||||
if (!this.collisionLoadPromise) {
|
||||
this.collisionLoadPromise = this.loadCollision(
|
||||
this.collisionSource.meshUrl,
|
||||
this.collisionSource.projectId,
|
||||
this.collisionSource.worldTransform,
|
||||
).finally(() => {
|
||||
this.collisionLoadPromise = null;
|
||||
});
|
||||
}
|
||||
await this.collisionLoadPromise;
|
||||
}
|
||||
|
||||
private unloadWorld(): void {
|
||||
this.controlRequestVersion += 1;
|
||||
this.ugvController?.disable();
|
||||
this.controlMode = "free";
|
||||
if (this.cameraController) this.cameraController.enabled = true;
|
||||
if (this.visualEntity) {
|
||||
this.visualEntity.destroy();
|
||||
this.visualEntity = null;
|
||||
}
|
||||
if (this.visualAsset && this.app) {
|
||||
this.app.assets.remove(this.visualAsset);
|
||||
this.visualAsset.unload();
|
||||
this.visualAsset = null;
|
||||
}
|
||||
if (this.collisionEntity) {
|
||||
this.collisionEntity.destroy();
|
||||
this.collisionEntity = null;
|
||||
}
|
||||
this.collisionVisuals = [];
|
||||
if (this.collisionAsset && this.app) {
|
||||
this.app.assets.remove(this.collisionAsset);
|
||||
this.collisionAsset.unload();
|
||||
this.collisionAsset = null;
|
||||
}
|
||||
this.collisionMaterial?.destroy();
|
||||
this.collisionMaterial = null;
|
||||
this.collisionSource = null;
|
||||
this.collisionLoadPromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
function preventContextMenu(event: Event): void {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
function configureDracoDecoder(): void {
|
||||
if (WasmModule.getConfig("DracoDecoderModule")) return;
|
||||
WasmModule.setConfig("DracoDecoderModule", {
|
||||
glueUrl: `${DRACO_DECODER_ROOT}/draco_wasm_wrapper_gltf.js`,
|
||||
wasmUrl: `${DRACO_DECODER_ROOT}/draco_decoder_gltf.wasm`,
|
||||
numWorkers: 2,
|
||||
});
|
||||
}
|
||||
|
||||
function focusCanvas(event: Event): void {
|
||||
(event.currentTarget as HTMLCanvasElement | null)?.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
function configureCameraDrag(
|
||||
controller: CameraController,
|
||||
inversion: () => { horizontal: boolean; vertical: boolean },
|
||||
): void {
|
||||
// CameraControls 2.21.4 deliberately exposes one pinned input source here.
|
||||
// Keep its pointer-capture and fly/orbit behavior; only the user-selected axes change sign.
|
||||
const input = controller._desktopInput;
|
||||
if (!input) return;
|
||||
const read = input.read.bind(input);
|
||||
input.read = () => {
|
||||
const frame = read();
|
||||
const selected = inversion();
|
||||
if (selected.horizontal && frame.mouse.length > 0) frame.mouse[0] *= -1;
|
||||
if (selected.vertical && frame.mouse.length > 1) frame.mouse[1] *= -1;
|
||||
return frame;
|
||||
};
|
||||
}
|
||||
|
||||
function applyWorldTransform(entity: Entity, values: number[]): void {
|
||||
const transform = new Mat4().set(values);
|
||||
entity.setLocalPosition(transform.getTranslation());
|
||||
entity.setLocalEulerAngles(transform.getEulerAngles());
|
||||
entity.setLocalScale(transform.getScale());
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
Icon,
|
||||
IconButton,
|
||||
StatusBadge,
|
||||
} from "@nodedc/ui-react";
|
||||
|
||||
import type {
|
||||
SimulationProject,
|
||||
SimulationProjectStatus,
|
||||
SimulationUploadProgress,
|
||||
} from "../../core/simulation/projects";
|
||||
import { estimateSimulationProcessing } from "../../core/simulation/projects";
|
||||
|
||||
const ACTIVE_STATUSES = new Set<SimulationProjectStatus>([
|
||||
"uploading",
|
||||
"queued",
|
||||
"processing",
|
||||
"importing",
|
||||
]);
|
||||
|
||||
export function SimulationCatalog({
|
||||
projects,
|
||||
uploadProgress,
|
||||
loading,
|
||||
loadError,
|
||||
queueError,
|
||||
dropping,
|
||||
onCreate,
|
||||
onRetryLoad,
|
||||
onSelect,
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: {
|
||||
projects: SimulationProject[];
|
||||
uploadProgress: ReadonlyMap<string, SimulationUploadProgress>;
|
||||
loading: boolean;
|
||||
loadError: string | null;
|
||||
queueError: string | null;
|
||||
dropping: boolean;
|
||||
onCreate: () => void;
|
||||
onRetryLoad: () => void;
|
||||
onSelect: (project: SimulationProject) => void;
|
||||
onEdit: (project: SimulationProject) => void;
|
||||
onDelete: (project: SimulationProject) => void;
|
||||
}) {
|
||||
const sourceBytes = projects.reduce(
|
||||
(sum, project) => sum + project.source.totalByteLength,
|
||||
0,
|
||||
);
|
||||
|
||||
return (
|
||||
<section
|
||||
className="simulation-catalog"
|
||||
data-dropping={dropping ? "true" : undefined}
|
||||
aria-label="Проекты симуляции"
|
||||
>
|
||||
<header className="simulation-catalog__summary">
|
||||
<div><span>Проектов</span><strong>{projects.length.toLocaleString("ru-RU")}</strong></div>
|
||||
<div><span>Визуал готов</span><strong>{countStatus(projects, "ready")}</strong></div>
|
||||
<div><span>В работе</span><strong>{projects.filter((project) => ACTIVE_STATUSES.has(project.status)).length}</strong></div>
|
||||
<div><span>Исходники</span><strong>{formatBytes(sourceBytes)}</strong></div>
|
||||
</header>
|
||||
|
||||
{queueError ? (
|
||||
<div className="simulation-catalog__notice" role="alert">
|
||||
<Icon name="alert" size={18} />
|
||||
<span>{queueError}</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{loading && projects.length === 0 ? (
|
||||
<div className="simulation-catalog__state" role="status">
|
||||
<ActivityIndicator label="Загрузка каталога" />
|
||||
<span>Читаем каталог сцен</span>
|
||||
</div>
|
||||
) : loadError && projects.length === 0 ? (
|
||||
<div className="simulation-catalog__state" role="alert">
|
||||
<Icon name="alert" size={20} />
|
||||
<div><strong>Каталог недоступен</strong><span>{loadError}</span></div>
|
||||
<Button size="compact" onClick={onRetryLoad}>Повторить</Button>
|
||||
</div>
|
||||
) : projects.length === 0 ? (
|
||||
<div className="simulation-catalog__empty">
|
||||
<span><Icon name="globe" size={20} /></span>
|
||||
<strong>Перетащите архивы в это окно</strong>
|
||||
<p>Каждый ZIP, RAR или 7z сразу станет отдельным проектом и встанет в очередь.</p>
|
||||
<Button variant="primary" icon={<Icon name="plus" size={16} />} onClick={onCreate}>
|
||||
Новый проект
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="simulation-catalog__table-wrap">
|
||||
<table className="simulation-catalog__table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Проект</th>
|
||||
<th>Источник</th>
|
||||
<th>Размер</th>
|
||||
<th>Сплаты</th>
|
||||
<th>Статус</th>
|
||||
<th>Обновлён</th>
|
||||
<th aria-label="Действия" />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{projects.map((project) => (
|
||||
<SimulationCatalogRow
|
||||
key={project.projectId}
|
||||
project={project}
|
||||
uploadProgress={uploadProgress.get(project.projectId)}
|
||||
onSelect={() => onSelect(project)}
|
||||
onEdit={() => onEdit(project)}
|
||||
onDelete={() => onDelete(project)}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{dropping ? (
|
||||
<div className="simulation-catalog__drop-overlay" role="status">
|
||||
<span className="simulation-catalog__drop-mark"><Icon name="plus" size={28} /></span>
|
||||
<strong>Отпустите архивы</strong>
|
||||
<span>ZIP · RAR · 7z · до 16 ГБ на проект</span>
|
||||
<small>Внутри — сцена LCC или LCC2 и связанные файлы</small>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function SimulationCatalogRow({
|
||||
project,
|
||||
uploadProgress,
|
||||
onSelect,
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: {
|
||||
project: SimulationProject;
|
||||
uploadProgress?: SimulationUploadProgress;
|
||||
onSelect: () => void;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
}) {
|
||||
const status = statusPresentation(project.status);
|
||||
const active = ACTIVE_STATUSES.has(project.status);
|
||||
return (
|
||||
<tr data-status={project.status}>
|
||||
<td>
|
||||
<button type="button" onClick={onSelect}>
|
||||
<span className="simulation-catalog__project-icon"><Icon name="globe" size={18} /></span>
|
||||
<span>
|
||||
<strong>{project.name}</strong>
|
||||
<small>{sourceFileLabel(project)}</small>
|
||||
</span>
|
||||
</button>
|
||||
</td>
|
||||
{active ? (
|
||||
<td colSpan={3}>
|
||||
<ProjectProgress project={project} localProgress={uploadProgress} />
|
||||
</td>
|
||||
) : (
|
||||
<>
|
||||
<td>
|
||||
{project.source.kind === "archive" ? "Архив" : "Папка"}
|
||||
<small>{project.source.files.length} файл(ов)</small>
|
||||
</td>
|
||||
<td>{formatBytes(project.source.totalByteLength)}</td>
|
||||
<td>—</td>
|
||||
</>
|
||||
)}
|
||||
<td><StatusBadge tone={status.tone}>{status.label}</StatusBadge></td>
|
||||
<td>{formatDate(project.updatedAtUtc)}</td>
|
||||
<td>
|
||||
<div className="simulation-catalog__actions">
|
||||
<IconButton label={`Удалить ${project.name}`} onClick={onDelete}>
|
||||
<Icon name="trash" size={16} />
|
||||
</IconButton>
|
||||
<IconButton label={`Редактировать ${project.name}`} onClick={onEdit}>
|
||||
<Icon name="edit" size={16} />
|
||||
</IconButton>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
function ProjectProgress({
|
||||
project,
|
||||
localProgress,
|
||||
}: {
|
||||
project: SimulationProject;
|
||||
localProgress?: SimulationUploadProgress;
|
||||
}) {
|
||||
const progress = progressPresentation(project, localProgress);
|
||||
return (
|
||||
<div
|
||||
className="simulation-catalog__progress"
|
||||
data-indeterminate={progress.indeterminate ? "true" : undefined}
|
||||
role="progressbar"
|
||||
aria-label={progress.label}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={progress.indeterminate ? undefined : progress.percent}
|
||||
>
|
||||
{progress.meta ? <small className="simulation-catalog__progress-meta">{progress.meta}</small> : null}
|
||||
<span className="simulation-catalog__progress-track">
|
||||
<i style={{ width: `${progress.percent}%` }} />
|
||||
</span>
|
||||
<small className="simulation-catalog__progress-stage">{progress.label}</small>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function progressPresentation(
|
||||
project: SimulationProject,
|
||||
local?: SimulationUploadProgress,
|
||||
): { percent: number; label: string; meta: string | null; indeterminate: boolean } {
|
||||
if (project.status === "uploading") {
|
||||
const uploaded = local?.uploadedBytes ?? project.source.uploadedByteLength;
|
||||
const total = local?.totalBytes ?? project.source.totalByteLength;
|
||||
const percent = total ? Math.min(100, uploaded / total * 100) : 0;
|
||||
return {
|
||||
percent,
|
||||
label: `${formatBytes(uploaded)} / ${formatBytes(total)}`,
|
||||
meta: progressMeta(percent, local?.estimatedSecondsRemaining),
|
||||
indeterminate: false,
|
||||
};
|
||||
}
|
||||
if (project.status === "queued") {
|
||||
return { percent: 0, label: "Ожидает обработки", meta: null, indeterminate: true };
|
||||
}
|
||||
const estimate = estimateSimulationProcessing(project);
|
||||
if (estimate) {
|
||||
return {
|
||||
percent: estimate.percent,
|
||||
label: processingLabel(project),
|
||||
meta: progressMeta(estimate.percent, estimate.estimatedSecondsRemaining),
|
||||
indeterminate: false,
|
||||
};
|
||||
}
|
||||
const completed = project.provider.progress?.completed_steps;
|
||||
const total = project.provider.progress?.total_steps;
|
||||
if (typeof completed === "number" && typeof total === "number" && total > 0) {
|
||||
const percent = Math.min(100, completed / total * 100);
|
||||
return {
|
||||
percent,
|
||||
label: processingLabel(project),
|
||||
meta: progressMeta(percent, null),
|
||||
indeterminate: false,
|
||||
};
|
||||
}
|
||||
return {
|
||||
percent: project.status === "importing" ? 96 : 0,
|
||||
label: processingLabel(project),
|
||||
meta: project.status === "importing" ? progressMeta(96, null) : null,
|
||||
indeterminate: project.status !== "importing",
|
||||
};
|
||||
}
|
||||
|
||||
function progressMeta(percent: number, seconds: number | null | undefined): string {
|
||||
const roundedPercent = Math.min(100, Math.max(0, Math.floor(percent)));
|
||||
return `Прогресс ${roundedPercent}% | ${remainingTimeLabel(seconds)}`;
|
||||
}
|
||||
|
||||
function remainingTimeLabel(seconds: number | null | undefined): string {
|
||||
if (seconds === null || seconds === undefined) return "Время уточняется";
|
||||
if (seconds <= 60) return "Осталось меньше минуты";
|
||||
const minutes = Math.ceil(seconds / 60);
|
||||
if (minutes < 60) return `Осталось примерно ${minutes} мин`;
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const remainder = minutes % 60;
|
||||
return `Осталось примерно ${hours} ч${remainder ? ` ${remainder} мин` : ""}`;
|
||||
}
|
||||
|
||||
function processingLabel(project: SimulationProject): string {
|
||||
if (project.status === "importing") return "Подготавливаем сцену";
|
||||
const stage = project.provider.state;
|
||||
if (stage === "verifying_source") return "Проверяем исходник";
|
||||
if (stage === "inspecting") return "Анализируем локацию";
|
||||
if (stage === "building_preview") return "Подготавливаем локацию";
|
||||
if (stage === "building_streamed_sog") return "Собираем уровни детализации";
|
||||
if (stage === "building_collision") return "Собираем коллизии";
|
||||
return "Обрабатываем локацию";
|
||||
}
|
||||
|
||||
function statusPresentation(status: SimulationProjectStatus): {
|
||||
label: string;
|
||||
tone: "success" | "accent" | "warning" | "neutral";
|
||||
} {
|
||||
if (status === "ready") return { label: "Визуал готов", tone: "success" };
|
||||
if (status === "failed") return { label: "Ошибка", tone: "warning" };
|
||||
if (status === "uploading") return { label: "Загрузка", tone: "neutral" };
|
||||
if (status === "queued") return { label: "В очереди", tone: "neutral" };
|
||||
if (status === "importing") return { label: "Подготовка", tone: "accent" };
|
||||
return { label: "Обработка", tone: "accent" };
|
||||
}
|
||||
|
||||
function sourceFileLabel(project: SimulationProject): string {
|
||||
const first = project.source.files[0]?.logicalPath;
|
||||
if (project.source.kind === "archive" && first) return first;
|
||||
return `${sceneTypeLabel(project.sceneType)} · ${project.source.files.length} файл(ов)`;
|
||||
}
|
||||
|
||||
function sceneTypeLabel(value: SimulationProject["sceneType"]): string {
|
||||
if (value === "interior") return "Интерьер";
|
||||
if (value === "object") return "Объект";
|
||||
return "Улица";
|
||||
}
|
||||
|
||||
function countStatus(projects: SimulationProject[], status: SimulationProjectStatus): number {
|
||||
return projects.filter((project) => project.status === status).length;
|
||||
}
|
||||
|
||||
function formatDate(value: string): string {
|
||||
const date = new Date(value);
|
||||
return Number.isNaN(date.valueOf()) ? "—" : date.toLocaleString("ru-RU", {
|
||||
day: "2-digit",
|
||||
month: "short",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
}
|
||||
|
||||
function formatBytes(value: number): string {
|
||||
if (value < 1024) return `${value} Б`;
|
||||
if (value < 1024 ** 2) return `${(value / 1024).toLocaleString("ru-RU", { maximumFractionDigits: 1 })} КБ`;
|
||||
if (value < 1024 ** 3) return `${(value / 1024 ** 2).toLocaleString("ru-RU", { maximumFractionDigits: 1 })} МБ`;
|
||||
return `${(value / 1024 ** 3).toLocaleString("ru-RU", { maximumFractionDigits: 2 })} ГБ`;
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
import { useEffect, useMemo, useRef, useState, type DragEvent } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
FieldFrame,
|
||||
Icon,
|
||||
Select,
|
||||
TextField,
|
||||
Window,
|
||||
WindowFooterActions,
|
||||
} from "@nodedc/ui-react";
|
||||
|
||||
import {
|
||||
createAndUploadSimulationProject,
|
||||
updateSimulationProject,
|
||||
type SimulationProject,
|
||||
type SimulationSceneType,
|
||||
type SimulationUploadCandidate,
|
||||
type SimulationUploadProgress,
|
||||
} from "../../core/simulation/projects";
|
||||
import {
|
||||
candidatesFromDrop,
|
||||
validateSimulationCandidates,
|
||||
} from "../../core/simulation/sourceFiles";
|
||||
|
||||
export function SimulationProjectWindow({
|
||||
open,
|
||||
project,
|
||||
onClose,
|
||||
onSaved,
|
||||
}: {
|
||||
open: boolean;
|
||||
project: SimulationProject | null;
|
||||
onClose: () => void;
|
||||
onSaved: (project: SimulationProject) => void;
|
||||
}) {
|
||||
const archiveInput = useRef<HTMLInputElement>(null);
|
||||
const folderInput = useRef<HTMLInputElement>(null);
|
||||
const [name, setName] = useState("");
|
||||
const [sceneType, setSceneType] = useState<SimulationSceneType>("outdoor");
|
||||
const [candidates, setCandidates] = useState<SimulationUploadCandidate[]>([]);
|
||||
const [dragging, setDragging] = useState(false);
|
||||
const [pending, setPending] = useState(false);
|
||||
const [progress, setProgress] = useState<SimulationUploadProgress | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
setName(project?.name ?? "");
|
||||
setSceneType(project?.sceneType ?? "outdoor");
|
||||
setCandidates([]);
|
||||
setProgress(null);
|
||||
setPending(false);
|
||||
setError(null);
|
||||
}, [open, project]);
|
||||
|
||||
const sourceSummary = useMemo(() => summarizeCandidates(candidates), [candidates]);
|
||||
const canSubmit = name.trim().length > 0 && (project !== null || candidates.length > 0) && !pending;
|
||||
|
||||
const acceptCandidates = (next: SimulationUploadCandidate[]) => {
|
||||
try {
|
||||
validateSimulationCandidates(next);
|
||||
setCandidates(next);
|
||||
setError(null);
|
||||
if (!name.trim() && next.length) {
|
||||
const named = next.find((candidate) => /\.lcc2?$/i.test(candidate.logicalPath)) ?? next[0];
|
||||
const first = named?.logicalPath.split("/").filter(Boolean).at(-1) ?? "Новая сцена";
|
||||
setName(first.replace(/\.(lcc2?|zip|rar|7z)$/i, ""));
|
||||
}
|
||||
} catch (caught) {
|
||||
setCandidates([]);
|
||||
setError(caught instanceof Error ? caught.message : "Источник не принят.");
|
||||
}
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
if (!canSubmit) return;
|
||||
setPending(true);
|
||||
setError(null);
|
||||
try {
|
||||
const saved = project
|
||||
? await updateSimulationProject(project.projectId, name, sceneType)
|
||||
: await createAndUploadSimulationProject(
|
||||
name,
|
||||
sceneType,
|
||||
candidates,
|
||||
setProgress,
|
||||
);
|
||||
onSaved(saved);
|
||||
} catch (caught) {
|
||||
setError(caught instanceof Error ? caught.message : "Не удалось сохранить проект.");
|
||||
setPending(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = async (event: DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
setDragging(false);
|
||||
try {
|
||||
acceptCandidates(await candidatesFromDrop(event.dataTransfer));
|
||||
} catch (caught) {
|
||||
setError(caught instanceof Error ? caught.message : "Не удалось прочитать источник.");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Window
|
||||
open={open}
|
||||
title={project ? "Редактировать проект" : "Новый проект симуляции"}
|
||||
subtitle={project ? "Метаданные сцены" : "LCC/LCC2 folder или ZIP/RAR/7z"}
|
||||
size="md"
|
||||
closeOnBackdrop={!pending}
|
||||
closeOnEscape={!pending}
|
||||
onClose={onClose}
|
||||
footer={(
|
||||
<>
|
||||
<span className="simulation-project-window__footer-state">
|
||||
{pending && project ? <><ActivityIndicator /><span>Сохраняем</span></> : null}
|
||||
</span>
|
||||
<WindowFooterActions>
|
||||
<Button disabled={pending} onClick={onClose}>Отмена</Button>
|
||||
<Button variant="primary" disabled={!canSubmit} onClick={() => void submit()}>
|
||||
{project ? "Сохранить" : "Создать и запустить"}
|
||||
</Button>
|
||||
</WindowFooterActions>
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<div className="simulation-project-window">
|
||||
<TextField
|
||||
label="Название"
|
||||
value={name}
|
||||
maxLength={120}
|
||||
disabled={pending}
|
||||
autoComplete="off"
|
||||
onChange={(event) => setName(event.currentTarget.value)}
|
||||
/>
|
||||
<FieldFrame label="Тип сцены" description="Сохраняется как профиль будущей физики и навигации.">
|
||||
<Select
|
||||
label="Тип сцены"
|
||||
value={sceneType}
|
||||
disabled={pending}
|
||||
onChange={(value) => setSceneType(value)}
|
||||
options={[
|
||||
{ value: "outdoor", label: "Улица" },
|
||||
{ value: "interior", label: "Интерьер" },
|
||||
{ value: "object", label: "Отдельный объект" },
|
||||
]}
|
||||
/>
|
||||
</FieldFrame>
|
||||
{!project ? (
|
||||
<FieldFrame
|
||||
label="Исходник"
|
||||
description="Имя родительской папки не фиксировано. Внутри должна быть ровно одна сцена LCC или LCC2."
|
||||
>
|
||||
<div
|
||||
className="simulation-source-drop"
|
||||
data-dragging={dragging ? "true" : undefined}
|
||||
onDragEnter={(event) => { event.preventDefault(); setDragging(true); }}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
onDragLeave={(event) => {
|
||||
if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setDragging(false);
|
||||
}}
|
||||
onDrop={(event) => void handleDrop(event)}
|
||||
>
|
||||
<Icon name={candidates.length ? "check" : "upload"} size={20} />
|
||||
<strong>{sourceSummary.title}</strong>
|
||||
<span>{sourceSummary.detail}</span>
|
||||
<div>
|
||||
<Button
|
||||
size="compact"
|
||||
icon={<Icon name="file" size={16} />}
|
||||
disabled={pending}
|
||||
onClick={() => archiveInput.current?.click()}
|
||||
>
|
||||
Выбрать архив
|
||||
</Button>
|
||||
<Button
|
||||
size="compact"
|
||||
icon={<Icon name="folder" size={16} />}
|
||||
disabled={pending}
|
||||
onClick={() => folderInput.current?.click()}
|
||||
>
|
||||
Выбрать папку
|
||||
</Button>
|
||||
</div>
|
||||
<input
|
||||
ref={archiveInput}
|
||||
type="file"
|
||||
accept=".zip,.rar,.7z"
|
||||
hidden
|
||||
onChange={(event) => {
|
||||
const file = event.currentTarget.files?.[0];
|
||||
if (file) acceptCandidates([{ file, logicalPath: file.name }]);
|
||||
event.currentTarget.value = "";
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
ref={folderInput}
|
||||
type="file"
|
||||
hidden
|
||||
multiple
|
||||
{...({ webkitdirectory: "" } as Record<string, string>)}
|
||||
onChange={(event) => {
|
||||
const next = Array.from(event.currentTarget.files ?? []).map((file) => ({
|
||||
file,
|
||||
logicalPath: file.webkitRelativePath || file.name,
|
||||
}));
|
||||
if (next.length) acceptCandidates(next);
|
||||
event.currentTarget.value = "";
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</FieldFrame>
|
||||
) : null}
|
||||
{progress ? (
|
||||
<div className="simulation-upload-progress" role="status">
|
||||
<span><i style={{ width: `${Math.min(100, progress.totalBytes ? progress.uploadedBytes / progress.totalBytes * 100 : 0)}%` }} /></span>
|
||||
<div>
|
||||
<strong>
|
||||
{formatBytes(progress.uploadedBytes)} / {formatBytes(progress.totalBytes)}
|
||||
{" · "}{formatUploadEta(progress.estimatedSecondsRemaining)}
|
||||
</strong>
|
||||
<small>{progress.currentPath}</small>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{error ? <p className="simulation-project-window__error" role="alert">{error}</p> : null}
|
||||
</div>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
|
||||
function formatUploadEta(seconds: number | null): string {
|
||||
if (seconds === 0) return "загружено";
|
||||
if (seconds === null) return "считаем время";
|
||||
if (seconds < 60) return `осталось ≈ ${Math.max(1, seconds)} сек`;
|
||||
const minutes = Math.ceil(seconds / 60);
|
||||
if (minutes < 60) return `осталось ≈ ${minutes} мин`;
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const remainder = minutes % 60;
|
||||
return `осталось ≈ ${hours} ч${remainder ? ` ${remainder} мин` : ""}`;
|
||||
}
|
||||
|
||||
function summarizeCandidates(candidates: SimulationUploadCandidate[]): { title: string; detail: string } {
|
||||
if (!candidates.length) return {
|
||||
title: "Перетащите архив или папку сюда",
|
||||
detail: "ZIP, RAR, 7z либо parent folder с LCC/LCC2",
|
||||
};
|
||||
const total = candidates.reduce((sum, candidate) => sum + candidate.file.size, 0);
|
||||
const archive = candidates.length === 1 && /\.(zip|rar|7z)$/i.test(candidates[0]?.logicalPath ?? "");
|
||||
return {
|
||||
title: archive ? candidates[0]?.logicalPath ?? "Архив" : "Папка принята",
|
||||
detail: `${candidates.length.toLocaleString("ru-RU")} файл(ов) · ${formatBytes(total)}`,
|
||||
};
|
||||
}
|
||||
|
||||
function formatBytes(value: number): string {
|
||||
if (value < 1024) return `${value} Б`;
|
||||
if (value < 1024 ** 2) return `${(value / 1024).toLocaleString("ru-RU", { maximumFractionDigits: 1 })} КБ`;
|
||||
if (value < 1024 ** 3) return `${(value / 1024 ** 2).toLocaleString("ru-RU", { maximumFractionDigits: 1 })} МБ`;
|
||||
return `${(value / 1024 ** 3).toLocaleString("ru-RU", { maximumFractionDigits: 2 })} ГБ`;
|
||||
}
|
||||
@@ -0,0 +1,999 @@
|
||||
import {
|
||||
Application,
|
||||
Color,
|
||||
Entity,
|
||||
Mat4,
|
||||
Mesh,
|
||||
PRIMITIVE_TRIANGLES,
|
||||
Quat,
|
||||
StandardMaterial,
|
||||
Vec3,
|
||||
WasmModule,
|
||||
type ModelComponent,
|
||||
} from "playcanvas";
|
||||
import { MeshoptSimplifier } from "meshoptimizer/simplifier";
|
||||
import type { SimulationUgvPreset } from "../../core/simulation/projects";
|
||||
|
||||
const AMMO_MODULE_ROOT = "/vendor/playcanvas/ammo/2026-08-25";
|
||||
const UGV_SPAWN_POSITION = new Vec3(0, 1.15, 0);
|
||||
const UGV_SPAWN_ROTATION = new Vec3(0, 0, 0);
|
||||
const ZERO = new Vec3(0, 0, 0);
|
||||
const DISABLE_DEACTIVATION = 4;
|
||||
const PHYSICS_PROXY_RATIO = 0.04;
|
||||
const PHYSICS_PROXY_ERROR = 0.0003;
|
||||
const PHYSICS_PROXY_MAX_TRIANGLES = 240_000;
|
||||
const SERVICE_BRAKE_DECELERATION_MPS2 = 1.8;
|
||||
const COAST_DECELERATION_MPS2 = 0.18;
|
||||
const BRAKE_ATTITUDE_DAMPING = 6;
|
||||
const DEFAULT_ORBIT_PITCH = 0.48;
|
||||
const CAMERA_RETURN_DELAY_SECONDS = 1.2;
|
||||
const CAMERA_RETURN_DURATION_SECONDS = 2;
|
||||
const UGV_SPAWN_OFFSETS: ReadonlyArray<readonly [number, number]> = [
|
||||
[0, 0],
|
||||
[1.5, 0],
|
||||
[-1.5, 0],
|
||||
[0, 1.5],
|
||||
[0, -1.5],
|
||||
[1.5, 1.5],
|
||||
[-1.5, 1.5],
|
||||
[1.5, -1.5],
|
||||
[-1.5, -1.5],
|
||||
[3, 0],
|
||||
[-3, 0],
|
||||
[0, 3],
|
||||
[0, -3],
|
||||
];
|
||||
|
||||
export const DEFAULT_SIMULATION_UGV_PRESET: SimulationUgvPreset = {
|
||||
presetName: "UGV 100 кг",
|
||||
massKg: 100,
|
||||
dimensionsMeters: {
|
||||
length: 1,
|
||||
width: 0.8,
|
||||
height: 0.4,
|
||||
groundClearance: 0.15,
|
||||
},
|
||||
maxSpeedMetersPerSecond: 1.2,
|
||||
maxTurnRateDegrees: 45,
|
||||
invertSteering: false,
|
||||
};
|
||||
|
||||
type NativeObject = object;
|
||||
|
||||
interface NativeVector3 extends NativeObject {
|
||||
x(): number;
|
||||
y(): number;
|
||||
z(): number;
|
||||
setValue(x: number, y: number, z: number): void;
|
||||
}
|
||||
|
||||
interface NativeQuaternion extends NativeObject {
|
||||
x(): number;
|
||||
y(): number;
|
||||
z(): number;
|
||||
w(): number;
|
||||
}
|
||||
|
||||
interface NativeTransform extends NativeObject {
|
||||
getOrigin(): NativeVector3;
|
||||
getRotation(): NativeQuaternion;
|
||||
}
|
||||
|
||||
interface NativeWheelInfo extends NativeObject {
|
||||
set_m_suspensionStiffness(value: number): void;
|
||||
set_m_wheelsDampingRelaxation(value: number): void;
|
||||
set_m_wheelsDampingCompression(value: number): void;
|
||||
set_m_frictionSlip(value: number): void;
|
||||
set_m_rollInfluence(value: number): void;
|
||||
}
|
||||
|
||||
interface NativeRaycastVehicle extends NativeObject {
|
||||
setCoordinateSystem(right: number, up: number, forward: number): void;
|
||||
addWheel(
|
||||
connectionPoint: NativeVector3,
|
||||
direction: NativeVector3,
|
||||
axle: NativeVector3,
|
||||
suspensionRestLength: number,
|
||||
radius: number,
|
||||
tuning: NativeObject,
|
||||
isFront: boolean,
|
||||
): NativeWheelInfo;
|
||||
applyEngineForce(force: number, wheel: number): void;
|
||||
setBrake(force: number, wheel: number): void;
|
||||
setSteeringValue(value: number, wheel: number): void;
|
||||
getNumWheels(): number;
|
||||
updateWheelTransform(wheel: number, interpolated: boolean): void;
|
||||
getWheelTransformWS(wheel: number): NativeTransform;
|
||||
getForwardVector(): NativeVector3;
|
||||
getCurrentSpeedKmHour(): number;
|
||||
resetSuspension(): void;
|
||||
}
|
||||
|
||||
export interface AmmoApi {
|
||||
btVehicleTuning: new () => NativeObject;
|
||||
btDefaultVehicleRaycaster: new (world: NativeObject) => NativeObject;
|
||||
btRaycastVehicle: new (
|
||||
tuning: NativeObject,
|
||||
body: NativeObject,
|
||||
raycaster: NativeObject,
|
||||
) => NativeRaycastVehicle;
|
||||
btVector3: new (x: number, y: number, z: number) => NativeVector3;
|
||||
destroy(object: NativeObject): void;
|
||||
}
|
||||
|
||||
interface NativeDynamicsWorld extends NativeObject {
|
||||
addAction(action: NativeObject): void;
|
||||
removeAction(action: NativeObject): void;
|
||||
}
|
||||
|
||||
interface PhysicsSystemAccess {
|
||||
systems: {
|
||||
rigidbody: {
|
||||
dynamicsWorld: NativeDynamicsWorld | null;
|
||||
raycastFirst(start: Vec3, end: Vec3): { point: Vec3; normal: Vec3 } | null;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface NativeRigidBodyAccess {
|
||||
rigidbody?: {
|
||||
body: NativeObject | null;
|
||||
linearVelocity: Vec3;
|
||||
angularVelocity: Vec3;
|
||||
teleport(position: Vec3, rotation?: Vec3 | Quat): void;
|
||||
};
|
||||
}
|
||||
|
||||
interface WheelDefinition {
|
||||
connection: Vec3;
|
||||
left: boolean;
|
||||
front: boolean;
|
||||
anchor: Entity;
|
||||
}
|
||||
|
||||
let ammoInstancePromise: Promise<AmmoApi> | null = null;
|
||||
|
||||
export function prepareSimulationPhysics(): Promise<AmmoApi> {
|
||||
if (ammoInstancePromise) return ammoInstancePromise;
|
||||
|
||||
ammoInstancePromise = new Promise<AmmoApi>((resolve, reject) => {
|
||||
if (!WasmModule.getConfig("Ammo")) {
|
||||
WasmModule.setConfig("Ammo", {
|
||||
glueUrl: `${AMMO_MODULE_ROOT}/ammo.wasm.js`,
|
||||
wasmUrl: `${AMMO_MODULE_ROOT}/ammo.wasm.wasm`,
|
||||
errorHandler: (error) => {
|
||||
ammoInstancePromise = null;
|
||||
reject(new Error(`Физический модуль UGV не загрузился: ${String(error)}`));
|
||||
},
|
||||
});
|
||||
}
|
||||
WasmModule.getInstance("Ammo", (instance) => {
|
||||
if (!instance) {
|
||||
ammoInstancePromise = null;
|
||||
reject(new Error("Физический модуль UGV вернул пустой экземпляр."));
|
||||
return;
|
||||
}
|
||||
resolve(instance as AmmoApi);
|
||||
});
|
||||
});
|
||||
|
||||
return ammoInstancePromise;
|
||||
}
|
||||
|
||||
export class SimulationUgvController {
|
||||
private readonly pressed = new Set<string>();
|
||||
private readonly collisionBodies: Entity[] = [];
|
||||
private readonly collisionMeshes: Mesh[] = [];
|
||||
private readonly wheelDefinitions: WheelDefinition[] = [];
|
||||
private readonly cameraTarget = new Vec3();
|
||||
private readonly cameraDesired = new Vec3();
|
||||
private readonly cameraLookAt = new Vec3();
|
||||
private readonly forward = new Vec3(0, 0, 1);
|
||||
private readonly smoothedCamera = new Vec3();
|
||||
private readonly limitedLinearVelocity = new Vec3();
|
||||
private readonly limitedAngularVelocity = new Vec3();
|
||||
private readonly spawnPosition = UGV_SPAWN_POSITION.clone();
|
||||
private orbitPointerId: number | null = null;
|
||||
private orbitPointerX = 0;
|
||||
private orbitPointerY = 0;
|
||||
private orbitYaw = 0;
|
||||
private orbitPitch = DEFAULT_ORBIT_PITCH;
|
||||
private orbitDistance = 3.8;
|
||||
private orbitIdleSeconds = 0;
|
||||
private cameraOrbitInitialized = false;
|
||||
private active = false;
|
||||
private vehicleEntity: Entity | null = null;
|
||||
private vehicle: NativeRaycastVehicle | null = null;
|
||||
private vehicleTuning: NativeObject | null = null;
|
||||
private vehicleRaycaster: NativeObject | null = null;
|
||||
private dynamicsWorld: NativeDynamicsWorld | null = null;
|
||||
private chassisMaterial: StandardMaterial | null = null;
|
||||
private wheelMaterial: StandardMaterial | null = null;
|
||||
private cameraInitialized = false;
|
||||
private settings: SimulationUgvPreset;
|
||||
|
||||
constructor(
|
||||
private readonly app: Application,
|
||||
private readonly canvas: HTMLCanvasElement,
|
||||
private readonly camera: Entity,
|
||||
private readonly ammo: AmmoApi,
|
||||
initialSettings: SimulationUgvPreset = DEFAULT_SIMULATION_UGV_PRESET,
|
||||
) {
|
||||
this.settings = cloneUgvPreset(initialSettings);
|
||||
}
|
||||
|
||||
get enabled(): boolean {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
configure(settings: SimulationUgvPreset): void {
|
||||
const next = cloneUgvPreset(settings);
|
||||
const rebuildRequired = this.active && vehicleGeometryChanged(this.settings, next);
|
||||
this.settings = next;
|
||||
if (!rebuildRequired) return;
|
||||
this.destroyVehicle();
|
||||
this.spawnPosition.copy(this.findSafeSpawnPosition());
|
||||
this.createVehicle();
|
||||
this.reset(false, false);
|
||||
}
|
||||
|
||||
async enable(collisionWorld: Entity): Promise<void> {
|
||||
if (this.active) return;
|
||||
await nextAnimationFrame();
|
||||
try {
|
||||
await this.createStaticCollisionBodies(collisionWorld);
|
||||
await nextAnimationFrame();
|
||||
this.spawnPosition.copy(this.findSafeSpawnPosition());
|
||||
this.createVehicle();
|
||||
this.attachInput();
|
||||
this.active = true;
|
||||
this.reset();
|
||||
} catch (error) {
|
||||
this.disable();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
disable(): void {
|
||||
this.active = false;
|
||||
this.detachInput();
|
||||
this.pressed.clear();
|
||||
|
||||
this.destroyVehicle();
|
||||
|
||||
for (const entity of this.collisionBodies.splice(0)) {
|
||||
runCleanup("destroy static physics proxy", () => entity.destroy());
|
||||
}
|
||||
for (const mesh of this.collisionMeshes.splice(0)) {
|
||||
runCleanup("destroy static physics mesh", () => mesh.destroy());
|
||||
}
|
||||
this.cameraInitialized = false;
|
||||
this.cameraOrbitInitialized = false;
|
||||
this.orbitIdleSeconds = 0;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disable();
|
||||
}
|
||||
|
||||
reset(focusCanvas = true, resetCameraOrbit = true): void {
|
||||
const vehicleEntity = this.vehicleEntity as (Entity & NativeRigidBodyAccess) | null;
|
||||
const rigidbody = vehicleEntity?.rigidbody;
|
||||
if (!vehicleEntity || !rigidbody) return;
|
||||
rigidbody.teleport(this.spawnPosition, UGV_SPAWN_ROTATION);
|
||||
rigidbody.linearVelocity = ZERO;
|
||||
rigidbody.angularVelocity = ZERO;
|
||||
this.vehicle?.resetSuspension();
|
||||
this.cameraInitialized = false;
|
||||
if (resetCameraOrbit) {
|
||||
this.cameraOrbitInitialized = false;
|
||||
this.orbitIdleSeconds = 0;
|
||||
}
|
||||
this.updateCamera(1);
|
||||
if (focusCanvas) this.canvas.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
syncCollisionBodies(): void {
|
||||
for (const entity of this.collisionBodies) {
|
||||
const rigidbody = (entity as Entity & NativeRigidBodyAccess).rigidbody;
|
||||
rigidbody?.teleport(entity.getPosition(), entity.getRotation());
|
||||
}
|
||||
}
|
||||
|
||||
update(deltaSeconds: number): void {
|
||||
if (!this.active || !this.vehicle || !this.vehicleEntity) return;
|
||||
const forwardInput = Number(this.isPressed("KeyW", "ArrowUp")) - Number(this.isPressed("KeyS", "ArrowDown"));
|
||||
const requestedTurn = Number(this.isPressed("KeyA", "ArrowLeft")) - Number(this.isPressed("KeyD", "ArrowRight"));
|
||||
const turnInput = this.settings.invertSteering ? -requestedTurn : requestedTurn;
|
||||
const braking = this.pressed.has("Space");
|
||||
const rigidbody = (this.vehicleEntity as Entity & NativeRigidBodyAccess).rigidbody;
|
||||
const speedMetersPerSecond = this.vehicle.getCurrentSpeedKmHour() / 3.6;
|
||||
const maxSpeed = this.settings.maxSpeedMetersPerSecond;
|
||||
const maxTurnRate = this.settings.maxTurnRateDegrees * Math.PI / 180;
|
||||
const pureTurn = !braking && forwardInput === 0 && turnInput !== 0;
|
||||
const desiredSpeed = forwardInput * maxSpeed;
|
||||
const speedError = desiredSpeed - speedMetersPerSecond;
|
||||
const speedResponseRange = Math.max(0.35, maxSpeed * 0.2);
|
||||
const throttle = forwardInput === 0
|
||||
? 0
|
||||
: clamp(Math.abs(speedError) / speedResponseRange, 0, 1);
|
||||
const maximumAcceleration = clamp(1.4 + maxSpeed * 0.35, 1.8, 4.2);
|
||||
const driveForcePerWheel = this.settings.massKg * maximumAcceleration * throttle / 4;
|
||||
const pivotForcePerWheel = this.settings.massKg * 0.65;
|
||||
const forwardCommand = braking ? 0 : forwardInput;
|
||||
const turnCommand = braking ? 0 : turnInput;
|
||||
const leftCommand = clamp(forwardCommand - turnCommand, -1, 1);
|
||||
const rightCommand = clamp(forwardCommand + turnCommand, -1, 1);
|
||||
const engineForce = pureTurn ? pivotForcePerWheel : driveForcePerWheel;
|
||||
|
||||
for (let index = 0; index < this.wheelDefinitions.length; index += 1) {
|
||||
const definition = this.wheelDefinitions[index];
|
||||
const command = definition.left ? leftCommand : rightCommand;
|
||||
this.vehicle.setSteeringValue(0, index);
|
||||
this.vehicle.applyEngineForce(command * engineForce, index);
|
||||
this.vehicle.setBrake(0, index);
|
||||
this.vehicle.updateWheelTransform(index, true);
|
||||
const transform = this.vehicle.getWheelTransformWS(index);
|
||||
const position = transform.getOrigin();
|
||||
const rotation = transform.getRotation();
|
||||
definition.anchor.setPosition(position.x(), position.y(), position.z());
|
||||
definition.anchor.setRotation(rotation.x(), rotation.y(), rotation.z(), rotation.w());
|
||||
}
|
||||
|
||||
if (rigidbody) {
|
||||
const linearVelocity = rigidbody.linearVelocity;
|
||||
let nextLinearX = linearVelocity.x;
|
||||
let nextLinearZ = linearVelocity.z;
|
||||
let horizontalSpeed = Math.hypot(nextLinearX, nextLinearZ);
|
||||
const coasting = !braking && forwardInput === 0 && turnInput === 0;
|
||||
if ((braking || coasting) && horizontalSpeed > 0.001) {
|
||||
const deceleration = braking
|
||||
? SERVICE_BRAKE_DECELERATION_MPS2
|
||||
: COAST_DECELERATION_MPS2;
|
||||
const nextSpeed = Math.max(0, horizontalSpeed - deceleration * Math.max(0, deltaSeconds));
|
||||
const scale = nextSpeed / horizontalSpeed;
|
||||
nextLinearX *= scale;
|
||||
nextLinearZ *= scale;
|
||||
horizontalSpeed = nextSpeed;
|
||||
}
|
||||
if (pureTurn && horizontalSpeed > 0.001) {
|
||||
const pivotDamping = Math.exp(-Math.max(0, deltaSeconds) * 8);
|
||||
nextLinearX *= pivotDamping;
|
||||
nextLinearZ *= pivotDamping;
|
||||
horizontalSpeed *= pivotDamping;
|
||||
}
|
||||
if (horizontalSpeed > maxSpeed * 1.05) {
|
||||
const scale = maxSpeed / horizontalSpeed;
|
||||
nextLinearX *= scale;
|
||||
nextLinearZ *= scale;
|
||||
}
|
||||
if (nextLinearX !== linearVelocity.x || nextLinearZ !== linearVelocity.z) {
|
||||
this.limitedLinearVelocity.set(nextLinearX, linearVelocity.y, nextLinearZ);
|
||||
rigidbody.linearVelocity = this.limitedLinearVelocity;
|
||||
}
|
||||
const angularVelocity = rigidbody.angularVelocity;
|
||||
const attitudeDamping = braking
|
||||
? Math.exp(-Math.max(0, deltaSeconds) * BRAKE_ATTITUDE_DAMPING)
|
||||
: 1;
|
||||
let nextAngularY = angularVelocity.y;
|
||||
if (pureTurn) {
|
||||
const desiredYawRate = -turnInput * maxTurnRate;
|
||||
const turnAcceleration = Math.max(2, maxTurnRate * 4);
|
||||
nextAngularY = approach(
|
||||
angularVelocity.y,
|
||||
desiredYawRate,
|
||||
turnAcceleration * Math.max(0, deltaSeconds),
|
||||
);
|
||||
} else if (Math.abs(angularVelocity.y) > maxTurnRate) {
|
||||
nextAngularY = Math.sign(angularVelocity.y) * maxTurnRate;
|
||||
}
|
||||
if (attitudeDamping !== 1 || nextAngularY !== angularVelocity.y) {
|
||||
this.limitedAngularVelocity.set(
|
||||
angularVelocity.x * attitudeDamping,
|
||||
nextAngularY,
|
||||
angularVelocity.z * attitudeDamping,
|
||||
);
|
||||
rigidbody.angularVelocity = this.limitedAngularVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
const body = (this.vehicleEntity as Entity & NativeRigidBodyAccess).rigidbody?.body as {
|
||||
setActivationState?: (state: number) => void;
|
||||
} | null;
|
||||
body?.setActivationState?.(DISABLE_DEACTIVATION);
|
||||
if (this.vehicleEntity.getPosition().y < -8) this.reset();
|
||||
this.updateCamera(deltaSeconds);
|
||||
}
|
||||
|
||||
private async createStaticCollisionBodies(collisionWorld: Entity): Promise<void> {
|
||||
const models = collisionWorld.findComponents("model") as ModelComponent[];
|
||||
if (models.length === 0) throw new Error("В слое коллизий нет геометрии для физики UGV.");
|
||||
|
||||
const meshInstances = models.flatMap((model) => Array.from(model.meshInstances ?? []));
|
||||
const totalTriangles = meshInstances.reduce(
|
||||
(total, meshInstance) => total + Math.floor((meshInstance.mesh.primitive[0]?.count ?? 0) / 3),
|
||||
0,
|
||||
);
|
||||
if (totalTriangles === 0) throw new Error("В слое коллизий нет треугольников для физики UGV.");
|
||||
const targetRatio = totalTriangles <= PHYSICS_PROXY_MAX_TRIANGLES
|
||||
? 1
|
||||
: Math.min(PHYSICS_PROXY_RATIO, PHYSICS_PROXY_MAX_TRIANGLES / totalTriangles);
|
||||
await MeshoptSimplifier.ready;
|
||||
await nextAnimationFrame();
|
||||
|
||||
const rootInverse = collisionWorld.getWorldTransform().clone().invert();
|
||||
for (let index = 0; index < meshInstances.length; index += 1) {
|
||||
const meshInstance = meshInstances[index];
|
||||
const physicsMesh = createPhysicsProxyMesh(
|
||||
this.app,
|
||||
meshInstance.mesh,
|
||||
new Mat4().mul2(rootInverse, meshInstance.node.getWorldTransform()),
|
||||
targetRatio,
|
||||
);
|
||||
if (!physicsMesh) continue;
|
||||
const entity = new Entity(`UGV physics proxy ${index + 1}`);
|
||||
collisionWorld.addChild(entity);
|
||||
entity.addComponent("collision", {
|
||||
type: "mesh",
|
||||
render: { meshes: [physicsMesh] },
|
||||
checkVertexDuplicates: false,
|
||||
});
|
||||
entity.addComponent("rigidbody", {
|
||||
type: "static",
|
||||
friction: 0.95,
|
||||
restitution: 0,
|
||||
});
|
||||
this.collisionBodies.push(entity);
|
||||
this.collisionMeshes.push(physicsMesh);
|
||||
if ((index + 1) % 4 === 0) await nextAnimationFrame();
|
||||
}
|
||||
|
||||
if (this.collisionBodies.length === 0) {
|
||||
throw new Error("Не удалось создать статический физический слой UGV.");
|
||||
}
|
||||
}
|
||||
|
||||
private createVehicle(): void {
|
||||
const access = this.app as unknown as PhysicsSystemAccess;
|
||||
const dynamicsWorld = access.systems.rigidbody.dynamicsWorld;
|
||||
if (!dynamicsWorld) throw new Error("Физический мир PlayCanvas не готов.");
|
||||
|
||||
const vehicle = new Entity("SimulationUGV");
|
||||
vehicle.addComponent("collision", { type: "compound" });
|
||||
vehicle.addComponent("rigidbody", {
|
||||
type: "dynamic",
|
||||
mass: this.settings.massKg,
|
||||
friction: 0.85,
|
||||
linearDamping: 0.08,
|
||||
angularDamping: 0.45,
|
||||
});
|
||||
|
||||
this.chassisMaterial = createMaterial(readThemeAccent(), new Color(0.03, 0.04, 0.05));
|
||||
this.wheelMaterial = createMaterial(new Color(0.055, 0.06, 0.07), new Color(0.008, 0.009, 0.01));
|
||||
|
||||
const dimensions = vehicleDimensions(this.settings);
|
||||
const chassis = createBox(
|
||||
"UGV chassis",
|
||||
new Vec3(dimensions.bodyWidth, dimensions.mainHeight, dimensions.length),
|
||||
this.chassisMaterial,
|
||||
);
|
||||
chassis.setLocalPosition(0, dimensions.mainCenterY, 0);
|
||||
chassis.addComponent("collision", {
|
||||
type: "box",
|
||||
halfExtents: new Vec3(
|
||||
dimensions.bodyWidth / 2,
|
||||
dimensions.mainHeight / 2,
|
||||
dimensions.length / 2,
|
||||
),
|
||||
});
|
||||
vehicle.addChild(chassis);
|
||||
|
||||
const equipment = createBox(
|
||||
"UGV equipment",
|
||||
new Vec3(dimensions.bodyWidth * 0.68, dimensions.equipmentHeight, dimensions.length * 0.56),
|
||||
this.chassisMaterial,
|
||||
);
|
||||
equipment.setLocalPosition(0, dimensions.equipmentCenterY, -dimensions.length * 0.04);
|
||||
equipment.addComponent("collision", {
|
||||
type: "box",
|
||||
halfExtents: new Vec3(
|
||||
dimensions.bodyWidth * 0.34,
|
||||
dimensions.equipmentHeight / 2,
|
||||
dimensions.length * 0.28,
|
||||
),
|
||||
});
|
||||
vehicle.addChild(equipment);
|
||||
|
||||
const wheelConnections = [
|
||||
{ connection: new Vec3(dimensions.wheelX, dimensions.wheelConnectionY, dimensions.wheelZ), left: false, front: true },
|
||||
{ connection: new Vec3(-dimensions.wheelX, dimensions.wheelConnectionY, dimensions.wheelZ), left: true, front: true },
|
||||
{ connection: new Vec3(dimensions.wheelX, dimensions.wheelConnectionY, -dimensions.wheelZ), left: false, front: false },
|
||||
{ connection: new Vec3(-dimensions.wheelX, dimensions.wheelConnectionY, -dimensions.wheelZ), left: true, front: false },
|
||||
];
|
||||
|
||||
for (const definition of wheelConnections) {
|
||||
const anchor = new Entity(definition.left ? "UGV wheel left" : "UGV wheel right");
|
||||
anchor.setLocalPosition(definition.connection);
|
||||
const wheelMesh = new Entity("UGV wheel mesh");
|
||||
wheelMesh.addComponent("render", { type: "cylinder", castShadows: false, receiveShadows: false });
|
||||
wheelMesh.setLocalEulerAngles(0, 0, 90);
|
||||
wheelMesh.setLocalScale(
|
||||
dimensions.wheelRadius * 2,
|
||||
dimensions.wheelThickness,
|
||||
dimensions.wheelRadius * 2,
|
||||
);
|
||||
applyMaterial(wheelMesh, this.wheelMaterial);
|
||||
anchor.addChild(wheelMesh);
|
||||
vehicle.addChild(anchor);
|
||||
this.wheelDefinitions.push({ ...definition, anchor });
|
||||
}
|
||||
|
||||
vehicle.setLocalPosition(this.spawnPosition);
|
||||
this.app.root.addChild(vehicle);
|
||||
|
||||
const body = (vehicle as Entity & NativeRigidBodyAccess).rigidbody?.body;
|
||||
if (!body) {
|
||||
vehicle.destroy();
|
||||
throw new Error("Динамическое тело UGV не создалось.");
|
||||
}
|
||||
|
||||
const tuning = new this.ammo.btVehicleTuning();
|
||||
const raycaster = new this.ammo.btDefaultVehicleRaycaster(dynamicsWorld);
|
||||
const nativeVehicle = new this.ammo.btRaycastVehicle(tuning, body, raycaster);
|
||||
nativeVehicle.setCoordinateSystem(0, 1, 2);
|
||||
|
||||
const axle = new this.ammo.btVector3(-1, 0, 0);
|
||||
const direction = new this.ammo.btVector3(0, -1, 0);
|
||||
const connection = new this.ammo.btVector3(0, 0, 0);
|
||||
for (const definition of this.wheelDefinitions) {
|
||||
connection.setValue(definition.connection.x, definition.connection.y, definition.connection.z);
|
||||
const wheel = nativeVehicle.addWheel(
|
||||
connection,
|
||||
direction,
|
||||
axle,
|
||||
dimensions.suspensionRestLength,
|
||||
dimensions.wheelRadius,
|
||||
tuning,
|
||||
definition.front,
|
||||
);
|
||||
wheel.set_m_suspensionStiffness(24);
|
||||
wheel.set_m_wheelsDampingRelaxation(3.2);
|
||||
wheel.set_m_wheelsDampingCompression(4.8);
|
||||
wheel.set_m_frictionSlip(5.5);
|
||||
wheel.set_m_rollInfluence(0.08);
|
||||
}
|
||||
this.ammo.destroy(axle);
|
||||
this.ammo.destroy(direction);
|
||||
this.ammo.destroy(connection);
|
||||
|
||||
dynamicsWorld.addAction(nativeVehicle);
|
||||
this.vehicleEntity = vehicle;
|
||||
this.vehicleTuning = tuning;
|
||||
this.vehicleRaycaster = raycaster;
|
||||
this.vehicle = nativeVehicle;
|
||||
this.dynamicsWorld = dynamicsWorld;
|
||||
}
|
||||
|
||||
private updateCamera(deltaSeconds: number): void {
|
||||
if (!this.vehicleEntity || !this.vehicle) return;
|
||||
this.cameraTarget.copy(this.vehicleEntity.getPosition());
|
||||
this.cameraLookAt.copy(this.cameraTarget);
|
||||
this.cameraLookAt.y += Math.max(0.15, this.settings.dimensionsMeters.height * 0.35);
|
||||
|
||||
const nativeForward = this.vehicle.getForwardVector();
|
||||
this.forward.set(nativeForward.x(), 0, nativeForward.z());
|
||||
if (this.forward.lengthSq() < 0.001) this.forward.set(0, 0, 1);
|
||||
this.forward.normalize();
|
||||
const rearOrbitYaw = Math.atan2(-this.forward.x, -this.forward.z);
|
||||
if (!this.cameraOrbitInitialized) {
|
||||
this.orbitYaw = rearOrbitYaw;
|
||||
this.orbitPitch = DEFAULT_ORBIT_PITCH;
|
||||
this.orbitDistance = Math.max(3.2, this.settings.dimensionsMeters.length * 3.8);
|
||||
this.cameraOrbitInitialized = true;
|
||||
this.orbitIdleSeconds = 0;
|
||||
} else if (this.orbitPointerId === null) {
|
||||
this.orbitIdleSeconds += Math.max(0, deltaSeconds);
|
||||
if (this.orbitIdleSeconds >= CAMERA_RETURN_DELAY_SECONDS) {
|
||||
const returnDelta = Math.max(0, deltaSeconds) / CAMERA_RETURN_DURATION_SECONDS;
|
||||
this.orbitYaw = approachAngle(this.orbitYaw, rearOrbitYaw, Math.PI * returnDelta);
|
||||
this.orbitPitch = approach(
|
||||
this.orbitPitch,
|
||||
DEFAULT_ORBIT_PITCH,
|
||||
Math.PI * 0.5 * returnDelta,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const horizontalDistance = Math.cos(this.orbitPitch) * this.orbitDistance;
|
||||
this.cameraDesired.set(
|
||||
this.cameraLookAt.x + Math.sin(this.orbitYaw) * horizontalDistance,
|
||||
this.cameraLookAt.y + Math.sin(this.orbitPitch) * this.orbitDistance,
|
||||
this.cameraLookAt.z + Math.cos(this.orbitYaw) * horizontalDistance,
|
||||
);
|
||||
|
||||
if (!this.cameraInitialized) {
|
||||
this.smoothedCamera.copy(this.cameraDesired);
|
||||
this.cameraInitialized = true;
|
||||
} else {
|
||||
const blend = 1 - Math.exp(
|
||||
-Math.max(0, deltaSeconds) * (this.orbitPointerId === null ? 8 : 18),
|
||||
);
|
||||
this.smoothedCamera.lerp(this.smoothedCamera, this.cameraDesired, blend);
|
||||
}
|
||||
this.camera.setPosition(this.smoothedCamera);
|
||||
this.camera.lookAt(this.cameraLookAt);
|
||||
}
|
||||
|
||||
private findSafeSpawnPosition(): Vec3 {
|
||||
const dimensions = vehicleDimensions(this.settings);
|
||||
const footprint: ReadonlyArray<readonly [number, number]> = [
|
||||
[0, 0],
|
||||
[dimensions.width * 0.42, dimensions.length * 0.42],
|
||||
[-dimensions.width * 0.42, dimensions.length * 0.42],
|
||||
[dimensions.width * 0.42, -dimensions.length * 0.42],
|
||||
[-dimensions.width * 0.42, -dimensions.length * 0.42],
|
||||
];
|
||||
const clearanceDirections: ReadonlyArray<readonly [number, number]> = [
|
||||
[dimensions.width * 0.62, 0],
|
||||
[-dimensions.width * 0.62, 0],
|
||||
[0, dimensions.length * 0.62],
|
||||
[0, -dimensions.length * 0.62],
|
||||
];
|
||||
const from = new Vec3();
|
||||
const to = new Vec3();
|
||||
const physics = (this.app as unknown as PhysicsSystemAccess).systems.rigidbody;
|
||||
|
||||
for (const [offsetX, offsetZ] of UGV_SPAWN_OFFSETS) {
|
||||
const heights: number[] = [];
|
||||
let suitable = true;
|
||||
for (const [sampleX, sampleZ] of footprint) {
|
||||
const x = UGV_SPAWN_POSITION.x + offsetX + sampleX;
|
||||
const z = UGV_SPAWN_POSITION.z + offsetZ + sampleZ;
|
||||
from.set(x, 8, z);
|
||||
to.set(x, -8, z);
|
||||
const hit = physics.raycastFirst(from, to);
|
||||
if (!hit || hit.normal.y < 0.72 || Math.abs(hit.point.y) > 2.5) {
|
||||
suitable = false;
|
||||
break;
|
||||
}
|
||||
heights.push(hit.point.y);
|
||||
}
|
||||
if (!suitable || heights.length !== footprint.length) continue;
|
||||
const minimum = Math.min(...heights);
|
||||
const maximum = Math.max(...heights);
|
||||
if (maximum - minimum > 0.32) continue;
|
||||
|
||||
const x = UGV_SPAWN_POSITION.x + offsetX;
|
||||
const z = UGV_SPAWN_POSITION.z + offsetZ;
|
||||
const ground = heights.reduce((sum, height) => sum + height, 0) / heights.length;
|
||||
const clearanceHeight = ground + dimensions.originHeight;
|
||||
const origin = new Vec3(x, clearanceHeight, z);
|
||||
const blocked = clearanceDirections.some(([directionX, directionZ]) => {
|
||||
to.set(x + directionX, clearanceHeight, z + directionZ);
|
||||
return physics.raycastFirst(origin, to) !== null;
|
||||
});
|
||||
if (!blocked) return new Vec3(x, ground + dimensions.originHeight, z);
|
||||
}
|
||||
|
||||
return UGV_SPAWN_POSITION.clone();
|
||||
}
|
||||
|
||||
private destroyVehicle(): void {
|
||||
if (this.vehicle && this.dynamicsWorld) {
|
||||
runCleanup("remove vehicle action", () => this.dynamicsWorld?.removeAction(this.vehicle as NativeObject));
|
||||
}
|
||||
if (this.vehicle) runCleanup("destroy vehicle", () => this.ammo.destroy(this.vehicle as NativeObject));
|
||||
if (this.vehicleRaycaster) runCleanup("destroy vehicle raycaster", () => this.ammo.destroy(this.vehicleRaycaster as NativeObject));
|
||||
if (this.vehicleTuning) runCleanup("destroy vehicle tuning", () => this.ammo.destroy(this.vehicleTuning as NativeObject));
|
||||
this.vehicle = null;
|
||||
this.vehicleRaycaster = null;
|
||||
this.vehicleTuning = null;
|
||||
this.dynamicsWorld = null;
|
||||
|
||||
if (this.vehicleEntity) runCleanup("destroy vehicle entity", () => this.vehicleEntity?.destroy());
|
||||
this.vehicleEntity = null;
|
||||
this.wheelDefinitions.length = 0;
|
||||
if (this.chassisMaterial) runCleanup("destroy chassis material", () => this.chassisMaterial?.destroy());
|
||||
if (this.wheelMaterial) runCleanup("destroy wheel material", () => this.wheelMaterial?.destroy());
|
||||
this.chassisMaterial = null;
|
||||
this.wheelMaterial = null;
|
||||
this.cameraInitialized = false;
|
||||
}
|
||||
|
||||
private isPressed(primary: string, alternative: string): boolean {
|
||||
return this.pressed.has(primary) || this.pressed.has(alternative);
|
||||
}
|
||||
|
||||
private attachInput(): void {
|
||||
window.addEventListener("keydown", this.onKeyDown, true);
|
||||
window.addEventListener("keyup", this.onKeyUp, true);
|
||||
window.addEventListener("blur", this.onWindowBlur);
|
||||
this.canvas.addEventListener("pointerdown", this.onOrbitPointerDown);
|
||||
this.canvas.addEventListener("pointermove", this.onOrbitPointerMove);
|
||||
this.canvas.addEventListener("pointerup", this.onOrbitPointerUp);
|
||||
this.canvas.addEventListener("pointercancel", this.onOrbitPointerUp);
|
||||
this.canvas.addEventListener("wheel", this.onOrbitWheel, { passive: false });
|
||||
}
|
||||
|
||||
private detachInput(): void {
|
||||
window.removeEventListener("keydown", this.onKeyDown, true);
|
||||
window.removeEventListener("keyup", this.onKeyUp, true);
|
||||
window.removeEventListener("blur", this.onWindowBlur);
|
||||
this.canvas.removeEventListener("pointerdown", this.onOrbitPointerDown);
|
||||
this.canvas.removeEventListener("pointermove", this.onOrbitPointerMove);
|
||||
this.canvas.removeEventListener("pointerup", this.onOrbitPointerUp);
|
||||
this.canvas.removeEventListener("pointercancel", this.onOrbitPointerUp);
|
||||
this.canvas.removeEventListener("wheel", this.onOrbitWheel);
|
||||
this.releaseOrbitPointer();
|
||||
}
|
||||
|
||||
private onOrbitPointerDown = (event: PointerEvent): void => {
|
||||
if (!this.active || event.button !== 0 || this.orbitPointerId !== null) return;
|
||||
event.preventDefault();
|
||||
this.orbitPointerId = event.pointerId;
|
||||
this.orbitPointerX = event.clientX;
|
||||
this.orbitPointerY = event.clientY;
|
||||
this.orbitIdleSeconds = 0;
|
||||
this.canvas.classList.add("is-orbiting");
|
||||
try {
|
||||
this.canvas.setPointerCapture(event.pointerId);
|
||||
} catch {
|
||||
// A browser may already have released the pointer during a window transition.
|
||||
}
|
||||
};
|
||||
|
||||
private onOrbitPointerMove = (event: PointerEvent): void => {
|
||||
if (!this.active || event.pointerId !== this.orbitPointerId) return;
|
||||
event.preventDefault();
|
||||
const deltaX = event.clientX - this.orbitPointerX;
|
||||
const deltaY = event.clientY - this.orbitPointerY;
|
||||
this.orbitPointerX = event.clientX;
|
||||
this.orbitPointerY = event.clientY;
|
||||
this.orbitIdleSeconds = 0;
|
||||
this.orbitYaw = (this.orbitYaw - deltaX * 0.006) % (Math.PI * 2);
|
||||
this.orbitPitch = clamp(this.orbitPitch + deltaY * 0.0045, -0.12, 1.32);
|
||||
};
|
||||
|
||||
private onOrbitPointerUp = (event: PointerEvent): void => {
|
||||
if (event.pointerId !== this.orbitPointerId) return;
|
||||
this.releaseOrbitPointer();
|
||||
};
|
||||
|
||||
private onOrbitWheel = (event: WheelEvent): void => {
|
||||
if (!this.active) return;
|
||||
event.preventDefault();
|
||||
this.orbitIdleSeconds = 0;
|
||||
this.orbitDistance = clamp(
|
||||
this.orbitDistance * Math.exp(event.deltaY * 0.0012),
|
||||
1.6,
|
||||
14,
|
||||
);
|
||||
};
|
||||
|
||||
private releaseOrbitPointer(): void {
|
||||
const pointerId = this.orbitPointerId;
|
||||
this.orbitPointerId = null;
|
||||
this.canvas.classList.remove("is-orbiting");
|
||||
if (pointerId === null || !this.canvas.hasPointerCapture(pointerId)) return;
|
||||
try {
|
||||
this.canvas.releasePointerCapture(pointerId);
|
||||
} catch {
|
||||
// Pointer capture is already gone; the local orbit state is still released.
|
||||
}
|
||||
}
|
||||
|
||||
private onKeyDown = (event: KeyboardEvent): void => {
|
||||
if (!this.active || isTextEntry(event.target)) return;
|
||||
if (!UGV_KEYS.has(event.code)) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.code === "KeyR") {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
this.pressed.add(event.code);
|
||||
};
|
||||
|
||||
private onKeyUp = (event: KeyboardEvent): void => {
|
||||
if (!this.active || !UGV_KEYS.has(event.code)) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.pressed.delete(event.code);
|
||||
};
|
||||
|
||||
private onWindowBlur = (): void => {
|
||||
this.pressed.clear();
|
||||
this.releaseOrbitPointer();
|
||||
};
|
||||
}
|
||||
|
||||
const UGV_KEYS = new Set([
|
||||
"KeyW",
|
||||
"KeyA",
|
||||
"KeyS",
|
||||
"KeyD",
|
||||
"ArrowUp",
|
||||
"ArrowDown",
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
"Space",
|
||||
"KeyR",
|
||||
]);
|
||||
|
||||
function createPhysicsProxyMesh(
|
||||
app: Application,
|
||||
source: Mesh,
|
||||
localTransform: Mat4,
|
||||
targetRatio: number,
|
||||
): Mesh | null {
|
||||
const primitive = source.primitive[0];
|
||||
const sourceVertexCount = source.vertexBuffer?.numVertices ?? 0;
|
||||
if (!primitive || sourceVertexCount === 0 || primitive.count < 3) return null;
|
||||
|
||||
const positions = new Float32Array(sourceVertexCount * 3);
|
||||
const populatedVertices = source.getPositions(positions);
|
||||
if (populatedVertices === 0) return null;
|
||||
const transformed = new Float32Array(populatedVertices * 3);
|
||||
const point = new Vec3();
|
||||
for (let vertex = 0; vertex < populatedVertices; vertex += 1) {
|
||||
const offset = vertex * 3;
|
||||
point.set(positions[offset], positions[offset + 1], positions[offset + 2]);
|
||||
localTransform.transformPoint(point, point);
|
||||
transformed[offset] = point.x;
|
||||
transformed[offset + 1] = point.y;
|
||||
transformed[offset + 2] = point.z;
|
||||
}
|
||||
|
||||
const requestedIndexCount = Math.max(3, primitive.count);
|
||||
let indices = new Uint32Array(requestedIndexCount);
|
||||
const populatedIndices = source.getIndices(indices);
|
||||
if (populatedIndices === 0) {
|
||||
const fallbackCount = Math.min(populatedVertices, requestedIndexCount);
|
||||
indices = new Uint32Array(fallbackCount);
|
||||
for (let index = 0; index < fallbackCount; index += 1) indices[index] = index;
|
||||
} else if (populatedIndices !== indices.length) {
|
||||
indices = indices.slice(0, populatedIndices);
|
||||
}
|
||||
const triangleIndexCount = Math.floor(indices.length / 3) * 3;
|
||||
if (triangleIndexCount < 3) return null;
|
||||
if (triangleIndexCount !== indices.length) indices = indices.slice(0, triangleIndexCount);
|
||||
|
||||
if (targetRatio < 1) {
|
||||
const targetIndexCount = Math.max(3, Math.floor(indices.length * targetRatio / 3) * 3);
|
||||
const [simplifiedIndices] = MeshoptSimplifier.simplify(
|
||||
indices,
|
||||
transformed,
|
||||
3,
|
||||
targetIndexCount,
|
||||
PHYSICS_PROXY_ERROR,
|
||||
);
|
||||
indices = new Uint32Array(simplifiedIndices);
|
||||
}
|
||||
|
||||
const compactedIndices = new Uint32Array(indices);
|
||||
const [remap, compactedVertexCount] = MeshoptSimplifier.compactMesh(compactedIndices);
|
||||
const compactedPositions = new Float32Array(compactedVertexCount * 3);
|
||||
const missing = 0xffff_ffff;
|
||||
for (let sourceVertex = 0; sourceVertex < remap.length; sourceVertex += 1) {
|
||||
const compactedVertex = remap[sourceVertex];
|
||||
if (compactedVertex === missing) continue;
|
||||
const sourceOffset = sourceVertex * 3;
|
||||
const compactedOffset = compactedVertex * 3;
|
||||
compactedPositions[compactedOffset] = transformed[sourceOffset];
|
||||
compactedPositions[compactedOffset + 1] = transformed[sourceOffset + 1];
|
||||
compactedPositions[compactedOffset + 2] = transformed[sourceOffset + 2];
|
||||
}
|
||||
|
||||
const physicsMesh = new Mesh(app.graphicsDevice);
|
||||
physicsMesh.setPositions(compactedPositions);
|
||||
physicsMesh.setIndices(compactedIndices);
|
||||
physicsMesh.update(PRIMITIVE_TRIANGLES, true);
|
||||
return physicsMesh;
|
||||
}
|
||||
|
||||
function cloneUgvPreset(preset: SimulationUgvPreset): SimulationUgvPreset {
|
||||
return {
|
||||
...preset,
|
||||
dimensionsMeters: { ...preset.dimensionsMeters },
|
||||
};
|
||||
}
|
||||
|
||||
function vehicleGeometryChanged(
|
||||
current: SimulationUgvPreset,
|
||||
next: SimulationUgvPreset,
|
||||
): boolean {
|
||||
return current.massKg !== next.massKg
|
||||
|| current.dimensionsMeters.length !== next.dimensionsMeters.length
|
||||
|| current.dimensionsMeters.width !== next.dimensionsMeters.width
|
||||
|| current.dimensionsMeters.height !== next.dimensionsMeters.height
|
||||
|| current.dimensionsMeters.groundClearance !== next.dimensionsMeters.groundClearance;
|
||||
}
|
||||
|
||||
function vehicleDimensions(settings: SimulationUgvPreset) {
|
||||
const { length, width, height, groundClearance } = settings.dimensionsMeters;
|
||||
const bodyHeight = height - groundClearance;
|
||||
const wheelRadius = clamp(
|
||||
groundClearance * 0.8,
|
||||
0.07,
|
||||
Math.min(height * 0.4, length * 0.22),
|
||||
);
|
||||
const wheelThickness = clamp(width * 0.13, 0.08, 0.16);
|
||||
const bodyWidth = Math.max(0.12, width - wheelThickness * 2);
|
||||
const mainHeight = bodyHeight * 0.68;
|
||||
const equipmentHeight = bodyHeight - mainHeight;
|
||||
const suspensionRestLength = clamp(groundClearance * 0.4, 0.04, 0.16);
|
||||
const originHeight = groundClearance + bodyHeight / 2;
|
||||
return {
|
||||
length,
|
||||
width,
|
||||
bodyWidth,
|
||||
mainHeight,
|
||||
equipmentHeight,
|
||||
mainCenterY: -bodyHeight / 2 + mainHeight / 2,
|
||||
equipmentCenterY: bodyHeight / 2 - equipmentHeight / 2,
|
||||
wheelRadius,
|
||||
wheelThickness,
|
||||
wheelX: width / 2 - wheelThickness / 2,
|
||||
wheelZ: Math.max(0, length / 2 - wheelRadius),
|
||||
wheelConnectionY: suspensionRestLength + wheelRadius - originHeight,
|
||||
suspensionRestLength,
|
||||
originHeight,
|
||||
};
|
||||
}
|
||||
|
||||
function createBox(name: string, scale: Vec3, material: StandardMaterial): Entity {
|
||||
const entity = new Entity(name);
|
||||
entity.addComponent("render", { type: "box", castShadows: false, receiveShadows: false });
|
||||
entity.setLocalScale(scale);
|
||||
applyMaterial(entity, material);
|
||||
return entity;
|
||||
}
|
||||
|
||||
function applyMaterial(entity: Entity, material: StandardMaterial): void {
|
||||
for (const meshInstance of entity.render?.meshInstances ?? []) meshInstance.material = material;
|
||||
}
|
||||
|
||||
function createMaterial(diffuse: Color, emissive: Color): StandardMaterial {
|
||||
const material = new StandardMaterial();
|
||||
material.diffuse = diffuse;
|
||||
material.emissive = emissive;
|
||||
material.metalness = 0.15;
|
||||
material.gloss = 0.32;
|
||||
material.update();
|
||||
return material;
|
||||
}
|
||||
|
||||
function readThemeAccent(): Color {
|
||||
const raw = getComputedStyle(document.documentElement).getPropertyValue("--nodedc-accent-rgb");
|
||||
const channels = raw.trim().split(/[\s,]+/).map(Number);
|
||||
if (channels.length < 3 || channels.some((value) => !Number.isFinite(value))) {
|
||||
return new Color(0.22, 0.72, 0.38);
|
||||
}
|
||||
return new Color(channels[0] / 255, channels[1] / 255, channels[2] / 255);
|
||||
}
|
||||
|
||||
function isTextEntry(target: EventTarget | null): boolean {
|
||||
return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement
|
||||
|| target instanceof HTMLSelectElement || target instanceof HTMLButtonElement
|
||||
|| (target instanceof HTMLElement && target.isContentEditable);
|
||||
}
|
||||
|
||||
function clamp(value: number, min: number, max: number): number { return Math.max(min, Math.min(max, value)); }
|
||||
function approach(current: number, target: number, maximumDelta: number): number {
|
||||
if (current < target) return Math.min(target, current + maximumDelta);
|
||||
if (current > target) return Math.max(target, current - maximumDelta);
|
||||
return target;
|
||||
}
|
||||
function approachAngle(current: number, target: number, maximumDelta: number): number {
|
||||
const delta = ((target - current + Math.PI) % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2) - Math.PI;
|
||||
return current + clamp(delta, -maximumDelta, maximumDelta);
|
||||
}
|
||||
function runCleanup(label: string, cleanup: () => void): void {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
console.warn(`[Simulation UGV] Cleanup failed: ${label}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
function nextAnimationFrame(): Promise<void> { return new Promise((resolve) => requestAnimationFrame(() => resolve())); }
|
||||
@@ -0,0 +1,191 @@
|
||||
import {
|
||||
Button,
|
||||
Icon,
|
||||
RangeControl,
|
||||
Switch,
|
||||
TextField,
|
||||
} from "@nodedc/ui-react";
|
||||
|
||||
import {
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS,
|
||||
type SimulationUgvPreset,
|
||||
} from "../../core/simulation/projects";
|
||||
|
||||
export type SimulationUgvPresetSaveState = "idle" | "saving" | "saved" | "failed";
|
||||
|
||||
export function SimulationUgvSettingsPanel({
|
||||
value,
|
||||
disabled,
|
||||
saveState,
|
||||
onChange,
|
||||
onSave,
|
||||
}: {
|
||||
value: SimulationUgvPreset;
|
||||
disabled: boolean;
|
||||
saveState: SimulationUgvPresetSaveState;
|
||||
onChange: (preset: SimulationUgvPreset) => void;
|
||||
onSave: () => void;
|
||||
}) {
|
||||
const dimensions = value.dimensionsMeters;
|
||||
const updateDimensions = (
|
||||
patch: Partial<SimulationUgvPreset["dimensionsMeters"]>,
|
||||
) => {
|
||||
const next = { ...dimensions, ...patch };
|
||||
next.groundClearance = Math.max(
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.groundClearance.min,
|
||||
Math.min(next.groundClearance, roundToHundredth(next.height - 0.05)),
|
||||
);
|
||||
onChange({ ...value, dimensionsMeters: next });
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="simulation-viewport__settings-group simulation-ugv-settings">
|
||||
<div className="simulation-viewport__settings-group-head">
|
||||
<strong>Физика UGV</strong>
|
||||
<span>Дифференциальный привод</span>
|
||||
</div>
|
||||
<p>
|
||||
A/D без W/S разворачивают UGV вокруг собственного центра. Скорость и
|
||||
динамика применяются сразу. Мышь вращает камеру вокруг машины, колесо
|
||||
меняет дистанцию; после паузы камера плавно возвращается назад. Ползунок
|
||||
работает в штатном диапазоне, точное значение можно ввести вручную.
|
||||
</p>
|
||||
<TextField
|
||||
label="Название пресета"
|
||||
value={value.presetName}
|
||||
maxLength={80}
|
||||
disabled={disabled}
|
||||
spellCheck={false}
|
||||
onChange={(event) => onChange({ ...value, presetName: event.currentTarget.value })}
|
||||
/>
|
||||
<RangeControl
|
||||
label="Масса конструкции"
|
||||
value={value.massKg}
|
||||
min={10}
|
||||
max={500}
|
||||
exactValueBounds={SIMULATION_UGV_EXACT_VALUE_LIMITS.massKg}
|
||||
step={5}
|
||||
disabled={disabled}
|
||||
formatValue={(mass) => `${Math.round(mass)} кг`}
|
||||
onChange={(massKg) => onChange({ ...value, massKg })}
|
||||
/>
|
||||
<div className="simulation-ugv-settings__subhead">
|
||||
<strong>Габариты</strong>
|
||||
<span>В метрах</span>
|
||||
</div>
|
||||
<RangeControl
|
||||
label="Длина"
|
||||
value={dimensions.length}
|
||||
min={0.4}
|
||||
max={3}
|
||||
exactValueBounds={SIMULATION_UGV_EXACT_VALUE_LIMITS.length}
|
||||
step={0.05}
|
||||
disabled={disabled}
|
||||
formatValue={formatMeters}
|
||||
onChange={(length) => updateDimensions({ length })}
|
||||
/>
|
||||
<RangeControl
|
||||
label="Ширина"
|
||||
value={dimensions.width}
|
||||
min={0.3}
|
||||
max={2}
|
||||
exactValueBounds={SIMULATION_UGV_EXACT_VALUE_LIMITS.width}
|
||||
step={0.05}
|
||||
disabled={disabled}
|
||||
formatValue={formatMeters}
|
||||
onChange={(width) => updateDimensions({ width })}
|
||||
/>
|
||||
<RangeControl
|
||||
label="Общая высота"
|
||||
value={dimensions.height}
|
||||
min={0.2}
|
||||
max={2}
|
||||
exactValueBounds={SIMULATION_UGV_EXACT_VALUE_LIMITS.height}
|
||||
step={0.05}
|
||||
disabled={disabled}
|
||||
formatValue={formatMeters}
|
||||
onChange={(height) => updateDimensions({ height })}
|
||||
/>
|
||||
<RangeControl
|
||||
label="Клиренс"
|
||||
value={dimensions.groundClearance}
|
||||
min={0.03}
|
||||
max={Math.max(0.03, Math.min(0.6, dimensions.height - 0.05))}
|
||||
exactValueBounds={{
|
||||
min: SIMULATION_UGV_EXACT_VALUE_LIMITS.groundClearance.min,
|
||||
max: Math.min(
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.groundClearance.max,
|
||||
dimensions.height - 0.05,
|
||||
),
|
||||
}}
|
||||
step={0.01}
|
||||
disabled={disabled}
|
||||
formatValue={formatMeters}
|
||||
onChange={(groundClearance) => updateDimensions({ groundClearance })}
|
||||
/>
|
||||
<div className="simulation-ugv-settings__subhead">
|
||||
<strong>Динамика</strong>
|
||||
<span>Ограничители движения</span>
|
||||
</div>
|
||||
<RangeControl
|
||||
label="Скорость движения"
|
||||
value={value.maxSpeedMetersPerSecond}
|
||||
min={0.1}
|
||||
max={8}
|
||||
exactValueBounds={SIMULATION_UGV_EXACT_VALUE_LIMITS.maxSpeedMetersPerSecond}
|
||||
step={0.1}
|
||||
disabled={disabled}
|
||||
formatValue={(speed) => `${formatDecimal(speed, 1)} м/с`}
|
||||
onChange={(maxSpeedMetersPerSecond) => onChange({
|
||||
...value,
|
||||
maxSpeedMetersPerSecond,
|
||||
})}
|
||||
/>
|
||||
<RangeControl
|
||||
label="Скорость разворота"
|
||||
value={value.maxTurnRateDegrees}
|
||||
min={5}
|
||||
max={180}
|
||||
exactValueBounds={SIMULATION_UGV_EXACT_VALUE_LIMITS.maxTurnRateDegrees}
|
||||
step={5}
|
||||
disabled={disabled}
|
||||
formatValue={(rate) => `${Math.round(rate)}°/с`}
|
||||
onChange={(maxTurnRateDegrees) => onChange({ ...value, maxTurnRateDegrees })}
|
||||
/>
|
||||
<Switch
|
||||
checked={value.invertSteering}
|
||||
disabled={disabled}
|
||||
label="Инверсия управления A/D"
|
||||
onChange={(invertSteering) => onChange({ ...value, invertSteering })}
|
||||
/>
|
||||
<Button
|
||||
className="simulation-ugv-settings__save"
|
||||
size="compact"
|
||||
variant="secondary"
|
||||
icon={<Icon name="save" size={16} />}
|
||||
disabled={disabled || saveState === "saving" || value.presetName.trim() === ""}
|
||||
onClick={onSave}
|
||||
>
|
||||
{saveState === "saving"
|
||||
? "Сохраняем…"
|
||||
: saveState === "saved"
|
||||
? "Пресет сохранён"
|
||||
: saveState === "failed"
|
||||
? "Повторить сохранение"
|
||||
: "Сохранить пресет"}
|
||||
</Button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function formatMeters(value: number): string {
|
||||
return `${formatDecimal(value, 2)} м`;
|
||||
}
|
||||
|
||||
function formatDecimal(value: number, digits: number): string {
|
||||
return value.toFixed(digits).replace(".", ",");
|
||||
}
|
||||
|
||||
function roundToHundredth(value: number): number {
|
||||
return Math.round(value * 100) / 100;
|
||||
}
|
||||
@@ -0,0 +1,591 @@
|
||||
import { useEffect, useId, useRef, useState } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
GlassMaterialSurface,
|
||||
Icon,
|
||||
IconButton,
|
||||
SegmentedControl,
|
||||
Select,
|
||||
StatusBadge,
|
||||
Switch,
|
||||
TextField,
|
||||
} from "@nodedc/ui-react";
|
||||
|
||||
import {
|
||||
saveSimulationViewerSettings,
|
||||
type SimulationEulerRotation,
|
||||
type SimulationProject,
|
||||
type SimulationUgvPreset,
|
||||
type SimulationViewerSettings,
|
||||
} from "../../core/simulation/projects";
|
||||
import {
|
||||
createLatestAsyncCommitter,
|
||||
type LatestAsyncCommitter,
|
||||
} from "../../core/runtime/latestAsyncCommitter";
|
||||
import {
|
||||
PlayCanvasRuntime,
|
||||
playCanvasEulerTransform,
|
||||
type SimulationControlMode,
|
||||
type SimulationQuality,
|
||||
type SimulationViewMode,
|
||||
} from "./PlayCanvasRuntime";
|
||||
import {
|
||||
SimulationUgvSettingsPanel,
|
||||
type SimulationUgvPresetSaveState,
|
||||
} from "./SimulationUgvSettingsPanel";
|
||||
|
||||
const ROTATION_AXES = ["x", "y", "z"] as const;
|
||||
|
||||
export function SimulationViewport({
|
||||
project,
|
||||
onProjectChange,
|
||||
}: {
|
||||
project: SimulationProject;
|
||||
onProjectChange?: (project: SimulationProject) => void;
|
||||
}) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const runtimeRef = useRef<PlayCanvasRuntime | null>(null);
|
||||
const viewerSettingsRef = useRef(project.viewerSettings);
|
||||
const settingsCommitterRef = useRef<LatestAsyncCommitter<SimulationViewerSettings> | null>(null);
|
||||
const settingsCommitSucceededRef = useRef(true);
|
||||
const ugvSaveRequestRef = useRef(0);
|
||||
const controlRequestRef = useRef(0);
|
||||
const settingsId = useId();
|
||||
const [state, setState] = useState<"mounting" | "loading" | "ready" | "failed">("mounting");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [viewMode, setViewMode] = useState<SimulationViewMode>("visual");
|
||||
const [controlMode, setControlMode] = useState<SimulationControlMode>("free");
|
||||
const [controlState, setControlState] = useState<"idle" | "loading" | "ready" | "failed">("idle");
|
||||
const [quality, setQuality] = useState<SimulationQuality>(project.viewerSettings.quality);
|
||||
const [collisionState, setCollisionState] = useState<"idle" | "loading" | "ready" | "failed">("idle");
|
||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||
const [visualRotation, setVisualRotation] = useState({
|
||||
...project.viewerSettings.visual.rotationDegrees,
|
||||
});
|
||||
const [collisionRotation, setCollisionRotation] = useState({
|
||||
...project.viewerSettings.collision.rotationDegrees,
|
||||
});
|
||||
const [horizontalInverted, setHorizontalInverted] = useState(
|
||||
project.viewerSettings.camera.invertHorizontal,
|
||||
);
|
||||
const [verticalInverted, setVerticalInverted] = useState(
|
||||
project.viewerSettings.camera.invertVertical,
|
||||
);
|
||||
const [ugvDraft, setUgvDraft] = useState<SimulationUgvPreset>(() =>
|
||||
cloneUgvPreset(project.viewerSettings.ugv),
|
||||
);
|
||||
const [ugvSaveState, setUgvSaveState] = useState<SimulationUgvPresetSaveState>("idle");
|
||||
const [settingsError, setSettingsError] = useState<string | null>(null);
|
||||
const worldManifestRevision = JSON.stringify(project.worldManifest);
|
||||
|
||||
useEffect(() => {
|
||||
const settings = project.viewerSettings;
|
||||
viewerSettingsRef.current = settings;
|
||||
setQuality(settings.quality);
|
||||
setVisualRotation({ ...settings.visual.rotationDegrees });
|
||||
setCollisionRotation({ ...settings.collision.rotationDegrees });
|
||||
setHorizontalInverted(settings.camera.invertHorizontal);
|
||||
setVerticalInverted(settings.camera.invertVertical);
|
||||
setUgvDraft(cloneUgvPreset(settings.ugv));
|
||||
setUgvSaveState("idle");
|
||||
ugvSaveRequestRef.current += 1;
|
||||
setSettingsError(null);
|
||||
setSettingsOpen(false);
|
||||
controlRequestRef.current += 1;
|
||||
setControlMode("free");
|
||||
setControlState("idle");
|
||||
}, [project.projectId]);
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
const committer = createLatestAsyncCommitter<SimulationViewerSettings>({
|
||||
async commit(settings) {
|
||||
try {
|
||||
const saved = await saveSimulationViewerSettings(project.projectId, settings);
|
||||
settingsCommitSucceededRef.current = true;
|
||||
if (active) onProjectChange?.(saved);
|
||||
return true;
|
||||
} catch (caught) {
|
||||
settingsCommitSucceededRef.current = false;
|
||||
if (active) {
|
||||
setSettingsError(
|
||||
caught instanceof Error ? caught.message : "Не удалось сохранить настройки сцены.",
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSettled({ applied, superseded }) {
|
||||
if (active && applied && !superseded) setSettingsError(null);
|
||||
},
|
||||
});
|
||||
settingsCommitterRef.current = committer;
|
||||
return () => {
|
||||
active = false;
|
||||
committer.dispose();
|
||||
if (settingsCommitterRef.current === committer) settingsCommitterRef.current = null;
|
||||
};
|
||||
}, [onProjectChange, project.projectId]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
const manifest = project.worldManifest;
|
||||
if (!canvas || !manifest) return;
|
||||
const runtime = new PlayCanvasRuntime();
|
||||
runtimeRef.current = runtime;
|
||||
let cancelled = false;
|
||||
setState("mounting");
|
||||
setError(null);
|
||||
void runtime.mount(canvas).then(async () => {
|
||||
if (cancelled) return;
|
||||
const settings = viewerSettingsRef.current;
|
||||
runtime.setQuality(settings.quality);
|
||||
runtime.setCameraInversion("horizontal", settings.camera.invertHorizontal);
|
||||
runtime.setCameraInversion("vertical", settings.camera.invertVertical);
|
||||
runtime.setUgvPreset(settings.ugv);
|
||||
setState("loading");
|
||||
await runtime.loadWorld(manifest);
|
||||
runtime.setLayerWorldTransform(
|
||||
"visual",
|
||||
playCanvasEulerTransform(settings.visual.rotationDegrees),
|
||||
);
|
||||
runtime.setLayerWorldTransform(
|
||||
"collision",
|
||||
playCanvasEulerTransform(settings.collision.rotationDegrees),
|
||||
);
|
||||
if (!cancelled) setState("ready");
|
||||
}).catch((caught: unknown) => {
|
||||
if (cancelled) return;
|
||||
setState("failed");
|
||||
setError(caught instanceof Error ? caught.message : "Не удалось открыть сцену.");
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
controlRequestRef.current += 1;
|
||||
runtime.dispose();
|
||||
runtimeRef.current = null;
|
||||
};
|
||||
// Saving viewer preferences returns a fresh project object. Restart the GPU
|
||||
// runtime only when the manifest content changes, not when its object identity
|
||||
// changes after an otherwise unrelated settings PUT.
|
||||
}, [project.projectId, worldManifestRevision]);
|
||||
|
||||
const collisionAvailable = project.worldManifest?.collision.available ?? false;
|
||||
const commitViewerSettings = (settings: SimulationViewerSettings) => {
|
||||
viewerSettingsRef.current = settings;
|
||||
settingsCommitSucceededRef.current = false;
|
||||
settingsCommitterRef.current?.enqueue(settings);
|
||||
};
|
||||
|
||||
const changeUgvDraft = (next: SimulationUgvPreset) => {
|
||||
setUgvDraft(cloneUgvPreset(next));
|
||||
setUgvSaveState("idle");
|
||||
ugvSaveRequestRef.current += 1;
|
||||
runtimeRef.current?.setUgvPreset(next);
|
||||
};
|
||||
|
||||
const saveUgvPreset = () => {
|
||||
const committer = settingsCommitterRef.current;
|
||||
if (!committer) {
|
||||
setUgvSaveState("failed");
|
||||
return;
|
||||
}
|
||||
const request = ++ugvSaveRequestRef.current;
|
||||
const normalized = cloneUgvPreset({
|
||||
...ugvDraft,
|
||||
presetName: ugvDraft.presetName.trim(),
|
||||
});
|
||||
setUgvDraft(normalized);
|
||||
setUgvSaveState("saving");
|
||||
setSettingsError(null);
|
||||
settingsCommitSucceededRef.current = false;
|
||||
const settings = { ...viewerSettingsRef.current, ugv: normalized };
|
||||
viewerSettingsRef.current = settings;
|
||||
committer.enqueue(settings);
|
||||
void committer.waitForIdle().then(() => {
|
||||
if (request !== ugvSaveRequestRef.current) return;
|
||||
setUgvSaveState(settingsCommitSucceededRef.current ? "saved" : "failed");
|
||||
});
|
||||
};
|
||||
|
||||
const changeControlMode = (next: SimulationControlMode) => {
|
||||
const runtime = runtimeRef.current;
|
||||
if (!runtime) return;
|
||||
const request = ++controlRequestRef.current;
|
||||
setControlMode(next);
|
||||
setControlState(next === "ugv" ? "loading" : "idle");
|
||||
if (next === "ugv" && collisionState !== "ready") setCollisionState("loading");
|
||||
void runtime.setControlMode(next).then(() => {
|
||||
if (request !== controlRequestRef.current) return;
|
||||
if (next === "ugv") {
|
||||
setControlState("ready");
|
||||
setCollisionState("ready");
|
||||
}
|
||||
}).catch((caught: unknown) => {
|
||||
if (request !== controlRequestRef.current) return;
|
||||
setControlMode("free");
|
||||
setControlState("failed");
|
||||
setCollisionState("failed");
|
||||
setError(caught instanceof Error ? caught.message : "Не удалось запустить UGV.");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
className="simulation-viewport"
|
||||
data-control-mode={controlMode}
|
||||
aria-label={`Сцена ${project.name}`}
|
||||
>
|
||||
<header className="simulation-viewport__toolbar">
|
||||
<div>
|
||||
<StatusBadge tone={state === "failed" || collisionState === "failed" ? "warning" : state === "ready" && collisionState !== "loading" ? "success" : "accent"}>
|
||||
{controlState === "loading"
|
||||
? "Подготовка UGV"
|
||||
: controlState === "ready"
|
||||
? "UGV готов"
|
||||
: controlState === "failed"
|
||||
? "Ошибка UGV"
|
||||
: collisionState === "loading"
|
||||
? "Загрузка коллизий"
|
||||
: collisionState === "failed"
|
||||
? "Ошибка коллизий"
|
||||
: state === "ready"
|
||||
? "Runtime готов"
|
||||
: state === "failed"
|
||||
? "Ошибка runtime"
|
||||
: "Загрузка локации"}
|
||||
</StatusBadge>
|
||||
<span>Engine 2.21.4</span>
|
||||
</div>
|
||||
<div className="simulation-viewport__controls">
|
||||
<Select
|
||||
label="Качество Gaussian-сцены"
|
||||
value={quality}
|
||||
onChange={(next) => {
|
||||
setQuality(next);
|
||||
runtimeRef.current?.setQuality(next);
|
||||
commitViewerSettings({ ...viewerSettingsRef.current, quality: next });
|
||||
}}
|
||||
options={[
|
||||
{ value: "maximum", label: "Максимум", description: "До 4 млн сплатов · Retina до 2× · 60 FPS" },
|
||||
{ value: "ultra", label: "Ультра", description: "До 2,5 млн · Retina до 1,5× · 60 FPS" },
|
||||
{ value: "high", label: "Высокое", description: "До 1,2 млн · Retina до 1,25× · 60 FPS" },
|
||||
{ value: "medium", label: "Среднее", description: "До 700 тыс. · 1× · 45 FPS" },
|
||||
{ value: "low", label: "Низкое", description: "До 350 тыс. · 0,75× · 30 FPS" },
|
||||
]}
|
||||
minMenuWidth={230}
|
||||
menuWidth={230}
|
||||
/>
|
||||
<Select
|
||||
label="Режим управления"
|
||||
value={controlMode}
|
||||
disabled={state !== "ready" || controlState === "loading"}
|
||||
onChange={changeControlMode}
|
||||
options={[
|
||||
{
|
||||
value: "free",
|
||||
label: "Свободно",
|
||||
description: "Свободная камера и навигация",
|
||||
},
|
||||
{
|
||||
value: "ugv",
|
||||
label: "UGV",
|
||||
description: "WASD/стрелки · пробел — тормоз · R — домой",
|
||||
disabled: !collisionAvailable,
|
||||
},
|
||||
]}
|
||||
minMenuWidth={250}
|
||||
menuWidth={250}
|
||||
/>
|
||||
<SegmentedControl
|
||||
label="Слой сцены"
|
||||
value={viewMode}
|
||||
onChange={(next) => {
|
||||
setViewMode(next);
|
||||
const runtime = runtimeRef.current;
|
||||
if (!runtime) return;
|
||||
if (next !== "visual" && collisionAvailable && collisionState !== "ready") {
|
||||
setCollisionState("loading");
|
||||
}
|
||||
void runtime.setViewMode(next).then(() => {
|
||||
if (next !== "visual") setCollisionState("ready");
|
||||
}).catch((caught: unknown) => {
|
||||
setCollisionState("failed");
|
||||
setError(caught instanceof Error ? caught.message : "Не удалось открыть слой коллизий.");
|
||||
});
|
||||
}}
|
||||
items={[
|
||||
{ value: "visual", label: "Визуал" },
|
||||
{ value: "collision", label: "Коллизии", disabled: !collisionAvailable },
|
||||
{ value: "combined", label: "Вместе", disabled: !collisionAvailable },
|
||||
]}
|
||||
/>
|
||||
<Button size="compact" variant="secondary" onClick={() => runtimeRef.current?.home()}>
|
||||
Домой
|
||||
</Button>
|
||||
<div className="simulation-viewport__settings-anchor">
|
||||
<IconButton
|
||||
label="Настройки сцены"
|
||||
aria-controls={settingsId}
|
||||
aria-expanded={settingsOpen}
|
||||
aria-pressed={settingsOpen}
|
||||
onClick={() => setSettingsOpen((open) => !open)}
|
||||
>
|
||||
<Icon name="settings" size={18} />
|
||||
</IconButton>
|
||||
{settingsOpen ? (
|
||||
<GlassMaterialSurface
|
||||
id={settingsId}
|
||||
className="simulation-viewport__settings"
|
||||
role="dialog"
|
||||
aria-label="Настройки сцены"
|
||||
>
|
||||
<div className="simulation-viewport__settings-head">
|
||||
<div>
|
||||
<strong>Настройки сцены</strong>
|
||||
<span>Локация, камера и UGV</span>
|
||||
</div>
|
||||
<IconButton label="Закрыть настройки" onClick={() => setSettingsOpen(false)}>
|
||||
<Icon name="close" size={16} />
|
||||
</IconButton>
|
||||
</div>
|
||||
<div className="simulation-viewport__settings-scroll">
|
||||
<section className="simulation-viewport__settings-group">
|
||||
<div className="simulation-viewport__settings-group-head">
|
||||
<strong>Система координат</strong>
|
||||
<span>Мир сцены · Y вверх</span>
|
||||
</div>
|
||||
<p>
|
||||
Коррекция слоёв не меняет координаты камеры, навигации и будущей физики.
|
||||
</p>
|
||||
<div className="simulation-viewport__settings-rotations">
|
||||
<LayerRotationFields
|
||||
label="Гауссовый слой"
|
||||
value={visualRotation}
|
||||
disabled={state !== "ready"}
|
||||
onChange={(next) => {
|
||||
setVisualRotation(next);
|
||||
runtimeRef.current?.setLayerWorldTransform(
|
||||
"visual",
|
||||
playCanvasEulerTransform(next),
|
||||
);
|
||||
commitViewerSettings({
|
||||
...viewerSettingsRef.current,
|
||||
visual: { rotationDegrees: next },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<LayerRotationFields
|
||||
label="Слой коллизий"
|
||||
value={collisionRotation}
|
||||
disabled={state !== "ready"}
|
||||
onChange={(next) => {
|
||||
setCollisionRotation(next);
|
||||
runtimeRef.current?.setLayerWorldTransform(
|
||||
"collision",
|
||||
playCanvasEulerTransform(next),
|
||||
);
|
||||
commitViewerSettings({
|
||||
...viewerSettingsRef.current,
|
||||
collision: { rotationDegrees: next },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section className="simulation-viewport__settings-group">
|
||||
<div className="simulation-viewport__settings-group-head">
|
||||
<strong>Управление камерой</strong>
|
||||
<span>Мышь и тачпад</span>
|
||||
</div>
|
||||
<div className="simulation-viewport__settings-switches">
|
||||
<Switch
|
||||
checked={horizontalInverted}
|
||||
disabled={state !== "ready"}
|
||||
label="Инверсия управления по горизонтали"
|
||||
onChange={(checked) => {
|
||||
setHorizontalInverted(checked);
|
||||
runtimeRef.current?.setCameraInversion("horizontal", checked);
|
||||
commitViewerSettings({
|
||||
...viewerSettingsRef.current,
|
||||
camera: { ...viewerSettingsRef.current.camera, invertHorizontal: checked },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Switch
|
||||
checked={verticalInverted}
|
||||
disabled={state !== "ready"}
|
||||
label="Инверсия управления по вертикали"
|
||||
onChange={(checked) => {
|
||||
setVerticalInverted(checked);
|
||||
runtimeRef.current?.setCameraInversion("vertical", checked);
|
||||
commitViewerSettings({
|
||||
...viewerSettingsRef.current,
|
||||
camera: { ...viewerSettingsRef.current.camera, invertVertical: checked },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<SimulationUgvSettingsPanel
|
||||
value={ugvDraft}
|
||||
disabled={state !== "ready"}
|
||||
saveState={ugvSaveState}
|
||||
onChange={changeUgvDraft}
|
||||
onSave={saveUgvPreset}
|
||||
/>
|
||||
{settingsError ? (
|
||||
<p className="simulation-viewport__settings-error" role="alert">
|
||||
Настройки не сохранены: {settingsError}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
</GlassMaterialSurface>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<span className="simulation-viewport__toolbar-balance" aria-hidden="true" />
|
||||
</header>
|
||||
<div className="simulation-viewport__stage">
|
||||
<canvas ref={canvasRef} aria-label={`Сцена ${project.name}`} />
|
||||
{state !== "ready" ? (
|
||||
<div className="simulation-viewport__state" role={state === "failed" ? "alert" : "status"}>
|
||||
{state === "failed" ? null : <ActivityIndicator label="Загрузка локации" />}
|
||||
<strong>{state === "failed" ? "Локация не открылась" : "Загружаем локацию"}</strong>
|
||||
<p>{error ?? "LOD-уровни загружаются по мере готовности runtime."}</p>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{!collisionAvailable ? (
|
||||
<footer className="simulation-viewport__notice">
|
||||
<StatusBadge tone="warning">Коллизии недоступны</StatusBadge>
|
||||
<span>Для этой сборки слой коллизий не создавался; визуальный слой остаётся доступен.</span>
|
||||
</footer>
|
||||
) : collisionState === "failed" ? (
|
||||
<footer className="simulation-viewport__notice" role="alert">
|
||||
<StatusBadge tone="warning">Коллизии не открылись</StatusBadge>
|
||||
<span>{error ?? "Слой коллизий не загрузился."}</span>
|
||||
</footer>
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function cloneUgvPreset(preset: SimulationUgvPreset): SimulationUgvPreset {
|
||||
return {
|
||||
...preset,
|
||||
dimensionsMeters: { ...preset.dimensionsMeters },
|
||||
};
|
||||
}
|
||||
|
||||
function LayerRotationFields({
|
||||
label,
|
||||
value,
|
||||
disabled,
|
||||
onChange,
|
||||
}: {
|
||||
label: string;
|
||||
value: SimulationEulerRotation;
|
||||
disabled: boolean;
|
||||
onChange: (rotation: SimulationEulerRotation) => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="simulation-viewport__rotation-row">
|
||||
<strong>{label}</strong>
|
||||
<div className="simulation-viewport__rotation-fields">
|
||||
{ROTATION_AXES.map((axis) => (
|
||||
<RotationField
|
||||
key={axis}
|
||||
label={axis.toUpperCase()}
|
||||
ariaLabel={`${label}: вращение ${axis.toUpperCase()}`}
|
||||
value={value[axis]}
|
||||
disabled={disabled}
|
||||
onChange={(angle) => onChange({ ...value, [axis]: angle })}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RotationField({
|
||||
label,
|
||||
ariaLabel,
|
||||
value,
|
||||
disabled,
|
||||
onChange,
|
||||
}: {
|
||||
label: string;
|
||||
ariaLabel: string;
|
||||
value: number;
|
||||
disabled: boolean;
|
||||
onChange: (angle: number) => void;
|
||||
}) {
|
||||
const [draft, setDraft] = useState(() => String(value));
|
||||
const editingRef = useRef(false);
|
||||
const cancelNextBlurRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editingRef.current) setDraft(String(value));
|
||||
}, [value]);
|
||||
|
||||
const parsedDraft = () => Number(draft.trim().replace(",", "."));
|
||||
const finishEditing = (commit: boolean) => {
|
||||
const parsed = parsedDraft();
|
||||
if (commit && draft.trim() !== "" && Number.isFinite(parsed)) {
|
||||
const normalized = Math.max(-360, Math.min(360, parsed));
|
||||
onChange(normalized);
|
||||
setDraft(String(normalized));
|
||||
} else {
|
||||
setDraft(String(value));
|
||||
}
|
||||
editingRef.current = false;
|
||||
};
|
||||
|
||||
return (
|
||||
<TextField
|
||||
label={label}
|
||||
aria-label={ariaLabel}
|
||||
fieldClassName="simulation-viewport__rotation-field"
|
||||
className="simulation-viewport__rotation-input"
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
value={draft}
|
||||
disabled={disabled}
|
||||
spellCheck={false}
|
||||
onFocus={() => {
|
||||
editingRef.current = true;
|
||||
}}
|
||||
onChange={(event) => {
|
||||
// Treat the first input event as the start of editing as well. Programmatic
|
||||
// focus (and some browser/trackpad paths) may not deliver React's focus
|
||||
// event before the controlled value changes.
|
||||
editingRef.current = true;
|
||||
const nextDraft = event.currentTarget.value;
|
||||
setDraft(nextDraft);
|
||||
const parsed = Number(nextDraft.trim().replace(",", "."));
|
||||
if (nextDraft.trim() !== "" && Number.isFinite(parsed) && parsed >= -360 && parsed <= 360) {
|
||||
onChange(parsed);
|
||||
}
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
event.stopPropagation();
|
||||
if (event.key === "Enter") event.currentTarget.blur();
|
||||
if (event.key === "Escape") {
|
||||
event.preventDefault();
|
||||
cancelNextBlurRef.current = true;
|
||||
finishEditing(false);
|
||||
event.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (cancelNextBlurRef.current) {
|
||||
cancelNextBlurRef.current = false;
|
||||
return;
|
||||
}
|
||||
finishEditing(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -42,12 +42,28 @@ import {
|
||||
fetchM48LifecycleResult,
|
||||
} from "./m48ObjectCentricQuality";
|
||||
import { fetchM48SmallStaticRegression } from "./m48SmallStaticRegression";
|
||||
import { fetchM48StaticOccupancyQualification } from "./m48StaticOccupancyQualification";
|
||||
import { fetchM48R3StaticOccupancyShadow } from "./m48r3StaticOccupancyShadow";
|
||||
import { fetchM48SFixedClassDetectorResult } from "./m48sFixedClassDetector";
|
||||
import { fetchM48TRiskQualityResult } from "./m48tRiskQuality";
|
||||
import { fetchM49TgsFailClosedResult } from "./m49TgsFailClosed";
|
||||
import { fetchM49TgsFullShadowResult } from "./m49TgsFullShadow";
|
||||
import {
|
||||
fetchVegetationBenchmarkResult,
|
||||
fetchVegetationShadowResult,
|
||||
} from "./vegetationShadow";
|
||||
|
||||
export type AdvancedLaboratoryWorkId =
|
||||
| "lab-v1-vegetation-benchmark"
|
||||
| "lab-v1-vegetation-shadow"
|
||||
| "m48-object-centric-quality"
|
||||
| "m48-small-static-passage-regression"
|
||||
| "m48-static-occupancy-qualification"
|
||||
| "m48r3-static-occupancy-shadow"
|
||||
| "m48s-fixed-class-detector"
|
||||
| "m48t-risk-quality-temporal"
|
||||
| "m49-tgs-fail-closed-evidence"
|
||||
| "m49-tgs-full-shadow"
|
||||
| "m47-reference-graph-shadow"
|
||||
| "m4-replay-threat"
|
||||
| "l3-pointpillars-visual-audit"
|
||||
@@ -90,9 +106,16 @@ export interface AdvancedLaboratoryIndexItem {
|
||||
}
|
||||
|
||||
const WORK_IDS: readonly AdvancedLaboratoryWorkId[] = [
|
||||
"lab-v1-vegetation-benchmark",
|
||||
"lab-v1-vegetation-shadow",
|
||||
"m48-object-centric-quality",
|
||||
"m48-small-static-passage-regression",
|
||||
"m48-static-occupancy-qualification",
|
||||
"m48r3-static-occupancy-shadow",
|
||||
"m48s-fixed-class-detector",
|
||||
"m48t-risk-quality-temporal",
|
||||
"m49-tgs-fail-closed-evidence",
|
||||
"m49-tgs-full-shadow",
|
||||
"m47-reference-graph-shadow",
|
||||
"m4-replay-threat",
|
||||
"l3-pointpillars-visual-audit",
|
||||
@@ -130,9 +153,16 @@ const WORK_IDS: readonly AdvancedLaboratoryWorkId[] = [
|
||||
];
|
||||
|
||||
const RESULT_PREFIX: Readonly<Record<AdvancedLaboratoryWorkId, string>> = {
|
||||
"lab-v1-vegetation-benchmark": "lab-v1-vegetation-benchmark",
|
||||
"lab-v1-vegetation-shadow": "lab-v1-vegetation-shadow",
|
||||
"m48-object-centric-quality": "m48-object-quality-(?:pack|result)",
|
||||
"m48-small-static-passage-regression": "m48-small-static-passage-regression",
|
||||
"m48-static-occupancy-qualification": "m48-static-occupancy-qualification",
|
||||
"m48r3-static-occupancy-shadow": "m48r3-static-occupancy-shadow",
|
||||
"m48s-fixed-class-detector": "m48s-fixed-class-detector-lab",
|
||||
"m48t-risk-quality-temporal": "(?:m48t-risk-quality-temporal-lab|m48q-native-risk-quality-lab)",
|
||||
"m49-tgs-fail-closed-evidence": "m49-tgs-fail-closed",
|
||||
"m49-tgs-full-shadow": "m49-tgs-full-shadow",
|
||||
"m47-reference-graph-shadow": "m47-reference-graph-lab",
|
||||
"m4-replay-threat": "m4-threat-replay",
|
||||
"l3-pointpillars-visual-audit": "l3-pointpillars-visual-audit",
|
||||
@@ -177,10 +207,17 @@ export function isAdvancedLaboratoryWorkId(
|
||||
|
||||
export function emptyAdvancedLaboratoryResults(): AdvancedLaboratoryResults {
|
||||
return {
|
||||
vegetationBenchmark: null,
|
||||
vegetationShadow: null,
|
||||
m47Graph: null,
|
||||
m48: null,
|
||||
m48SmallStatic: null,
|
||||
m48StaticOccupancy: null,
|
||||
m48r3StaticOccupancy: null,
|
||||
m48s: null,
|
||||
m48t: null,
|
||||
m49Tgs: null,
|
||||
m49TgsFull: null,
|
||||
m4Threat: null,
|
||||
l3: null,
|
||||
l31: null,
|
||||
@@ -305,9 +342,16 @@ export function advancedLaboratoryResultAvailable(
|
||||
workId: AdvancedLaboratoryWorkId,
|
||||
results: AdvancedLaboratoryResults,
|
||||
): boolean {
|
||||
return workId === "m48-object-centric-quality" ? results.m48 !== null
|
||||
return workId === "lab-v1-vegetation-benchmark" ? results.vegetationBenchmark !== null
|
||||
: workId === "lab-v1-vegetation-shadow" ? results.vegetationShadow !== null
|
||||
: workId === "m48-object-centric-quality" ? results.m48 !== null
|
||||
: workId === "m48-small-static-passage-regression" ? results.m48SmallStatic !== null
|
||||
: workId === "m48-static-occupancy-qualification" ? results.m48StaticOccupancy !== null
|
||||
: workId === "m48r3-static-occupancy-shadow" ? results.m48r3StaticOccupancy !== null
|
||||
: workId === "m48s-fixed-class-detector" ? results.m48s !== null
|
||||
: workId === "m48t-risk-quality-temporal" ? results.m48t !== null
|
||||
: workId === "m49-tgs-fail-closed-evidence" ? results.m49Tgs !== null
|
||||
: workId === "m49-tgs-full-shadow" ? results.m49TgsFull !== null
|
||||
: workId === "m47-reference-graph-shadow" ? results.m47Graph !== null
|
||||
: workId === "m4-replay-threat" ? results.m4Threat !== null
|
||||
: workId === "l3-pointpillars-visual-audit" ? results.l3 !== null
|
||||
@@ -357,15 +401,36 @@ export async function fetchAdvancedLaboratoryResult(
|
||||
} = {},
|
||||
): Promise<AdvancedLaboratoryResults> {
|
||||
const results = emptyAdvancedLaboratoryResults();
|
||||
if (workId === "m48-object-centric-quality") {
|
||||
if (workId === "lab-v1-vegetation-benchmark") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("Vegetation benchmark identity не выбрана.");
|
||||
results.vegetationBenchmark = await fetchVegetationBenchmarkResult(resultId, { fetcher, signal });
|
||||
} else if (workId === "lab-v1-vegetation-shadow") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("Vegetation LAB identity не выбрана.");
|
||||
results.vegetationShadow = await fetchVegetationShadowResult(resultId, { fetcher, signal });
|
||||
} else if (workId === "m48-object-centric-quality") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8 lifecycle evidence identity не выбрана.");
|
||||
results.m48 = await fetchM48LifecycleResult(resultId, { fetcher, signal });
|
||||
} else if (workId === "m48-small-static-passage-regression") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8R1 regression identity не выбрана.");
|
||||
results.m48SmallStatic = await fetchM48SmallStaticRegression(resultId, { fetcher, signal });
|
||||
} else if (workId === "m48-static-occupancy-qualification") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8R2 qualification identity не выбрана.");
|
||||
results.m48StaticOccupancy = await fetchM48StaticOccupancyQualification(resultId, { fetcher, signal });
|
||||
} else if (workId === "m48r3-static-occupancy-shadow") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8R3 Worker shadow identity не выбрана.");
|
||||
results.m48r3StaticOccupancy = await fetchM48R3StaticOccupancyShadow(resultId, { fetcher, signal });
|
||||
} else if (workId === "m48s-fixed-class-detector") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8S LAB identity не выбрана.");
|
||||
results.m48s = await fetchM48SFixedClassDetectorResult(resultId, { fetcher, signal });
|
||||
} else if (workId === "m48t-risk-quality-temporal") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8T LAB identity не выбрана.");
|
||||
results.m48t = await fetchM48TRiskQualityResult(resultId, { fetcher, signal });
|
||||
} else if (workId === "m49-tgs-fail-closed-evidence") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("M4.9 TGS LAB identity не выбрана.");
|
||||
results.m49Tgs = await fetchM49TgsFailClosedResult(resultId, { fetcher, signal });
|
||||
} else if (workId === "m49-tgs-full-shadow") {
|
||||
if (!resultId) throw new AdvancedLaboratoryContractError("M4.9 full TGS shadow identity не выбрана.");
|
||||
results.m49TgsFull = await fetchM49TgsFullShadowResult(resultId, { fetcher, signal });
|
||||
} else if (workId === "m47-reference-graph-shadow") {
|
||||
if (!resultId) {
|
||||
throw new AdvancedLaboratoryContractError("M4.7 LAB identity не выбрана.");
|
||||
|
||||
@@ -36,13 +36,26 @@ import type { M4ThreatReplayResult } from "./m4ReplayThreat";
|
||||
import type { M47ReferenceGraphLabResult } from "./m47ReferenceGraph";
|
||||
import type { M48AdvancedResult } from "./m48ObjectCentricQuality";
|
||||
import type { M48SmallStaticRegressionResult } from "./m48SmallStaticRegression";
|
||||
import type { M48StaticOccupancyQualificationResult } from "./m48StaticOccupancyQualification";
|
||||
import type { M48R3StaticOccupancyShadowResult } from "./m48r3StaticOccupancyShadow";
|
||||
import type { M48SFixedClassDetectorResult } from "./m48sFixedClassDetector";
|
||||
import type { M48TRiskQualityResult } from "./m48tRiskQuality";
|
||||
import type { M49TgsFailClosedResult } from "./m49TgsFailClosed";
|
||||
import type { M49TgsFullShadowResult } from "./m49TgsFullShadow";
|
||||
import type { VegetationShadowResult } from "./vegetationShadow";
|
||||
|
||||
export interface AdvancedLaboratoryResults {
|
||||
vegetationBenchmark: VegetationShadowResult | null;
|
||||
vegetationShadow: VegetationShadowResult | null;
|
||||
m47Graph: M47ReferenceGraphLabResult | null;
|
||||
m48: M48AdvancedResult | null;
|
||||
m48SmallStatic: M48SmallStaticRegressionResult | null;
|
||||
m48StaticOccupancy: M48StaticOccupancyQualificationResult | null;
|
||||
m48r3StaticOccupancy: M48R3StaticOccupancyShadowResult | null;
|
||||
m48s: M48SFixedClassDetectorResult | null;
|
||||
m48t: M48TRiskQualityResult | null;
|
||||
m49Tgs: M49TgsFailClosedResult | null;
|
||||
m49TgsFull: M49TgsFullShadowResult | null;
|
||||
m4Threat: M4ThreatReplayResult | null;
|
||||
l3: L3PointPillarsVisualAuditResult | null;
|
||||
l31: L31PointPillarsRavnovesResult | null;
|
||||
|
||||
@@ -967,10 +967,12 @@ export async function fetchAdvancedLaboratoryResults({
|
||||
const e39 = settledCatalogValue(settled[7]);
|
||||
const e40 = settledCatalogValue(settled[8]);
|
||||
return {
|
||||
m47Graph: null, m48: null, m48SmallStatic: null, m48s: null, m4Threat: null,
|
||||
l3: null, l31: null,
|
||||
l32: null,
|
||||
l33: null,
|
||||
vegetationBenchmark: null,
|
||||
vegetationShadow: null,
|
||||
m47Graph: null, m48: null, m48SmallStatic: null, m48StaticOccupancy: null,
|
||||
m48r3StaticOccupancy: null,
|
||||
m48s: null, m48t: null, m49Tgs: null, m49TgsFull: null, m4Threat: null,
|
||||
l3: null, l31: null, l32: null, l33: null,
|
||||
e31,
|
||||
e32,
|
||||
e33,
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
import type { LaboratoryFetch } from "./advancedResults";
|
||||
import type { M48Authority } from "./m48ObjectCentricQuality";
|
||||
|
||||
const RESULT_ID = /^m48-static-occupancy-qualification-[a-f0-9]{64}$/;
|
||||
const M47_RESULT_ID = /^m47-reference-graph-lab-[a-f0-9]{64}$/;
|
||||
const M48R1_RESULT_ID = /^m48-small-static-passage-regression-[a-f0-9]{64}$/;
|
||||
const ANCHOR_ID = /^anchor-[a-f0-9]{24}$/;
|
||||
|
||||
export interface M48StaticOccupancyMetrics {
|
||||
operatorStaticAnchorCount: number;
|
||||
baselineQualifiedCount: number;
|
||||
candidateQualifiedCount: number;
|
||||
unresolvedUnknownCount: number;
|
||||
criticalNearAnchorCount: number;
|
||||
criticalNearBaselineRecall: number;
|
||||
criticalNearCandidateRecall: number;
|
||||
approachAnchorCount: number;
|
||||
approachBaselineRecall: number;
|
||||
approachCandidateRecall: number;
|
||||
canonicalEngineeringAnchorCount: number;
|
||||
canonicalEngineeringRecall: number;
|
||||
falseFreeCount: number;
|
||||
}
|
||||
|
||||
export interface M48StaticOccupancyQualificationResult {
|
||||
resultId: string;
|
||||
referenceGraphLabResultId: string;
|
||||
smallStaticResultId: string;
|
||||
createdAtUtc: string;
|
||||
runLabel: "M4.8R2";
|
||||
pipelineId: "m4-current-rolling-plus-step-static-occupancy/v1";
|
||||
experimentId: "m48-static-occupancy-qualification/v1";
|
||||
accepted: boolean;
|
||||
metrics: M48StaticOccupancyMetrics;
|
||||
gates: {
|
||||
criticalNearCandidateRecall: boolean;
|
||||
approachCandidateRecall: boolean;
|
||||
canonicalEngineeringRecall: boolean;
|
||||
zeroFalseFree: boolean;
|
||||
independentTruthAvailable: false;
|
||||
};
|
||||
decision: {
|
||||
state: "accepted-bounded-static-occupancy-qualification" | "partial-static-occupancy-qualification";
|
||||
criticalNearCandidateReadyForShadow: boolean;
|
||||
productionAccepted: false;
|
||||
summary: string;
|
||||
nextAction: string;
|
||||
};
|
||||
authority: M48Authority;
|
||||
}
|
||||
|
||||
export interface M48StaticOccupancyCase {
|
||||
anchorId: string;
|
||||
clipId: string;
|
||||
sequence: number;
|
||||
extentXyxy: readonly [number, number, number, number];
|
||||
distanceM: number;
|
||||
distanceBand: "critical-near" | "approach" | "outside-qualified-bands";
|
||||
baselineQualified: boolean;
|
||||
candidateQualified: boolean;
|
||||
outcome: "candidate-qualified" | "unresolved-unknown-never-free";
|
||||
graphMatched: boolean;
|
||||
}
|
||||
|
||||
export class M48StaticOccupancyContractError extends Error {}
|
||||
|
||||
function objectValue(value: unknown, label: string): Record<string, unknown> {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
throw new M48StaticOccupancyContractError(`${label}: ожидался объект.`);
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function text(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new M48StaticOccupancyContractError(`${label}: ожидалась строка.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function numberValue(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
throw new M48StaticOccupancyContractError(`${label}: ожидалось число.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function integer(value: unknown, label: string): number {
|
||||
const parsed = numberValue(value, label);
|
||||
if (!Number.isInteger(parsed) || parsed < 0) {
|
||||
throw new M48StaticOccupancyContractError(`${label}: ожидалось целое число.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function bool(value: unknown, label: string): boolean {
|
||||
if (typeof value !== "boolean") {
|
||||
throw new M48StaticOccupancyContractError(`${label}: ожидался флаг.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function exact(value: unknown, expected: string | boolean, label: string): void {
|
||||
if (value !== expected) throw new M48StaticOccupancyContractError(`${label}: нарушен контракт.`);
|
||||
}
|
||||
|
||||
function member<T extends string>(value: unknown, allowed: readonly T[], label: string): T {
|
||||
const parsed = text(value, label);
|
||||
if (!allowed.includes(parsed as T)) {
|
||||
throw new M48StaticOccupancyContractError(`${label}: недопустимое значение.`);
|
||||
}
|
||||
return parsed as T;
|
||||
}
|
||||
|
||||
function extent(value: unknown): readonly [number, number, number, number] {
|
||||
if (!Array.isArray(value) || value.length !== 4 || value.some((item) => typeof item !== "number" || !Number.isFinite(item))) {
|
||||
throw new M48StaticOccupancyContractError("M4.8R2.case.extent: нарушен контракт.");
|
||||
}
|
||||
const result = value as number[];
|
||||
if (result.some((item) => item < 0 || item > 1) || result[0]! >= result[2]! || result[1]! >= result[3]!) {
|
||||
throw new M48StaticOccupancyContractError("M4.8R2.case.extent: нарушена геометрия.");
|
||||
}
|
||||
return result as unknown as readonly [number, number, number, number];
|
||||
}
|
||||
|
||||
function authority(value: unknown): M48Authority {
|
||||
const row = objectValue(value, "M4.8R2.authority");
|
||||
exact(row.mode, "replay-simulated", "M4.8R2.authority.mode");
|
||||
exact(row.physical_live, false, "M4.8R2.authority.physical_live");
|
||||
exact(row.commands_enabled, false, "M4.8R2.authority.commands_enabled");
|
||||
exact(row.actuation_allowed, false, "M4.8R2.authority.actuation_allowed");
|
||||
exact(row.navigation_or_safety_accepted, false, "M4.8R2.authority.navigation_or_safety_accepted");
|
||||
return { mode: "replay-simulated", physicalLive: false, commandsEnabled: false, actuationAllowed: false, navigationOrSafetyAccepted: false };
|
||||
}
|
||||
|
||||
function metrics(value: unknown): M48StaticOccupancyMetrics {
|
||||
const row = objectValue(value, "M4.8R2.metrics");
|
||||
return {
|
||||
operatorStaticAnchorCount: integer(row.operator_static_anchor_count, "operator_static_anchor_count"),
|
||||
baselineQualifiedCount: integer(row.baseline_qualified_count, "baseline_qualified_count"),
|
||||
candidateQualifiedCount: integer(row.candidate_qualified_count, "candidate_qualified_count"),
|
||||
unresolvedUnknownCount: integer(row.unresolved_unknown_count, "unresolved_unknown_count"),
|
||||
criticalNearAnchorCount: integer(row.critical_near_anchor_count, "critical_near_anchor_count"),
|
||||
criticalNearBaselineRecall: numberValue(row.critical_near_baseline_recall, "critical_near_baseline_recall"),
|
||||
criticalNearCandidateRecall: numberValue(row.critical_near_candidate_recall, "critical_near_candidate_recall"),
|
||||
approachAnchorCount: integer(row.approach_anchor_count, "approach_anchor_count"),
|
||||
approachBaselineRecall: numberValue(row.approach_baseline_recall, "approach_baseline_recall"),
|
||||
approachCandidateRecall: numberValue(row.approach_candidate_recall, "approach_candidate_recall"),
|
||||
canonicalEngineeringAnchorCount: integer(row.canonical_engineering_anchor_count, "canonical_engineering_anchor_count"),
|
||||
canonicalEngineeringRecall: numberValue(row.canonical_engineering_recall, "canonical_engineering_recall"),
|
||||
falseFreeCount: integer(row.false_free_count, "false_free_count"),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM48StaticOccupancyQualification(
|
||||
resultId: string,
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<M48StaticOccupancyQualificationResult> {
|
||||
if (!RESULT_ID.test(resultId)) throw new M48StaticOccupancyContractError("M4.8R2 identity недопустима.");
|
||||
const response = await fetcher(`/api/v1/laboratory/m48/regressions/static-occupancy/${encodeURIComponent(resultId)}`, { method: "GET", headers: { Accept: "application/json" }, signal });
|
||||
if (!response.ok) throw new M48StaticOccupancyContractError(`M4.8R2 недоступен: HTTP ${response.status}.`);
|
||||
const payload = objectValue(await response.json(), "M4.8R2");
|
||||
exact(payload.schema_version, "missioncore.m48-static-occupancy-qualification-result-view/v1", "M4.8R2.schema_version");
|
||||
const m47 = text(payload.reference_graph_lab_result_id, "M4.8R2.reference_graph_lab_result_id");
|
||||
const m48r1 = text(payload.small_static_result_id, "M4.8R2.small_static_result_id");
|
||||
if (!M47_RESULT_ID.test(m47) || !M48R1_RESULT_ID.test(m48r1)) throw new M48StaticOccupancyContractError("M4.8R2 source identity нарушена.");
|
||||
exact(payload.run_label, "M4.8R2", "M4.8R2.run_label");
|
||||
exact(payload.pipeline_id, "m4-current-rolling-plus-step-static-occupancy/v1", "M4.8R2.pipeline_id");
|
||||
exact(payload.experiment_id, "m48-static-occupancy-qualification/v1", "M4.8R2.experiment_id");
|
||||
exact(payload.ground_truth, false, "M4.8R2.ground_truth");
|
||||
exact(payload.independent_truth, false, "M4.8R2.independent_truth");
|
||||
const gates = objectValue(payload.gates, "M4.8R2.gates");
|
||||
const decision = objectValue(payload.decision, "M4.8R2.decision");
|
||||
exact(decision.production_accepted, false, "M4.8R2.decision.production_accepted");
|
||||
return {
|
||||
resultId,
|
||||
referenceGraphLabResultId: m47,
|
||||
smallStaticResultId: m48r1,
|
||||
createdAtUtc: text(payload.created_at_utc, "M4.8R2.created_at_utc"),
|
||||
runLabel: "M4.8R2",
|
||||
pipelineId: "m4-current-rolling-plus-step-static-occupancy/v1",
|
||||
experimentId: "m48-static-occupancy-qualification/v1",
|
||||
accepted: bool(payload.accepted, "M4.8R2.accepted"),
|
||||
metrics: metrics(payload.metrics),
|
||||
gates: {
|
||||
criticalNearCandidateRecall: bool(gates.critical_near_candidate_recall, "critical_near_candidate_recall"),
|
||||
approachCandidateRecall: bool(gates.approach_candidate_recall, "approach_candidate_recall"),
|
||||
canonicalEngineeringRecall: bool(gates.canonical_engineering_recall, "canonical_engineering_recall"),
|
||||
zeroFalseFree: bool(gates.zero_false_free, "zero_false_free"),
|
||||
independentTruthAvailable: false,
|
||||
},
|
||||
decision: {
|
||||
state: member(
|
||||
decision.state,
|
||||
[
|
||||
"accepted-bounded-static-occupancy-qualification",
|
||||
"partial-static-occupancy-qualification",
|
||||
] as const,
|
||||
"M4.8R2.decision.state",
|
||||
),
|
||||
criticalNearCandidateReadyForShadow: bool(decision.critical_near_candidate_ready_for_shadow, "critical_near_candidate_ready_for_shadow"),
|
||||
productionAccepted: false,
|
||||
summary: text(decision.summary, "M4.8R2.decision.summary"),
|
||||
nextAction: text(decision.next_action, "M4.8R2.decision.next_action"),
|
||||
},
|
||||
authority: authority(payload.authority),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM48StaticOccupancyCases(
|
||||
resultId: string,
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<readonly M48StaticOccupancyCase[]> {
|
||||
if (!RESULT_ID.test(resultId)) throw new M48StaticOccupancyContractError("M4.8R2 identity недопустима.");
|
||||
const response = await fetcher(`/api/v1/laboratory/m48/regressions/static-occupancy/${encodeURIComponent(resultId)}/cases`, { method: "GET", headers: { Accept: "application/json" }, signal });
|
||||
if (!response.ok) throw new M48StaticOccupancyContractError(`M4.8R2 cases недоступны: HTTP ${response.status}.`);
|
||||
const payload = objectValue(await response.json(), "M4.8R2 cases");
|
||||
exact(payload.schema_version, "missioncore.m48-static-occupancy-case-catalog/v1", "M4.8R2 cases.schema_version");
|
||||
if (!Array.isArray(payload.cases) || payload.cases.length !== integer(payload.case_count, "M4.8R2.case_count")) throw new M48StaticOccupancyContractError("M4.8R2 cases: размер изменился.");
|
||||
return payload.cases.map((value, index) => {
|
||||
const row = objectValue(value, `M4.8R2.case[${index}]`);
|
||||
const anchorId = text(row.anchor_id, "anchor_id");
|
||||
if (!ANCHOR_ID.test(anchorId)) throw new M48StaticOccupancyContractError("M4.8R2 anchor identity нарушена.");
|
||||
const graph = objectValue(row.accepted_graph, "accepted_graph");
|
||||
const band = member(
|
||||
row.distance_band,
|
||||
["critical-near", "approach", "outside-qualified-bands"] as const,
|
||||
"distance_band",
|
||||
);
|
||||
const outcome = member(
|
||||
row.outcome,
|
||||
["candidate-qualified", "unresolved-unknown-never-free"] as const,
|
||||
"outcome",
|
||||
);
|
||||
return {
|
||||
anchorId,
|
||||
clipId: text(row.clip_id, "clip_id"),
|
||||
sequence: integer(row.sequence, "sequence"),
|
||||
extentXyxy: extent(row.extent_xyxy),
|
||||
distanceM: numberValue(row.distance_m, "distance_m"),
|
||||
distanceBand: band,
|
||||
baselineQualified: bool(row.baseline_qualified, "baseline_qualified"),
|
||||
candidateQualified: bool(row.candidate_qualified, "candidate_qualified"),
|
||||
outcome,
|
||||
graphMatched: bool(graph.matched, "accepted_graph.matched"),
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
import type { LaboratoryFetch } from "./advancedResults";
|
||||
import type { M48Authority } from "./m48ObjectCentricQuality";
|
||||
|
||||
const RESULT_ID = /^m48r3-static-occupancy-shadow-[a-f0-9]{64}$/;
|
||||
|
||||
interface M48R3WorkerPerformance {
|
||||
admittedFrames: number;
|
||||
deliveredFrames: number;
|
||||
fps: number;
|
||||
worldP95Ms: number;
|
||||
worldP99Ms: number;
|
||||
geometryP95Ms: number;
|
||||
geometryP99Ms: number;
|
||||
}
|
||||
|
||||
export interface M48R3StaticOccupancyShadowResult {
|
||||
resultId: string;
|
||||
createdAtUtc: string;
|
||||
accepted: boolean;
|
||||
profile: {
|
||||
id: string;
|
||||
sha256: string;
|
||||
minimumPoints: number;
|
||||
};
|
||||
metrics: {
|
||||
frames: { expected: number; baselineDelivered: number; candidateDelivered: number };
|
||||
performance: {
|
||||
baseline: M48R3WorkerPerformance;
|
||||
candidate: M48R3WorkerPerformance;
|
||||
fpsRegressionFraction: number;
|
||||
worldStateP95DeltaMs: number;
|
||||
};
|
||||
occupancy: {
|
||||
baselineCellTotal: number;
|
||||
candidateCellTotal: number;
|
||||
addedCellTotal: number;
|
||||
lostCellTotal: number;
|
||||
baselineComponentTotal: number;
|
||||
candidateComponentTotal: number;
|
||||
meanCellGrowthFraction: number;
|
||||
meanComponentGrowthFraction: number;
|
||||
maximumAddedCellsPerFrame: number;
|
||||
maximumCandidateComponentsPerFrame: number;
|
||||
};
|
||||
provider: {
|
||||
additiveObservationCount: number;
|
||||
additiveVoxelCount: number;
|
||||
framesWithAdditions: number;
|
||||
additiveMeanMsPerFrame: number;
|
||||
peakTemporalComponents: number;
|
||||
peakRollingCells: number;
|
||||
};
|
||||
anchors: {
|
||||
count: number;
|
||||
criticalNearCount: number;
|
||||
criticalNearRecall: number;
|
||||
matchedCount: number;
|
||||
canonicalEngineeringRecall: number;
|
||||
separation: readonly {
|
||||
displayFrame: number;
|
||||
expectedMinimumComponents: number;
|
||||
observedComponents: number;
|
||||
passed: boolean;
|
||||
interpretation: string;
|
||||
}[];
|
||||
};
|
||||
capacityDropCount: number;
|
||||
falseFreeCount: number;
|
||||
};
|
||||
gates: Readonly<Record<string, boolean>>;
|
||||
decision: {
|
||||
state: "accepted-bounded-worker-shadow" | "rejected-bounded-worker-shadow";
|
||||
candidateAccepted: boolean;
|
||||
productionAccepted: false;
|
||||
nextAction: string;
|
||||
};
|
||||
limitations: readonly string[];
|
||||
authority: M48Authority;
|
||||
}
|
||||
|
||||
export interface M48R3StaticOccupancyCase {
|
||||
anchorId: string;
|
||||
displayFrame: number;
|
||||
sourceSequence: number;
|
||||
extentXyxy: readonly [number, number, number, number];
|
||||
distanceBand: "critical-near" | "approach" | "outside-qualified-bands";
|
||||
componentCount: number;
|
||||
matched: boolean;
|
||||
}
|
||||
|
||||
export class M48R3StaticOccupancyContractError extends Error {}
|
||||
|
||||
function objectValue(value: unknown, label: string): Record<string, unknown> {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
throw new M48R3StaticOccupancyContractError(`${label}: ожидался объект.`);
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function text(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new M48R3StaticOccupancyContractError(`${label}: ожидалась строка.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function numberValue(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
throw new M48R3StaticOccupancyContractError(`${label}: ожидалось число.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function integer(value: unknown, label: string): number {
|
||||
const parsed = numberValue(value, label);
|
||||
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
||||
throw new M48R3StaticOccupancyContractError(`${label}: ожидалось целое число.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function bool(value: unknown, label: string): boolean {
|
||||
if (typeof value !== "boolean") {
|
||||
throw new M48R3StaticOccupancyContractError(`${label}: ожидался флаг.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function exact(value: unknown, expected: string | boolean, label: string): void {
|
||||
if (value !== expected) {
|
||||
throw new M48R3StaticOccupancyContractError(`${label}: нарушен контракт.`);
|
||||
}
|
||||
}
|
||||
|
||||
function sha256(value: unknown, label: string): string {
|
||||
const parsed = text(value, label);
|
||||
if (!/^[a-f0-9]{64}$/.test(parsed)) {
|
||||
throw new M48R3StaticOccupancyContractError(`${label}: неверный SHA-256.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function extent(value: unknown): readonly [number, number, number, number] {
|
||||
if (!Array.isArray(value) || value.length !== 4) {
|
||||
throw new M48R3StaticOccupancyContractError("M4.8R3 extent: нарушен контракт.");
|
||||
}
|
||||
const parsed = value.map((item) => numberValue(item, "M4.8R3 extent"));
|
||||
return [parsed[0]!, parsed[1]!, parsed[2]!, parsed[3]!];
|
||||
}
|
||||
|
||||
function authority(value: unknown): M48Authority {
|
||||
const row = objectValue(value, "M4.8R3 authority");
|
||||
exact(row.mode, "replay-simulated", "M4.8R3 authority.mode");
|
||||
exact(row.physical_live, false, "M4.8R3 authority.physical_live");
|
||||
exact(row.commands_enabled, false, "M4.8R3 authority.commands_enabled");
|
||||
exact(row.actuation_allowed, false, "M4.8R3 authority.actuation_allowed");
|
||||
exact(
|
||||
row.navigation_or_safety_accepted,
|
||||
false,
|
||||
"M4.8R3 authority.navigation_or_safety_accepted",
|
||||
);
|
||||
return {
|
||||
mode: "replay-simulated",
|
||||
physicalLive: false,
|
||||
commandsEnabled: false,
|
||||
actuationAllowed: false,
|
||||
navigationOrSafetyAccepted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function workerPerformance(value: unknown, label: string): M48R3WorkerPerformance {
|
||||
const row = objectValue(value, label);
|
||||
return {
|
||||
admittedFrames: integer(row.admitted_frames, `${label}.admitted_frames`),
|
||||
deliveredFrames: integer(row.delivered_frames, `${label}.delivered_frames`),
|
||||
fps: numberValue(row.fps, `${label}.fps`),
|
||||
worldP95Ms: numberValue(row.world_p95_ms, `${label}.world_p95_ms`),
|
||||
worldP99Ms: numberValue(row.world_p99_ms, `${label}.world_p99_ms`),
|
||||
geometryP95Ms: numberValue(row.geometry_p95_ms, `${label}.geometry_p95_ms`),
|
||||
geometryP99Ms: numberValue(row.geometry_p99_ms, `${label}.geometry_p99_ms`),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM48R3StaticOccupancyShadow(
|
||||
resultId: string,
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<M48R3StaticOccupancyShadowResult> {
|
||||
if (!RESULT_ID.test(resultId)) {
|
||||
throw new M48R3StaticOccupancyContractError("M4.8R3 identity недопустима.");
|
||||
}
|
||||
const response = await fetcher(
|
||||
`/api/v1/laboratory/m48r3/static-occupancy/${encodeURIComponent(resultId)}`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new M48R3StaticOccupancyContractError(`M4.8R3 недоступен: HTTP ${response.status}.`);
|
||||
}
|
||||
const payload = objectValue(await response.json(), "M4.8R3");
|
||||
exact(
|
||||
payload.schema_version,
|
||||
"missioncore.m48r3-static-occupancy-shadow-view/v1",
|
||||
"M4.8R3 schema",
|
||||
);
|
||||
exact(payload.result_id, resultId, "M4.8R3 result");
|
||||
exact(payload.ground_truth, false, "M4.8R3 ground truth");
|
||||
const profile = objectValue(payload.profile, "M4.8R3 profile");
|
||||
const componentization = objectValue(profile.componentization, "M4.8R3 componentization");
|
||||
const metrics = objectValue(payload.metrics, "M4.8R3 metrics");
|
||||
const frames = objectValue(metrics.frames, "M4.8R3 frames");
|
||||
const performance = objectValue(metrics.performance, "M4.8R3 performance");
|
||||
const occupancy = objectValue(metrics.occupancy, "M4.8R3 occupancy");
|
||||
const provider = objectValue(metrics.provider, "M4.8R3 provider");
|
||||
const anchors = objectValue(metrics.assisted_anchors, "M4.8R3 anchors");
|
||||
if (!Array.isArray(anchors.separation)) {
|
||||
throw new M48R3StaticOccupancyContractError("M4.8R3 separation: ожидался массив.");
|
||||
}
|
||||
const gates = objectValue(payload.gates, "M4.8R3 gates");
|
||||
const parsedGates = Object.fromEntries(
|
||||
Object.entries(gates).map(([key, value]) => [key, bool(value, `M4.8R3 gate ${key}`)]),
|
||||
);
|
||||
const decision = objectValue(payload.decision, "M4.8R3 decision");
|
||||
const state = text(decision.state, "M4.8R3 decision.state");
|
||||
if (state !== "accepted-bounded-worker-shadow" && state !== "rejected-bounded-worker-shadow") {
|
||||
throw new M48R3StaticOccupancyContractError("M4.8R3 decision.state: неизвестное состояние.");
|
||||
}
|
||||
exact(decision.production_accepted, false, "M4.8R3 production acceptance");
|
||||
if (!Array.isArray(payload.limitations)) {
|
||||
throw new M48R3StaticOccupancyContractError("M4.8R3 limitations: ожидался массив.");
|
||||
}
|
||||
return {
|
||||
resultId,
|
||||
createdAtUtc: text(payload.created_at_utc, "M4.8R3 created"),
|
||||
accepted: bool(payload.accepted, "M4.8R3 accepted"),
|
||||
profile: {
|
||||
id: text(profile.id, "M4.8R3 profile id"),
|
||||
sha256: sha256(profile.sha256, "M4.8R3 profile sha"),
|
||||
minimumPoints: integer(componentization.minimum_points, "M4.8R3 minimum points"),
|
||||
},
|
||||
metrics: {
|
||||
frames: {
|
||||
expected: integer(frames.expected, "M4.8R3 expected frames"),
|
||||
baselineDelivered: integer(frames.baseline_delivered, "M4.8R3 baseline frames"),
|
||||
candidateDelivered: integer(frames.candidate_delivered, "M4.8R3 candidate frames"),
|
||||
},
|
||||
performance: {
|
||||
baseline: workerPerformance(performance.baseline, "M4.8R3 baseline"),
|
||||
candidate: workerPerformance(performance.candidate, "M4.8R3 candidate"),
|
||||
fpsRegressionFraction: numberValue(performance.fps_regression_fraction, "M4.8R3 FPS regression"),
|
||||
worldStateP95DeltaMs: numberValue(performance.world_state_p95_delta_ms, "M4.8R3 p95 delta"),
|
||||
},
|
||||
occupancy: {
|
||||
baselineCellTotal: integer(occupancy.baseline_cell_total, "M4.8R3 baseline cells"),
|
||||
candidateCellTotal: integer(occupancy.candidate_cell_total, "M4.8R3 candidate cells"),
|
||||
addedCellTotal: integer(occupancy.added_cell_total, "M4.8R3 added cells"),
|
||||
lostCellTotal: integer(occupancy.lost_cell_total, "M4.8R3 lost cells"),
|
||||
baselineComponentTotal: integer(occupancy.baseline_component_total, "M4.8R3 baseline components"),
|
||||
candidateComponentTotal: integer(occupancy.candidate_component_total, "M4.8R3 candidate components"),
|
||||
meanCellGrowthFraction: numberValue(occupancy.mean_cell_growth_fraction, "M4.8R3 cell growth"),
|
||||
meanComponentGrowthFraction: numberValue(occupancy.mean_component_growth_fraction, "M4.8R3 component growth"),
|
||||
maximumAddedCellsPerFrame: integer(occupancy.maximum_added_cells_per_frame, "M4.8R3 maximum added cells"),
|
||||
maximumCandidateComponentsPerFrame: integer(occupancy.maximum_candidate_components_per_frame, "M4.8R3 maximum components"),
|
||||
},
|
||||
provider: {
|
||||
additiveObservationCount: integer(provider.additive_observation_count, "M4.8R3 observations"),
|
||||
additiveVoxelCount: integer(provider.additive_voxel_count, "M4.8R3 voxels"),
|
||||
framesWithAdditions: integer(provider.frames_with_additions, "M4.8R3 added frames"),
|
||||
additiveMeanMsPerFrame: numberValue(provider.additive_mean_ms_per_frame, "M4.8R3 additive mean"),
|
||||
peakTemporalComponents: integer(provider.peak_temporal_components, "M4.8R3 temporal peak"),
|
||||
peakRollingCells: integer(provider.peak_rolling_cells, "M4.8R3 rolling peak"),
|
||||
},
|
||||
anchors: {
|
||||
count: integer(anchors.count, "M4.8R3 anchor count"),
|
||||
criticalNearCount: integer(anchors.critical_near_count, "M4.8R3 near anchors"),
|
||||
criticalNearRecall: numberValue(anchors.critical_near_recall, "M4.8R3 near recall"),
|
||||
matchedCount: integer(anchors.matched_count, "M4.8R3 matched anchors"),
|
||||
canonicalEngineeringRecall: numberValue(anchors.canonical_engineering_recall, "M4.8R3 canonical recall"),
|
||||
separation: anchors.separation.map((value, index) => {
|
||||
const row = objectValue(value, `M4.8R3 separation ${index}`);
|
||||
return {
|
||||
displayFrame: integer(row.display_frame, "M4.8R3 separation frame"),
|
||||
expectedMinimumComponents: integer(row.expected_minimum_components, "M4.8R3 expected components"),
|
||||
observedComponents: integer(row.observed_components, "M4.8R3 observed components"),
|
||||
passed: bool(row.passed, "M4.8R3 separation passed"),
|
||||
interpretation: text(row.interpretation, "M4.8R3 separation interpretation"),
|
||||
};
|
||||
}),
|
||||
},
|
||||
capacityDropCount: integer(metrics.capacity_drop_count, "M4.8R3 capacity drops"),
|
||||
falseFreeCount: integer(metrics.false_free_count, "M4.8R3 false free"),
|
||||
},
|
||||
gates: parsedGates,
|
||||
decision: {
|
||||
state,
|
||||
candidateAccepted: bool(decision.candidate_accepted, "M4.8R3 candidate accepted"),
|
||||
productionAccepted: false,
|
||||
nextAction: text(decision.next_action, "M4.8R3 next action"),
|
||||
},
|
||||
limitations: payload.limitations.map((value, index) => text(value, `M4.8R3 limitation ${index}`)),
|
||||
authority: authority(payload.authority),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM48R3StaticOccupancyCases(
|
||||
resultId: string,
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<readonly M48R3StaticOccupancyCase[]> {
|
||||
if (!RESULT_ID.test(resultId)) {
|
||||
throw new M48R3StaticOccupancyContractError("M4.8R3 identity недопустима.");
|
||||
}
|
||||
const response = await fetcher(
|
||||
`/api/v1/laboratory/m48r3/static-occupancy/${encodeURIComponent(resultId)}/cases`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new M48R3StaticOccupancyContractError(`M4.8R3 cases недоступны: HTTP ${response.status}.`);
|
||||
}
|
||||
const payload = objectValue(await response.json(), "M4.8R3 cases");
|
||||
exact(
|
||||
payload.schema_version,
|
||||
"missioncore.m48r3-static-occupancy-shadow-cases/v1",
|
||||
"M4.8R3 cases schema",
|
||||
);
|
||||
exact(payload.result_id, resultId, "M4.8R3 cases result");
|
||||
if (!Array.isArray(payload.cases) || payload.cases.length !== integer(payload.case_count, "M4.8R3 case count")) {
|
||||
throw new M48R3StaticOccupancyContractError("M4.8R3 cases: нарушен размер.");
|
||||
}
|
||||
return payload.cases.map((value, index) => {
|
||||
const row = objectValue(value, `M4.8R3 case ${index}`);
|
||||
const distanceBand = text(row.distance_band, "M4.8R3 distance band");
|
||||
if (distanceBand !== "critical-near" && distanceBand !== "approach" && distanceBand !== "outside-qualified-bands") {
|
||||
throw new M48R3StaticOccupancyContractError("M4.8R3 distance band: неизвестное значение.");
|
||||
}
|
||||
return {
|
||||
anchorId: text(row.anchor_id, "M4.8R3 anchor id"),
|
||||
displayFrame: integer(row.display_frame, "M4.8R3 display frame"),
|
||||
sourceSequence: integer(row.source_sequence, "M4.8R3 source sequence"),
|
||||
extentXyxy: extent(row.extent_xyxy),
|
||||
distanceBand,
|
||||
componentCount: integer(row.component_count, "M4.8R3 component count"),
|
||||
matched: bool(row.matched, "M4.8R3 matched"),
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import type { LaboratoryFetch } from "./advancedResults";
|
||||
|
||||
const RESULT_ID = /^m48s-fixed-class-detector-lab-[a-f0-9]{64}$/;
|
||||
const FRAME_ID = /^[0-9]{6}$/;
|
||||
const SHA256 = /^[a-f0-9]{64}$/;
|
||||
const MODES = ["source", "yolox", "dfine", "rf-detr"] as const;
|
||||
const DETECTOR_MODES = ["yolox", "dfine", "rf-detr"] as const;
|
||||
const RESULT_STATUSES = [
|
||||
@@ -80,6 +81,100 @@ export interface M48SIntegratedWorldState {
|
||||
failures: number;
|
||||
}
|
||||
|
||||
export interface M48SRuntimeHardeningFullRun {
|
||||
sourceFramesAdmitted: number;
|
||||
deliveredWorldStates: number;
|
||||
supersededFrames: number;
|
||||
effectiveWorldStateFps: number;
|
||||
worldStateCompletionAgeP95Ms: number;
|
||||
worldStateCompletionAgeP99Ms: number;
|
||||
worldStateCompletionAgeMaximumMs: number;
|
||||
rollingMaximumMs: number;
|
||||
geometryMaximumMs: number;
|
||||
additionalInferencePasses: number;
|
||||
}
|
||||
|
||||
export interface M48SRuntimeHardeningComparison {
|
||||
baseline: M48SRuntimeHardeningFullRun;
|
||||
hardened: M48SRuntimeHardeningFullRun;
|
||||
startup: {
|
||||
baseline: { detectorMs: number; worldStateMs: number };
|
||||
prewarmed: { detectorMs: number; worldStateMs: number };
|
||||
prewarmDurationMs: number;
|
||||
prewarmInferencePasses: number;
|
||||
validationFrames: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface M48SLoadEnvelopeScenario {
|
||||
id: "production-10fps" | "reserve-12fps" | "limit-15fps";
|
||||
loadPurpose: "production-rate" | "reserve-gate" | "limit-discovery";
|
||||
requestedSourceRateHz: number;
|
||||
sourceFramesAdmitted: number;
|
||||
deliveredWorldStates: number;
|
||||
supersededFrames: number;
|
||||
deliveryRatio: number;
|
||||
effectiveWorldStateFps: number;
|
||||
worldStateCompletionAgeP95Ms: number;
|
||||
worldStateCompletionAgeP99Ms: number;
|
||||
worldStateCompletionAgeMaximumMs: number;
|
||||
hotLoopDecodeP95Ms: number;
|
||||
hotLoopDecodeMaximumMs: number;
|
||||
preadmissionDecodeMaximumMs: number;
|
||||
sourcePrefetchPreparationMaximumMs: number;
|
||||
sourcePacingLatenessP95Ms: number;
|
||||
sourcePacingLatenessMaximumMs: number;
|
||||
detectorP95Ms: number;
|
||||
detectorMaximumMs: number;
|
||||
gpuUtilizationMeanPercent: number;
|
||||
gpuUtilizationMaximumPercent: number;
|
||||
gpuMemoryMaximumMib: number;
|
||||
processPeakRssMib: number;
|
||||
queueHighWatermarks: Readonly<Record<"detector" | "geometry" | "temporal" | "rolling" | "threat", number>>;
|
||||
queueCapacity: number;
|
||||
additionalInferencePasses: number;
|
||||
repeatCount: number;
|
||||
allRepetitionsPassed: boolean;
|
||||
integrityGatePassed: boolean;
|
||||
operatingTargetGatePassed: boolean;
|
||||
thresholds: {
|
||||
minimumDeliveryRatio: number;
|
||||
minimumEffectiveWorldStateFps: number;
|
||||
maximumWorldStateCompletionP95Ms: number;
|
||||
};
|
||||
repetitions: readonly M48SLoadEnvelopeRepetition[];
|
||||
}
|
||||
|
||||
export interface M48SLoadEnvelopeRepetition {
|
||||
runId: string;
|
||||
repetition: 1 | 2 | 3;
|
||||
deliveredWorldStates: number;
|
||||
supersededFrames: number;
|
||||
deliveryRatio: number;
|
||||
effectiveWorldStateFps: number;
|
||||
worldStateCompletionAgeP95Ms: number;
|
||||
hotLoopDecodeP95Ms: number;
|
||||
hotLoopDecodeMaximumMs: number;
|
||||
preadmissionDecodeMaximumMs: number;
|
||||
sourcePacingLatenessMaximumMs: number;
|
||||
operatingTargetGatePassed: boolean;
|
||||
resultSha256: string;
|
||||
frameEvidenceSha256: string;
|
||||
}
|
||||
|
||||
export interface M48SLoadEnvelopeComparison {
|
||||
repeatCountPerRate: number;
|
||||
productionRateRepeatabilityPassed: boolean;
|
||||
reserve12FpsPassed: boolean;
|
||||
limit15FpsPassed: boolean;
|
||||
loadEnvelopeAccepted: boolean;
|
||||
computeCapacityAtLeastFps: 15;
|
||||
bottleneckInterpretation:
|
||||
| "rare-source-decode-or-scheduling-tail-not-steady-gpu-saturation"
|
||||
| "cold-video-decode-isolated-before-admission-no-steady-gpu-saturation";
|
||||
scenarios: readonly M48SLoadEnvelopeScenario[];
|
||||
}
|
||||
|
||||
export interface M48SFixedClassDetectorResult {
|
||||
resultId: string;
|
||||
createdAtUtc: string;
|
||||
@@ -118,6 +213,8 @@ export interface M48SFixedClassDetectorResult {
|
||||
failures: number;
|
||||
};
|
||||
integratedWorldState: M48SIntegratedWorldState | null;
|
||||
runtimeHardening: M48SRuntimeHardeningComparison | null;
|
||||
loadEnvelope: M48SLoadEnvelopeComparison | null;
|
||||
};
|
||||
decision: {
|
||||
selectedCandidate: "rf-detr";
|
||||
@@ -125,6 +222,11 @@ export interface M48SFixedClassDetectorResult {
|
||||
integratedWorldStateGateEvaluated: boolean;
|
||||
integratedWorldStateGatePassed: boolean;
|
||||
detectorReplacementAuthorized: false;
|
||||
loadEnvelopeEvaluated: boolean;
|
||||
productionRateRepeatabilityPassed: boolean;
|
||||
reserve12FpsPassed: boolean;
|
||||
limit15FpsPassed: boolean;
|
||||
loadEnvelopeAccepted: boolean;
|
||||
productionAccepted: false;
|
||||
};
|
||||
limitations: readonly string[];
|
||||
@@ -366,6 +468,288 @@ function integratedWorldStateValue(value: unknown): M48SIntegratedWorldState {
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeHardeningFullRunValue(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): M48SRuntimeHardeningFullRun {
|
||||
const run = objectValue(value, label);
|
||||
return {
|
||||
sourceFramesAdmitted: integerValue(run.source_frames_admitted, `${label}.source_frames_admitted`),
|
||||
deliveredWorldStates: integerValue(run.delivered_world_states, `${label}.delivered_world_states`),
|
||||
supersededFrames: integerValue(run.superseded_frames, `${label}.superseded_frames`),
|
||||
effectiveWorldStateFps: numberValue(run.effective_world_state_fps, `${label}.effective_world_state_fps`),
|
||||
worldStateCompletionAgeP95Ms: numberValue(run.world_state_completion_age_p95_ms, `${label}.world_state_completion_age_p95_ms`),
|
||||
worldStateCompletionAgeP99Ms: numberValue(run.world_state_completion_age_p99_ms, `${label}.world_state_completion_age_p99_ms`),
|
||||
worldStateCompletionAgeMaximumMs: numberValue(run.world_state_completion_age_maximum_ms, `${label}.world_state_completion_age_maximum_ms`),
|
||||
rollingMaximumMs: numberValue(run.rolling_maximum_ms, `${label}.rolling_maximum_ms`),
|
||||
geometryMaximumMs: numberValue(run.geometry_maximum_ms, `${label}.geometry_maximum_ms`),
|
||||
additionalInferencePasses: integerValue(run.additional_inference_passes, `${label}.additional_inference_passes`),
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeHardeningComparisonValue(value: unknown): M48SRuntimeHardeningComparison {
|
||||
const comparison = objectValue(value, "M4.8S.metrics.runtime_hardening");
|
||||
exact(
|
||||
comparison.schema_version,
|
||||
"missioncore.m48s-runtime-hardening-comparison/v1",
|
||||
"M4.8S.metrics.runtime_hardening.schema_version",
|
||||
);
|
||||
const startup = objectValue(comparison.startup, "M4.8S.runtime_hardening.startup");
|
||||
const startupFrame = (
|
||||
candidate: unknown,
|
||||
label: string,
|
||||
): { detectorMs: number; worldStateMs: number } => {
|
||||
const frame = objectValue(candidate, label);
|
||||
return {
|
||||
detectorMs: numberValue(frame.detector_ms, `${label}.detector_ms`),
|
||||
worldStateMs: numberValue(frame.world_state_ms, `${label}.world_state_ms`),
|
||||
};
|
||||
};
|
||||
return {
|
||||
baseline: runtimeHardeningFullRunValue(
|
||||
comparison.baseline,
|
||||
"M4.8S.runtime_hardening.baseline",
|
||||
),
|
||||
hardened: runtimeHardeningFullRunValue(
|
||||
comparison.hardened,
|
||||
"M4.8S.runtime_hardening.hardened",
|
||||
),
|
||||
startup: {
|
||||
baseline: startupFrame(startup.baseline, "M4.8S.runtime_hardening.startup.baseline"),
|
||||
prewarmed: startupFrame(startup.prewarmed, "M4.8S.runtime_hardening.startup.prewarmed"),
|
||||
prewarmDurationMs: numberValue(
|
||||
startup.prewarm_duration_ms,
|
||||
"M4.8S.runtime_hardening.startup.prewarm_duration_ms",
|
||||
),
|
||||
prewarmInferencePasses: integerValue(
|
||||
startup.prewarm_inference_passes,
|
||||
"M4.8S.runtime_hardening.startup.prewarm_inference_passes",
|
||||
),
|
||||
validationFrames: integerValue(
|
||||
startup.validation_frames,
|
||||
"M4.8S.runtime_hardening.startup.validation_frames",
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function loadEnvelopeComparisonValue(value: unknown): M48SLoadEnvelopeComparison {
|
||||
const comparison = objectValue(value, "M4.8S.metrics.load_envelope");
|
||||
if (comparison.schema_version === "missioncore.m48s-load-envelope-comparison/v1") {
|
||||
exact(comparison.production_rate_repeatability_passed, false, "M4.8S.load_envelope.production_rate_repeatability_passed");
|
||||
exact(comparison.reserve_12_fps_passed, true, "M4.8S.load_envelope.reserve_12_fps_passed");
|
||||
exact(comparison.limit_15_fps_passed, true, "M4.8S.load_envelope.limit_15_fps_passed");
|
||||
exact(comparison.load_envelope_accepted, false, "M4.8S.load_envelope.load_envelope_accepted");
|
||||
exact(comparison.compute_capacity_at_least_fps, 15, "M4.8S.load_envelope.compute_capacity_at_least_fps");
|
||||
exact(
|
||||
comparison.bottleneck_interpretation,
|
||||
"rare-source-decode-or-scheduling-tail-not-steady-gpu-saturation",
|
||||
"M4.8S.load_envelope.bottleneck_interpretation",
|
||||
);
|
||||
const ids = ["production-10fps", "reserve-12fps", "limit-15fps"] as const;
|
||||
const purposes = ["production-rate", "reserve-gate", "limit-discovery"] as const;
|
||||
const targetGates = [false, true, true] as const;
|
||||
const scenarios = arrayValue(comparison.scenarios, "M4.8S.load_envelope.scenarios").map((value, index) => {
|
||||
const label = `M4.8S.load_envelope.scenarios[${index}]`;
|
||||
const scenario = objectValue(value, label);
|
||||
const id = ids[index];
|
||||
const purpose = purposes[index];
|
||||
const targetGate = targetGates[index];
|
||||
if (id === undefined || purpose === undefined || targetGate === undefined) {
|
||||
throw new M48SFixedClassDetectorContractError("M4.8S.load_envelope.scenarios: лишний legacy-сценарий.");
|
||||
}
|
||||
exact(scenario.id, id, `${label}.id`);
|
||||
exact(scenario.load_purpose, purpose, `${label}.load_purpose`);
|
||||
exact(scenario.integrity_gate_passed, true, `${label}.integrity_gate_passed`);
|
||||
exact(scenario.operating_target_gate_passed, targetGate, `${label}.operating_target_gate_passed`);
|
||||
exact(scenario.additional_inference_passes, 0, `${label}.additional_inference_passes`);
|
||||
const queues = integerRecordValue(scenario.queue_high_watermarks, `${label}.queue_high_watermarks`);
|
||||
const thresholds = objectValue(scenario.thresholds, `${label}.thresholds`);
|
||||
const frameEvidenceSha256 = textValue(scenario.frame_evidence_sha256, `${label}.frame_evidence_sha256`);
|
||||
if (!SHA256.test(frameEvidenceSha256)) {
|
||||
throw new M48SFixedClassDetectorContractError(`${label}.frame_evidence_sha256: нарушен SHA-256.`);
|
||||
}
|
||||
const legacyDecodeP95 = numberValue(scenario.decode_p95_ms, `${label}.decode_p95_ms`);
|
||||
const legacyDecodeMaximum = numberValue(scenario.decode_maximum_ms, `${label}.decode_maximum_ms`);
|
||||
return {
|
||||
id,
|
||||
loadPurpose: purpose,
|
||||
requestedSourceRateHz: numberValue(scenario.requested_source_rate_hz, `${label}.requested_source_rate_hz`),
|
||||
sourceFramesAdmitted: integerValue(scenario.source_frames_admitted, `${label}.source_frames_admitted`),
|
||||
deliveredWorldStates: integerValue(scenario.delivered_world_states, `${label}.delivered_world_states`),
|
||||
supersededFrames: integerValue(scenario.superseded_frames, `${label}.superseded_frames`),
|
||||
deliveryRatio: numberValue(scenario.delivery_ratio, `${label}.delivery_ratio`),
|
||||
effectiveWorldStateFps: numberValue(scenario.effective_world_state_fps, `${label}.effective_world_state_fps`),
|
||||
worldStateCompletionAgeP95Ms: numberValue(scenario.world_state_completion_age_p95_ms, `${label}.world_state_completion_age_p95_ms`),
|
||||
worldStateCompletionAgeP99Ms: numberValue(scenario.world_state_completion_age_p99_ms, `${label}.world_state_completion_age_p99_ms`),
|
||||
worldStateCompletionAgeMaximumMs: numberValue(scenario.world_state_completion_age_maximum_ms, `${label}.world_state_completion_age_maximum_ms`),
|
||||
hotLoopDecodeP95Ms: legacyDecodeP95,
|
||||
hotLoopDecodeMaximumMs: legacyDecodeMaximum,
|
||||
preadmissionDecodeMaximumMs: legacyDecodeMaximum,
|
||||
sourcePrefetchPreparationMaximumMs: 0,
|
||||
sourcePacingLatenessP95Ms: 0,
|
||||
sourcePacingLatenessMaximumMs: 0,
|
||||
detectorP95Ms: numberValue(scenario.detector_p95_ms, `${label}.detector_p95_ms`),
|
||||
detectorMaximumMs: numberValue(scenario.detector_maximum_ms, `${label}.detector_maximum_ms`),
|
||||
gpuUtilizationMeanPercent: numberValue(scenario.gpu_utilization_mean_percent, `${label}.gpu_utilization_mean_percent`),
|
||||
gpuUtilizationMaximumPercent: numberValue(scenario.gpu_utilization_maximum_percent, `${label}.gpu_utilization_maximum_percent`),
|
||||
gpuMemoryMaximumMib: numberValue(scenario.gpu_memory_maximum_mib, `${label}.gpu_memory_maximum_mib`),
|
||||
processPeakRssMib: numberValue(scenario.process_peak_rss_mib, `${label}.process_peak_rss_mib`),
|
||||
queueHighWatermarks: queues as M48SLoadEnvelopeScenario["queueHighWatermarks"],
|
||||
queueCapacity: integerValue(scenario.queue_capacity, `${label}.queue_capacity`),
|
||||
additionalInferencePasses: 0,
|
||||
repeatCount: 1,
|
||||
allRepetitionsPassed: targetGate,
|
||||
integrityGatePassed: true,
|
||||
operatingTargetGatePassed: targetGate,
|
||||
thresholds: {
|
||||
minimumDeliveryRatio: numberValue(thresholds.minimum_delivery_ratio, `${label}.thresholds.minimum_delivery_ratio`),
|
||||
minimumEffectiveWorldStateFps: numberValue(thresholds.minimum_effective_world_state_fps, `${label}.thresholds.minimum_effective_world_state_fps`),
|
||||
maximumWorldStateCompletionP95Ms: numberValue(thresholds.maximum_world_state_completion_p95_ms, `${label}.thresholds.maximum_world_state_completion_p95_ms`),
|
||||
},
|
||||
repetitions: [],
|
||||
};
|
||||
});
|
||||
if (scenarios.length !== 3) {
|
||||
throw new M48SFixedClassDetectorContractError("M4.8S.load_envelope.scenarios: неполный legacy-набор.");
|
||||
}
|
||||
return {
|
||||
repeatCountPerRate: 1,
|
||||
productionRateRepeatabilityPassed: false,
|
||||
reserve12FpsPassed: true,
|
||||
limit15FpsPassed: true,
|
||||
loadEnvelopeAccepted: false,
|
||||
computeCapacityAtLeastFps: 15,
|
||||
bottleneckInterpretation: "rare-source-decode-or-scheduling-tail-not-steady-gpu-saturation",
|
||||
scenarios,
|
||||
};
|
||||
}
|
||||
exact(
|
||||
comparison.schema_version,
|
||||
"missioncore.m48s-load-envelope-comparison/v2",
|
||||
"M4.8S.metrics.load_envelope.schema_version",
|
||||
);
|
||||
exact(comparison.repeat_count_per_rate, 3, "M4.8S.load_envelope.repeat_count_per_rate");
|
||||
exact(comparison.production_rate_repeatability_passed, true, "M4.8S.load_envelope.production_rate_repeatability_passed");
|
||||
exact(comparison.reserve_12_fps_passed, true, "M4.8S.load_envelope.reserve_12_fps_passed");
|
||||
exact(comparison.limit_15_fps_passed, true, "M4.8S.load_envelope.limit_15_fps_passed");
|
||||
exact(comparison.load_envelope_accepted, true, "M4.8S.load_envelope.load_envelope_accepted");
|
||||
exact(comparison.compute_capacity_at_least_fps, 15, "M4.8S.load_envelope.compute_capacity_at_least_fps");
|
||||
exact(
|
||||
comparison.bottleneck_interpretation,
|
||||
"cold-video-decode-isolated-before-admission-no-steady-gpu-saturation",
|
||||
"M4.8S.load_envelope.bottleneck_interpretation",
|
||||
);
|
||||
const ids = ["production-10fps", "reserve-12fps", "limit-15fps"] as const;
|
||||
const purposes = ["production-rate", "reserve-gate", "limit-discovery"] as const;
|
||||
const scenarios = arrayValue(comparison.scenarios, "M4.8S.load_envelope.scenarios").map((value, index) => {
|
||||
const label = `M4.8S.load_envelope.scenarios[${index}]`;
|
||||
const scenario = objectValue(value, label);
|
||||
const id = ids[index];
|
||||
const purpose = purposes[index];
|
||||
if (id === undefined || purpose === undefined) {
|
||||
throw new M48SFixedClassDetectorContractError("M4.8S.load_envelope.scenarios: лишний сценарий.");
|
||||
}
|
||||
exact(scenario.id, id, `${label}.id`);
|
||||
exact(scenario.load_purpose, purpose, `${label}.load_purpose`);
|
||||
exact(scenario.repeat_count, 3, `${label}.repeat_count`);
|
||||
exact(scenario.all_repetitions_passed, true, `${label}.all_repetitions_passed`);
|
||||
exact(scenario.integrity_gate_passed, true, `${label}.integrity_gate_passed`);
|
||||
exact(scenario.operating_target_gate_passed, true, `${label}.operating_target_gate_passed`);
|
||||
exact(scenario.additional_inference_passes, 0, `${label}.additional_inference_passes`);
|
||||
const queues = integerRecordValue(scenario.queue_high_watermarks, `${label}.queue_high_watermarks`);
|
||||
for (const key of ["detector", "geometry", "temporal", "rolling", "threat"] as const) {
|
||||
if (!(key in queues)) {
|
||||
throw new M48SFixedClassDetectorContractError(`${label}.queue_high_watermarks.${key}: отсутствует.`);
|
||||
}
|
||||
}
|
||||
const thresholds = objectValue(scenario.thresholds, `${label}.thresholds`);
|
||||
const repetitions = arrayValue(scenario.repetitions, `${label}.repetitions`).map((value, repetitionIndex) => {
|
||||
const repetitionLabel = `${label}.repetitions[${repetitionIndex}]`;
|
||||
const repetition = objectValue(value, repetitionLabel);
|
||||
const repetitionNumber = repetitionIndex + 1;
|
||||
exact(repetition.repetition, repetitionNumber, `${repetitionLabel}.repetition`);
|
||||
exact(repetition.operating_target_gate_passed, true, `${repetitionLabel}.operating_target_gate_passed`);
|
||||
const runId = textValue(repetition.run_id, `${repetitionLabel}.run_id`);
|
||||
const resultSha256 = textValue(repetition.result_sha256, `${repetitionLabel}.result_sha256`);
|
||||
const frameEvidenceSha256 = textValue(repetition.frame_evidence_sha256, `${repetitionLabel}.frame_evidence_sha256`);
|
||||
if (!SHA256.test(resultSha256) || !SHA256.test(frameEvidenceSha256)) {
|
||||
throw new M48SFixedClassDetectorContractError(`${repetitionLabel}: нарушен SHA-256.`);
|
||||
}
|
||||
return {
|
||||
runId,
|
||||
repetition: repetitionNumber as 1 | 2 | 3,
|
||||
deliveredWorldStates: integerValue(repetition.delivered_world_states, `${repetitionLabel}.delivered_world_states`),
|
||||
supersededFrames: integerValue(repetition.superseded_frames, `${repetitionLabel}.superseded_frames`),
|
||||
deliveryRatio: numberValue(repetition.delivery_ratio, `${repetitionLabel}.delivery_ratio`),
|
||||
effectiveWorldStateFps: numberValue(repetition.effective_world_state_fps, `${repetitionLabel}.effective_world_state_fps`),
|
||||
worldStateCompletionAgeP95Ms: numberValue(repetition.world_state_completion_age_p95_ms, `${repetitionLabel}.world_state_completion_age_p95_ms`),
|
||||
hotLoopDecodeP95Ms: numberValue(repetition.hot_loop_decode_p95_ms, `${repetitionLabel}.hot_loop_decode_p95_ms`),
|
||||
hotLoopDecodeMaximumMs: numberValue(repetition.hot_loop_decode_maximum_ms, `${repetitionLabel}.hot_loop_decode_maximum_ms`),
|
||||
preadmissionDecodeMaximumMs: numberValue(repetition.preadmission_decode_maximum_ms, `${repetitionLabel}.preadmission_decode_maximum_ms`),
|
||||
sourcePacingLatenessMaximumMs: numberValue(repetition.source_pacing_lateness_maximum_ms, `${repetitionLabel}.source_pacing_lateness_maximum_ms`),
|
||||
operatingTargetGatePassed: true as const,
|
||||
resultSha256,
|
||||
frameEvidenceSha256,
|
||||
};
|
||||
});
|
||||
if (repetitions.length !== 3) {
|
||||
throw new M48SFixedClassDetectorContractError(`${label}.repetitions: требуется три повтора.`);
|
||||
}
|
||||
return {
|
||||
id,
|
||||
loadPurpose: purpose,
|
||||
requestedSourceRateHz: numberValue(scenario.requested_source_rate_hz, `${label}.requested_source_rate_hz`),
|
||||
sourceFramesAdmitted: integerValue(scenario.source_frames_admitted, `${label}.source_frames_admitted`),
|
||||
deliveredWorldStates: integerValue(scenario.delivered_world_states, `${label}.delivered_world_states`),
|
||||
supersededFrames: integerValue(scenario.superseded_frames, `${label}.superseded_frames`),
|
||||
deliveryRatio: numberValue(scenario.delivery_ratio, `${label}.delivery_ratio`),
|
||||
effectiveWorldStateFps: numberValue(scenario.effective_world_state_fps, `${label}.effective_world_state_fps`),
|
||||
worldStateCompletionAgeP95Ms: numberValue(scenario.world_state_completion_age_p95_ms, `${label}.world_state_completion_age_p95_ms`),
|
||||
worldStateCompletionAgeP99Ms: numberValue(scenario.world_state_completion_age_p99_ms, `${label}.world_state_completion_age_p99_ms`),
|
||||
worldStateCompletionAgeMaximumMs: numberValue(scenario.world_state_completion_age_maximum_ms, `${label}.world_state_completion_age_maximum_ms`),
|
||||
hotLoopDecodeP95Ms: numberValue(scenario.hot_loop_decode_p95_ms, `${label}.hot_loop_decode_p95_ms`),
|
||||
hotLoopDecodeMaximumMs: numberValue(scenario.hot_loop_decode_maximum_ms, `${label}.hot_loop_decode_maximum_ms`),
|
||||
preadmissionDecodeMaximumMs: numberValue(scenario.preadmission_decode_maximum_ms, `${label}.preadmission_decode_maximum_ms`),
|
||||
sourcePrefetchPreparationMaximumMs: numberValue(scenario.source_prefetch_preparation_maximum_ms, `${label}.source_prefetch_preparation_maximum_ms`),
|
||||
sourcePacingLatenessP95Ms: numberValue(scenario.source_pacing_lateness_p95_ms, `${label}.source_pacing_lateness_p95_ms`),
|
||||
sourcePacingLatenessMaximumMs: numberValue(scenario.source_pacing_lateness_maximum_ms, `${label}.source_pacing_lateness_maximum_ms`),
|
||||
detectorP95Ms: numberValue(scenario.detector_p95_ms, `${label}.detector_p95_ms`),
|
||||
detectorMaximumMs: numberValue(scenario.detector_maximum_ms, `${label}.detector_maximum_ms`),
|
||||
gpuUtilizationMeanPercent: numberValue(scenario.gpu_utilization_mean_percent, `${label}.gpu_utilization_mean_percent`),
|
||||
gpuUtilizationMaximumPercent: numberValue(scenario.gpu_utilization_maximum_percent, `${label}.gpu_utilization_maximum_percent`),
|
||||
gpuMemoryMaximumMib: numberValue(scenario.gpu_memory_maximum_mib, `${label}.gpu_memory_maximum_mib`),
|
||||
processPeakRssMib: numberValue(scenario.process_peak_rss_mib, `${label}.process_peak_rss_mib`),
|
||||
queueHighWatermarks: queues as M48SLoadEnvelopeScenario["queueHighWatermarks"],
|
||||
queueCapacity: integerValue(scenario.queue_capacity, `${label}.queue_capacity`),
|
||||
additionalInferencePasses: 0,
|
||||
repeatCount: 3 as const,
|
||||
allRepetitionsPassed: true as const,
|
||||
integrityGatePassed: true as const,
|
||||
operatingTargetGatePassed: true as const,
|
||||
thresholds: {
|
||||
minimumDeliveryRatio: numberValue(thresholds.minimum_delivery_ratio, `${label}.thresholds.minimum_delivery_ratio`),
|
||||
minimumEffectiveWorldStateFps: numberValue(thresholds.minimum_effective_world_state_fps, `${label}.thresholds.minimum_effective_world_state_fps`),
|
||||
maximumWorldStateCompletionP95Ms: numberValue(thresholds.maximum_world_state_completion_p95_ms, `${label}.thresholds.maximum_world_state_completion_p95_ms`),
|
||||
},
|
||||
repetitions,
|
||||
};
|
||||
});
|
||||
if (scenarios.length !== ids.length) {
|
||||
throw new M48SFixedClassDetectorContractError("M4.8S.load_envelope.scenarios: неполный набор.");
|
||||
}
|
||||
return {
|
||||
repeatCountPerRate: 3,
|
||||
productionRateRepeatabilityPassed: true,
|
||||
reserve12FpsPassed: true,
|
||||
limit15FpsPassed: true,
|
||||
loadEnvelopeAccepted: true,
|
||||
computeCapacityAtLeastFps: 15,
|
||||
bottleneckInterpretation: "cold-video-decode-isolated-before-admission-no-steady-gpu-saturation",
|
||||
scenarios,
|
||||
};
|
||||
}
|
||||
|
||||
function parseResult(value: unknown, resultId: string): M48SFixedClassDetectorResult {
|
||||
const payload = objectValue(value, "M4.8S");
|
||||
exact(
|
||||
@@ -384,6 +768,9 @@ function parseResult(value: unknown, resultId: string): M48SFixedClassDetectorRe
|
||||
const metrics = objectValue(payload.metrics, "M4.8S.metrics");
|
||||
const load = objectValue(metrics.detector_load, "M4.8S.metrics.detector_load");
|
||||
const decision = objectValue(payload.decision, "M4.8S.decision");
|
||||
const loadEnvelope = metrics.load_envelope === undefined
|
||||
? null
|
||||
: loadEnvelopeComparisonValue(metrics.load_envelope);
|
||||
const cameraRaster = arrayValue(source.camera_raster, "M4.8S.source.camera_raster");
|
||||
if (cameraRaster.length !== 2) {
|
||||
throw new M48SFixedClassDetectorContractError("M4.8S.source.camera_raster: нарушен размер.");
|
||||
@@ -412,6 +799,13 @@ function parseResult(value: unknown, resultId: string): M48SFixedClassDetectorRe
|
||||
exact(decision.detector_replacement_authorized, false, "M4.8S.decision.detector_replacement_authorized");
|
||||
}
|
||||
exact(decision.production_accepted, false, "M4.8S.decision.production_accepted");
|
||||
if (loadEnvelope !== null) {
|
||||
exact(decision.load_envelope_evaluated, true, "M4.8S.decision.load_envelope_evaluated");
|
||||
exact(decision.production_rate_repeatability_passed, loadEnvelope.productionRateRepeatabilityPassed, "M4.8S.decision.production_rate_repeatability_passed");
|
||||
exact(decision.reserve_12_fps_passed, loadEnvelope.reserve12FpsPassed, "M4.8S.decision.reserve_12_fps_passed");
|
||||
exact(decision.limit_15_fps_passed, loadEnvelope.limit15FpsPassed, "M4.8S.decision.limit_15_fps_passed");
|
||||
exact(decision.load_envelope_accepted, loadEnvelope.loadEnvelopeAccepted, "M4.8S.decision.load_envelope_accepted");
|
||||
}
|
||||
const frames = arrayValue(payload.frames, "M4.8S.frames").map(descriptorValue);
|
||||
const evidenceFrameCount = integerValue(source.evidence_frame_count, "M4.8S.source.evidence_frame_count");
|
||||
if (frames.length !== evidenceFrameCount || new Set(frames.map((frame) => frame.frameId)).size !== frames.length) {
|
||||
@@ -457,6 +851,10 @@ function parseResult(value: unknown, resultId: string): M48SFixedClassDetectorRe
|
||||
integratedWorldState: integratedGate
|
||||
? integratedWorldStateValue(metrics.integrated_world_state)
|
||||
: null,
|
||||
runtimeHardening: metrics.runtime_hardening === undefined
|
||||
? null
|
||||
: runtimeHardeningComparisonValue(metrics.runtime_hardening),
|
||||
loadEnvelope,
|
||||
},
|
||||
decision: {
|
||||
selectedCandidate: "rf-detr",
|
||||
@@ -464,6 +862,11 @@ function parseResult(value: unknown, resultId: string): M48SFixedClassDetectorRe
|
||||
integratedWorldStateGateEvaluated: integratedGate,
|
||||
integratedWorldStateGatePassed: integratedGate,
|
||||
detectorReplacementAuthorized: false,
|
||||
loadEnvelopeEvaluated: loadEnvelope !== null,
|
||||
productionRateRepeatabilityPassed: loadEnvelope?.productionRateRepeatabilityPassed ?? false,
|
||||
reserve12FpsPassed: loadEnvelope?.reserve12FpsPassed ?? false,
|
||||
limit15FpsPassed: loadEnvelope?.limit15FpsPassed ?? false,
|
||||
loadEnvelopeAccepted: loadEnvelope?.loadEnvelopeAccepted ?? false,
|
||||
productionAccepted: false,
|
||||
},
|
||||
limitations: arrayValue(payload.limitations, "M4.8S.limitations").map((item, index) => textValue(item, `M4.8S.limitations[${index}]`)),
|
||||
|
||||
@@ -0,0 +1,618 @@
|
||||
export interface M48TLaboratoryMethod {
|
||||
completeness: "complete";
|
||||
executionClass: "hybrid";
|
||||
pipelineId: string;
|
||||
components: readonly {
|
||||
kind: "source" | "model" | "algorithm" | "runtime" | "tool";
|
||||
name: string;
|
||||
version: string;
|
||||
role: string;
|
||||
identitySha256: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface M48TReviewCase {
|
||||
caseId: string;
|
||||
imageId: number;
|
||||
imageUrl: string;
|
||||
byteLength: number;
|
||||
sha256: string;
|
||||
}
|
||||
|
||||
export interface M48TLegacyRiskQualityResult {
|
||||
variant: "legacy-coco-quality";
|
||||
resultId: string;
|
||||
createdAtUtc: string;
|
||||
source: {
|
||||
quality: {
|
||||
datasetId: "coco-2017-val";
|
||||
riskImages: number;
|
||||
truthInstances: number;
|
||||
independentHumanAnnotations: true;
|
||||
ravnovesGroundTruth: false;
|
||||
};
|
||||
temporal: {
|
||||
sourceId: "RAVNOVES00";
|
||||
frames: number;
|
||||
publications: number;
|
||||
independentSemanticTruthAvailable: false;
|
||||
};
|
||||
};
|
||||
candidate: {
|
||||
providerId: string;
|
||||
modelId: "rf_detr_large:1";
|
||||
minimumScore: 0.25;
|
||||
};
|
||||
execution: {
|
||||
durationSeconds: number;
|
||||
effectiveImagesPerSecond: number;
|
||||
imageP95Ms: number;
|
||||
inferenceP95Ms: number;
|
||||
timingIsAdmissionEvidence: false;
|
||||
};
|
||||
quality: {
|
||||
microPrecision: number;
|
||||
microRecall: number;
|
||||
mediumLargeRecall: number;
|
||||
emptyRiskImageFraction: number;
|
||||
families: Readonly<Record<"person" | "animal" | "light-road-user" | "vehicle", number>>;
|
||||
};
|
||||
counts: {
|
||||
truth: number;
|
||||
predictions: number;
|
||||
truePositive: number;
|
||||
falsePositive: number;
|
||||
falseNegative: number;
|
||||
};
|
||||
failures: Readonly<Record<string, number>>;
|
||||
temporal: {
|
||||
rawClassSwitches: number;
|
||||
stableClassSwitches: number;
|
||||
rawFamilySwitches: number;
|
||||
stableFamilySwitches: number;
|
||||
suppressedClassSwitches: number;
|
||||
suppressedFamilySwitches: number;
|
||||
selectedPublications: number;
|
||||
semanticObservations: number;
|
||||
peakActiveComponents: number;
|
||||
maximumActiveComponents: number;
|
||||
};
|
||||
acceptance: {
|
||||
qualityPassed: false;
|
||||
failedQualityGates: readonly [
|
||||
"minimum-micro-precision",
|
||||
"minimum-family-recall:vehicle",
|
||||
];
|
||||
temporalInvariantPassed: true;
|
||||
};
|
||||
review: {
|
||||
truthColor: "green";
|
||||
predictionColor: "yellow";
|
||||
cases: readonly M48TReviewCase[];
|
||||
};
|
||||
method: M48TLaboratoryMethod;
|
||||
limitations: readonly string[];
|
||||
}
|
||||
|
||||
export type M48QRiskFamily = "person" | "animal" | "light-road-user" | "vehicle";
|
||||
|
||||
export interface M48QNativeProposal {
|
||||
proposalId: string;
|
||||
className: string;
|
||||
riskFamily: M48QRiskFamily;
|
||||
score: number;
|
||||
boxXyxy: readonly [number, number, number, number];
|
||||
}
|
||||
|
||||
export interface M48QNativeReviewCase {
|
||||
caseId: string;
|
||||
sequence: number;
|
||||
frameId: string;
|
||||
evidenceTimeNs: number;
|
||||
imageUrl: string;
|
||||
width: 800;
|
||||
height: 600;
|
||||
byteLength: number;
|
||||
sha256: string;
|
||||
selectionBuckets: readonly string[];
|
||||
nativeDetectionCount: number;
|
||||
legacyDetectionCount: number;
|
||||
matchedDetectionCount: number;
|
||||
proposals: readonly M48QNativeProposal[];
|
||||
}
|
||||
|
||||
export interface M48QNativeRiskQualityResult {
|
||||
variant: "native-risk-review";
|
||||
resultId: string;
|
||||
createdAtUtc: string;
|
||||
source: {
|
||||
sourceId: "RAVNOVES00";
|
||||
frameCount: 4489;
|
||||
width: 800;
|
||||
height: 600;
|
||||
geometricResampling: false;
|
||||
};
|
||||
candidate: {
|
||||
providerId: string;
|
||||
modelId: "rf_detr_large_native_kb4:1";
|
||||
preprocessId: "raw-kb4-uint8-fused-mask-rgb-pad8-imagenet-trt/v0";
|
||||
minimumScore: 0.25;
|
||||
};
|
||||
execution: {
|
||||
effectiveWorldStateFps: number;
|
||||
worldStateCompletionP95Ms: number;
|
||||
detectorTotalP95Ms: number;
|
||||
gpuUtilizationP95Percent: number;
|
||||
gpuMemoryMaximumMib: number;
|
||||
additionalInferencePasses: 0;
|
||||
};
|
||||
selection: {
|
||||
caseCount: 24;
|
||||
minimumSequenceSeparation: number;
|
||||
bucketCoverage: Readonly<Record<string, number>>;
|
||||
classCounts: Readonly<Record<string, number>>;
|
||||
};
|
||||
runtime: {
|
||||
deliveryRatio: number;
|
||||
integratedGatePassed: true;
|
||||
operatingTargetGatePassed: true;
|
||||
};
|
||||
parity: {
|
||||
precision: number;
|
||||
recall: number;
|
||||
meanIou: number;
|
||||
};
|
||||
acceptance: {
|
||||
reviewReady: true;
|
||||
independentQualityEvaluated: false;
|
||||
semanticCandidateAccepted: false;
|
||||
};
|
||||
review: {
|
||||
cases: readonly M48QNativeReviewCase[];
|
||||
};
|
||||
method: M48TLaboratoryMethod;
|
||||
limitations: readonly string[];
|
||||
}
|
||||
|
||||
export type M48TRiskQualityResult =
|
||||
| M48TLegacyRiskQualityResult
|
||||
| M48QNativeRiskQualityResult;
|
||||
|
||||
type LaboratoryFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
||||
|
||||
export class M48TContractError extends Error {}
|
||||
|
||||
function object(value: unknown, label: string): Record<string, unknown> {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
throw new M48TContractError(`${label}: ожидался объект.`);
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function array(value: unknown, label: string): readonly unknown[] {
|
||||
if (!Array.isArray(value)) throw new M48TContractError(`${label}: ожидался массив.`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function text(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new M48TContractError(`${label}: ожидалась строка.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function number(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
||||
throw new M48TContractError(`${label}: ожидалось неотрицательное число.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function integer(value: unknown, label: string): number {
|
||||
const parsed = number(value, label);
|
||||
if (!Number.isSafeInteger(parsed)) {
|
||||
throw new M48TContractError(`${label}: ожидалось целое число.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function exact<T extends string | number | boolean>(
|
||||
value: unknown,
|
||||
expected: T,
|
||||
label: string,
|
||||
): T {
|
||||
if (value !== expected) throw new M48TContractError(`${label}: нарушен контракт.`);
|
||||
return expected;
|
||||
}
|
||||
|
||||
function sha(value: unknown, label: string): string {
|
||||
const parsed = text(value, label);
|
||||
if (!/^[a-f0-9]{64}$/.test(parsed)) {
|
||||
throw new M48TContractError(`${label}: нарушена SHA-256 идентичность.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function method(value: unknown): M48TLaboratoryMethod {
|
||||
const raw = object(value, "M4.8T method");
|
||||
exact(raw.schema_version, "missioncore.laboratory-method/v1", "M4.8T method schema");
|
||||
exact(raw.completeness, "complete", "M4.8T method completeness");
|
||||
exact(raw.execution_class, "hybrid", "M4.8T method execution");
|
||||
const allowedKinds = new Set(["source", "model", "algorithm", "runtime", "tool"]);
|
||||
return {
|
||||
completeness: "complete",
|
||||
executionClass: "hybrid",
|
||||
pipelineId: text(raw.pipeline_id, "M4.8T pipeline"),
|
||||
components: array(raw.components, "M4.8T components").map((value) => {
|
||||
const component = object(value, "M4.8T component");
|
||||
const kind = text(component.kind, "M4.8T component kind");
|
||||
if (!allowedKinds.has(kind)) throw new M48TContractError("M4.8T component kind: неизвестное значение.");
|
||||
return {
|
||||
kind: kind as "source" | "model" | "algorithm" | "runtime" | "tool",
|
||||
name: text(component.name, "M4.8T component name"),
|
||||
version: text(component.version, "M4.8T component version"),
|
||||
role: text(component.role, "M4.8T component role"),
|
||||
identitySha256: sha(component.identity_sha256, "M4.8T component identity"),
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function parseLegacyResult(value: unknown, expectedResultId: string): M48TLegacyRiskQualityResult {
|
||||
const raw = object(value, "M4.8T result");
|
||||
exact(raw.schema_version, "missioncore.m48t-risk-quality-temporal-view/v1", "M4.8T schema");
|
||||
exact(raw.variant, "legacy-coco-quality", "M4.8T variant");
|
||||
exact(raw.result_id, expectedResultId, "M4.8T identity");
|
||||
exact(raw.status, "complete-quality-gate-failed-temporal-invariant-passed", "M4.8T status");
|
||||
exact(raw.access, "read-only", "M4.8T access");
|
||||
exact(raw.ground_truth, false, "M4.8T ground truth");
|
||||
|
||||
const source = object(raw.source, "M4.8T source");
|
||||
const qualitySource = object(source.quality, "M4.8T quality source");
|
||||
const temporalSource = object(source.temporal, "M4.8T temporal source");
|
||||
const configuration = object(raw.configuration, "M4.8T configuration");
|
||||
const candidate = object(configuration.candidate, "M4.8T candidate");
|
||||
const execution = object(raw.execution, "M4.8T execution");
|
||||
const imageTiming = object(execution.image_timing_ms, "M4.8T image timing");
|
||||
const inferenceTiming = object(execution.triton_inference_ms, "M4.8T inference timing");
|
||||
const metrics = object(raw.metrics, "M4.8T metrics");
|
||||
const quality = object(metrics.quality, "M4.8T quality metrics");
|
||||
const families = object(quality.families, "M4.8T family metrics");
|
||||
const familyRecall = (name: "person" | "animal" | "light-road-user" | "vehicle") =>
|
||||
number(object(families[name], `M4.8T ${name}`).family_recall, `M4.8T ${name} recall`);
|
||||
const counts = object(metrics.counts, "M4.8T counts");
|
||||
const failures = object(metrics.failure_buckets, "M4.8T failures");
|
||||
const temporal = object(metrics.temporal, "M4.8T temporal metrics");
|
||||
const snapshot = object(temporal.snapshot, "M4.8T temporal snapshot");
|
||||
const acceptance = object(raw.acceptance, "M4.8T acceptance");
|
||||
const qualityGate = object(acceptance.quality, "M4.8T quality gate");
|
||||
const temporalGate = object(acceptance.temporal_invariant, "M4.8T temporal gate");
|
||||
const failed = array(qualityGate.failed, "M4.8T failed gates").map((item) => text(item, "M4.8T failed gate"));
|
||||
if (failed.length !== 2 || failed[0] !== "minimum-micro-precision" || failed[1] !== "minimum-family-recall:vehicle") {
|
||||
throw new M48TContractError("M4.8T failed gates: изменён зафиксированный результат.");
|
||||
}
|
||||
exact(qualityGate.passed, false, "M4.8T quality gate");
|
||||
exact(temporalGate.passed, true, "M4.8T temporal invariant");
|
||||
exact(temporalGate.semantic_quality_accepted, false, "M4.8T temporal semantic acceptance");
|
||||
|
||||
const review = object(raw.review, "M4.8T review");
|
||||
const legend = object(review.legend, "M4.8T review legend");
|
||||
exact(legend.ground_truth, "green", "M4.8T truth legend");
|
||||
exact(legend.rf_detr_prediction, "yellow", "M4.8T prediction legend");
|
||||
const cases = array(review.cases, "M4.8T review cases").map((value) => {
|
||||
const item = object(value, "M4.8T review case");
|
||||
const caseId = text(item.case_id, "M4.8T case id");
|
||||
if (!/^[0-9]{12}$/.test(caseId)) throw new M48TContractError("M4.8T case identity нарушена.");
|
||||
exact(item.media_type, "image/jpeg", "M4.8T case media");
|
||||
return {
|
||||
caseId,
|
||||
imageId: integer(item.image_id, "M4.8T image id"),
|
||||
imageUrl: text(item.image_url, "M4.8T image URL"),
|
||||
byteLength: integer(item.byte_length, "M4.8T image bytes"),
|
||||
sha256: sha(item.sha256, "M4.8T image SHA"),
|
||||
};
|
||||
});
|
||||
if (cases.length !== 16 || new Set(cases.map(({ caseId }) => caseId)).size !== 16) {
|
||||
throw new M48TContractError("M4.8T review catalog: нарушен размер.");
|
||||
}
|
||||
|
||||
const parsedFailures: Record<string, number> = {};
|
||||
for (const [key, count] of Object.entries(failures)) parsedFailures[key] = integer(count, `M4.8T failure ${key}`);
|
||||
const temporalConfiguration = object(configuration.temporal, "M4.8T temporal configuration");
|
||||
return {
|
||||
variant: "legacy-coco-quality",
|
||||
resultId: expectedResultId,
|
||||
createdAtUtc: text(raw.created_at_utc, "M4.8T created at"),
|
||||
source: {
|
||||
quality: {
|
||||
datasetId: exact(qualitySource.dataset_id, "coco-2017-val", "M4.8T dataset"),
|
||||
riskImages: integer(qualitySource.risk_images, "M4.8T risk images"),
|
||||
truthInstances: integer(qualitySource.truth_instances, "M4.8T truth instances"),
|
||||
independentHumanAnnotations: exact(qualitySource.independent_human_annotations, true, "M4.8T independent truth"),
|
||||
ravnovesGroundTruth: exact(qualitySource.ravnoves_ground_truth, false, "M4.8T RAVNOVES truth"),
|
||||
},
|
||||
temporal: {
|
||||
sourceId: exact(temporalSource.source_id, "RAVNOVES00", "M4.8T temporal source"),
|
||||
frames: integer(temporalSource.frames, "M4.8T temporal frames"),
|
||||
publications: integer(temporalSource.publications, "M4.8T temporal publications"),
|
||||
independentSemanticTruthAvailable: exact(temporalSource.independent_semantic_truth_available, false, "M4.8T temporal truth"),
|
||||
},
|
||||
},
|
||||
candidate: {
|
||||
providerId: text(candidate.provider_id, "M4.8T provider"),
|
||||
modelId: exact(candidate.model_id, "rf_detr_large:1", "M4.8T model"),
|
||||
minimumScore: exact(candidate.minimum_score, 0.25, "M4.8T threshold"),
|
||||
},
|
||||
execution: {
|
||||
durationSeconds: number(execution.duration_seconds, "M4.8T duration"),
|
||||
effectiveImagesPerSecond: number(execution.effective_images_per_second, "M4.8T throughput"),
|
||||
imageP95Ms: number(imageTiming.p95, "M4.8T image p95"),
|
||||
inferenceP95Ms: number(inferenceTiming.p95, "M4.8T inference p95"),
|
||||
timingIsAdmissionEvidence: exact(execution.timing_is_admission_evidence, false, "M4.8T timing authority"),
|
||||
},
|
||||
quality: {
|
||||
microPrecision: number(quality.micro_precision, "M4.8T precision"),
|
||||
microRecall: number(quality.micro_recall, "M4.8T recall"),
|
||||
mediumLargeRecall: number(quality.medium_large_recall, "M4.8T medium-large recall"),
|
||||
emptyRiskImageFraction: number(quality.empty_prediction_risk_image_fraction, "M4.8T empty fraction"),
|
||||
families: {
|
||||
person: familyRecall("person"),
|
||||
animal: familyRecall("animal"),
|
||||
"light-road-user": familyRecall("light-road-user"),
|
||||
vehicle: familyRecall("vehicle"),
|
||||
},
|
||||
},
|
||||
counts: {
|
||||
truth: integer(qualitySource.truth_instances, "M4.8T truth count"),
|
||||
predictions: integer(counts.predictions, "M4.8T predictions"),
|
||||
truePositive: integer(counts.true_positive, "M4.8T TP"),
|
||||
falsePositive: integer(counts.false_positive, "M4.8T FP"),
|
||||
falseNegative: integer(counts.false_negative, "M4.8T FN"),
|
||||
},
|
||||
failures: parsedFailures,
|
||||
temporal: {
|
||||
rawClassSwitches: integer(temporal.raw_class_switches, "M4.8T raw class switches"),
|
||||
stableClassSwitches: integer(temporal.stable_class_switches, "M4.8T stable class switches"),
|
||||
rawFamilySwitches: integer(temporal.raw_family_switches, "M4.8T raw family switches"),
|
||||
stableFamilySwitches: integer(temporal.stable_family_switches, "M4.8T stable family switches"),
|
||||
suppressedClassSwitches: integer(temporal.suppressed_or_deferred_class_switches, "M4.8T suppressed class switches"),
|
||||
suppressedFamilySwitches: integer(temporal.suppressed_or_deferred_family_switches, "M4.8T suppressed family switches"),
|
||||
selectedPublications: integer(temporal.selected_publications, "M4.8T selected publications"),
|
||||
semanticObservations: integer(temporal.semantic_current_observations, "M4.8T semantic observations"),
|
||||
peakActiveComponents: integer(snapshot.peak_active_components, "M4.8T active peak"),
|
||||
maximumActiveComponents: integer(temporalConfiguration.maximum_active_components, "M4.8T active bound"),
|
||||
},
|
||||
acceptance: {
|
||||
qualityPassed: false,
|
||||
failedQualityGates: ["minimum-micro-precision", "minimum-family-recall:vehicle"],
|
||||
temporalInvariantPassed: true,
|
||||
},
|
||||
review: { truthColor: "green", predictionColor: "yellow", cases },
|
||||
method: method(raw.method),
|
||||
limitations: array(raw.limitations, "M4.8T limitations").map((item) => text(item, "M4.8T limitation")),
|
||||
};
|
||||
}
|
||||
|
||||
function numberRecord(value: unknown, label: string): Readonly<Record<string, number>> {
|
||||
const raw = object(value, label);
|
||||
const parsed: Record<string, number> = {};
|
||||
for (const [key, item] of Object.entries(raw)) parsed[key] = integer(item, `${label}.${key}`);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function nativeRiskFamily(value: unknown): M48QRiskFamily {
|
||||
const parsed = text(value, "M4.8Q risk family");
|
||||
if (!["person", "animal", "light-road-user", "vehicle"].includes(parsed)) {
|
||||
throw new M48TContractError("M4.8Q risk family: неизвестное значение.");
|
||||
}
|
||||
return parsed as M48QRiskFamily;
|
||||
}
|
||||
|
||||
function nativeProposal(value: unknown): M48QNativeProposal {
|
||||
const raw = object(value, "M4.8Q proposal");
|
||||
const coordinates = array(raw.box_xyxy, "M4.8Q proposal box").map((item) =>
|
||||
number(item, "M4.8Q proposal coordinate")
|
||||
);
|
||||
if (
|
||||
coordinates.length !== 4
|
||||
|| coordinates[0] >= coordinates[2]
|
||||
|| coordinates[1] >= coordinates[3]
|
||||
|| coordinates[2] > 800
|
||||
|| coordinates[3] > 600
|
||||
) {
|
||||
throw new M48TContractError("M4.8Q proposal box: нарушена raw-raster геометрия.");
|
||||
}
|
||||
const score = number(raw.score, "M4.8Q proposal score");
|
||||
if (score < 0.25 || score > 1) throw new M48TContractError("M4.8Q proposal score: нарушен threshold.");
|
||||
return {
|
||||
proposalId: text(raw.proposal_id, "M4.8Q proposal id"),
|
||||
className: text(raw.class_name, "M4.8Q proposal class"),
|
||||
riskFamily: nativeRiskFamily(raw.risk_family),
|
||||
score,
|
||||
boxXyxy: coordinates as [number, number, number, number],
|
||||
};
|
||||
}
|
||||
|
||||
function parseNativeResult(value: unknown, expectedResultId: string): M48QNativeRiskQualityResult {
|
||||
const raw = object(value, "M4.8Q result");
|
||||
exact(raw.schema_version, "missioncore.m48q-native-risk-quality-view/v1", "M4.8Q schema");
|
||||
exact(raw.variant, "native-risk-review", "M4.8Q variant");
|
||||
exact(raw.result_id, expectedResultId, "M4.8Q identity");
|
||||
exact(raw.status, "complete-review-ready-quality-not-adjudicated", "M4.8Q status");
|
||||
exact(raw.access, "read-only", "M4.8Q access");
|
||||
exact(raw.ground_truth, false, "M4.8Q ground truth");
|
||||
|
||||
const source = object(raw.source, "M4.8Q source");
|
||||
exact(source.source_id, "RAVNOVES00", "M4.8Q source id");
|
||||
exact(source.frame_count, 4489, "M4.8Q source frames");
|
||||
exact(source.raster_width, 800, "M4.8Q source width");
|
||||
exact(source.raster_height, 600, "M4.8Q source height");
|
||||
exact(source.geometric_resampling, false, "M4.8Q source resampling");
|
||||
exact(source.rectification, false, "M4.8Q source rectification");
|
||||
exact(source.warp, false, "M4.8Q source warp");
|
||||
|
||||
const configuration = object(raw.configuration, "M4.8Q configuration");
|
||||
const candidate = object(configuration.candidate, "M4.8Q candidate");
|
||||
const execution = object(raw.execution, "M4.8Q execution");
|
||||
const metrics = object(raw.metrics, "M4.8Q metrics");
|
||||
const selection = object(metrics.selection, "M4.8Q selection");
|
||||
const runtime = object(metrics.runtime, "M4.8Q runtime");
|
||||
const parity = object(metrics.native_tensor_parity, "M4.8Q parity");
|
||||
const acceptance = object(raw.acceptance, "M4.8Q acceptance");
|
||||
exact(acceptance.review_ready, true, "M4.8Q review readiness");
|
||||
exact(acceptance.integrated_runtime_gate_passed, true, "M4.8Q runtime gate");
|
||||
exact(acceptance.independent_quality_evaluated, false, "M4.8Q quality state");
|
||||
exact(acceptance.semantic_candidate_accepted, false, "M4.8Q candidate state");
|
||||
exact(selection.case_count, 24, "M4.8Q selected cases");
|
||||
|
||||
const review = object(raw.review, "M4.8Q review");
|
||||
const raster = object(review.source_raster, "M4.8Q review raster");
|
||||
exact(raster.width, 800, "M4.8Q review width");
|
||||
exact(raster.height, 600, "M4.8Q review height");
|
||||
const overlay = object(review.overlay, "M4.8Q overlay");
|
||||
exact(overlay.client_rendered, true, "M4.8Q client overlay");
|
||||
exact(overlay.toggleable, true, "M4.8Q overlay toggle");
|
||||
const cases = array(review.cases, "M4.8Q review cases").map((value) => {
|
||||
const item = object(value, "M4.8Q review case");
|
||||
const caseId = text(item.case_id, "M4.8Q case id");
|
||||
if (!/^[0-9]{6}$/.test(caseId)) throw new M48TContractError("M4.8Q case identity нарушена.");
|
||||
const sequence = integer(item.sequence, "M4.8Q case sequence");
|
||||
exact(caseId, sequence.toString().padStart(6, "0"), "M4.8Q case/sequence identity");
|
||||
exact(item.frame_id, `frame-${caseId}`, "M4.8Q frame identity");
|
||||
exact(item.media_type, "image/jpeg", "M4.8Q case media");
|
||||
exact(item.width, 800, "M4.8Q case width");
|
||||
exact(item.height, 600, "M4.8Q case height");
|
||||
exact(item.geometric_resampling, false, "M4.8Q case resampling");
|
||||
const comparison = object(item.comparison, "M4.8Q comparison");
|
||||
const proposals = array(item.proposals, "M4.8Q proposals").map(nativeProposal);
|
||||
if (!proposals.length) throw new M48TContractError("M4.8Q proposals: пустой review case.");
|
||||
return {
|
||||
caseId,
|
||||
sequence,
|
||||
frameId: `frame-${caseId}`,
|
||||
evidenceTimeNs: integer(item.evidence_time_ns, "M4.8Q evidence time"),
|
||||
imageUrl: text(item.image_url, "M4.8Q image URL"),
|
||||
width: 800 as const,
|
||||
height: 600 as const,
|
||||
byteLength: integer(item.byte_length, "M4.8Q image bytes"),
|
||||
sha256: sha(item.sha256, "M4.8Q image SHA"),
|
||||
selectionBuckets: array(item.selection_buckets, "M4.8Q selection buckets").map((bucket) =>
|
||||
text(bucket, "M4.8Q selection bucket")
|
||||
),
|
||||
nativeDetectionCount: integer(comparison.native_detection_count, "M4.8Q native count"),
|
||||
legacyDetectionCount: integer(comparison.legacy_704_detection_count, "M4.8Q legacy count"),
|
||||
matchedDetectionCount: integer(
|
||||
comparison.matched_detection_count_iou_at_least_0_5,
|
||||
"M4.8Q matched count",
|
||||
),
|
||||
proposals,
|
||||
};
|
||||
});
|
||||
if (cases.length !== 24 || new Set(cases.map(({ caseId }) => caseId)).size !== 24) {
|
||||
throw new M48TContractError("M4.8Q review catalog: нарушен размер.");
|
||||
}
|
||||
|
||||
return {
|
||||
variant: "native-risk-review",
|
||||
resultId: expectedResultId,
|
||||
createdAtUtc: text(raw.created_at_utc, "M4.8Q created at"),
|
||||
source: {
|
||||
sourceId: "RAVNOVES00",
|
||||
frameCount: 4489,
|
||||
width: 800,
|
||||
height: 600,
|
||||
geometricResampling: false,
|
||||
},
|
||||
candidate: {
|
||||
providerId: text(candidate.provider_id, "M4.8Q provider"),
|
||||
modelId: exact(candidate.model_id, "rf_detr_large_native_kb4:1", "M4.8Q model"),
|
||||
preprocessId: exact(
|
||||
candidate.preprocess_id,
|
||||
"raw-kb4-uint8-fused-mask-rgb-pad8-imagenet-trt/v0",
|
||||
"M4.8Q preprocess",
|
||||
),
|
||||
minimumScore: exact(candidate.minimum_score, 0.25, "M4.8Q threshold"),
|
||||
},
|
||||
execution: {
|
||||
effectiveWorldStateFps: number(execution.effective_world_state_fps, "M4.8Q FPS"),
|
||||
worldStateCompletionP95Ms: number(
|
||||
execution.world_state_completion_p95_ms,
|
||||
"M4.8Q world-state p95",
|
||||
),
|
||||
detectorTotalP95Ms: number(execution.detector_total_p95_ms, "M4.8Q detector p95"),
|
||||
gpuUtilizationP95Percent: number(
|
||||
execution.gpu_utilization_p95_percent,
|
||||
"M4.8Q GPU p95",
|
||||
),
|
||||
gpuMemoryMaximumMib: number(
|
||||
execution.gpu_memory_used_maximum_mib,
|
||||
"M4.8Q VRAM maximum",
|
||||
),
|
||||
additionalInferencePasses: exact(
|
||||
execution.additional_inference_passes,
|
||||
0,
|
||||
"M4.8Q inference passes",
|
||||
),
|
||||
},
|
||||
selection: {
|
||||
caseCount: 24,
|
||||
minimumSequenceSeparation: integer(
|
||||
selection.minimum_sequence_separation,
|
||||
"M4.8Q case separation",
|
||||
),
|
||||
bucketCoverage: numberRecord(selection.selected_bucket_coverage, "M4.8Q bucket coverage"),
|
||||
classCounts: numberRecord(selection.selected_class_counts, "M4.8Q class counts"),
|
||||
},
|
||||
runtime: {
|
||||
deliveryRatio: number(runtime.delivery_ratio, "M4.8Q delivery ratio"),
|
||||
integratedGatePassed: exact(
|
||||
runtime.integrated_runtime_gate_passed,
|
||||
true,
|
||||
"M4.8Q integrated gate",
|
||||
),
|
||||
operatingTargetGatePassed: exact(
|
||||
runtime.operating_target_gate_passed,
|
||||
true,
|
||||
"M4.8Q target gate",
|
||||
),
|
||||
},
|
||||
parity: {
|
||||
precision: number(parity.risk_detection_precision, "M4.8Q parity precision"),
|
||||
recall: number(parity.risk_detection_recall, "M4.8Q parity recall"),
|
||||
meanIou: number(parity.matched_mean_iou, "M4.8Q parity IoU"),
|
||||
},
|
||||
acceptance: {
|
||||
reviewReady: true,
|
||||
independentQualityEvaluated: false,
|
||||
semanticCandidateAccepted: false,
|
||||
},
|
||||
review: { cases },
|
||||
method: method(raw.method),
|
||||
limitations: array(raw.limitations, "M4.8Q limitations").map((item) =>
|
||||
text(item, "M4.8Q limitation")
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM48TRiskQualityResult(
|
||||
resultId: string,
|
||||
{
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
}: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<M48TRiskQualityResult> {
|
||||
if (!/^(?:m48t-risk-quality-temporal-lab|m48q-native-risk-quality-lab)-[a-f0-9]{64}$/.test(resultId)) {
|
||||
throw new M48TContractError("M4.8T result identity недопустима.");
|
||||
}
|
||||
const response = await fetcher(`/api/v1/laboratory/m48t/risk-quality/results/${resultId}`, {
|
||||
method: "GET",
|
||||
headers: { Accept: "application/json" },
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) throw new M48TContractError(`M4.8T недоступен: HTTP ${response.status}.`);
|
||||
const payload: unknown = await response.json();
|
||||
const raw = object(payload, "M4.8T/M4.8Q result");
|
||||
return raw.schema_version === "missioncore.m48q-native-risk-quality-view/v1"
|
||||
? parseNativeResult(payload, resultId)
|
||||
: parseLegacyResult(payload, resultId);
|
||||
}
|
||||
@@ -0,0 +1,671 @@
|
||||
import type { LaboratoryFetch } from "./advancedResults";
|
||||
|
||||
const RESULT_ID = /^m49-physical-safety-playback-[a-f0-9]{64}$/;
|
||||
const SOURCE_RESULT_ID = /^m49-tgs-full-shadow-[a-f0-9]{64}$/;
|
||||
const SCHEMA = "missioncore.m49-physical-safety-playback/v1";
|
||||
const CHUNK_MAGIC = "MCPSCH01";
|
||||
const CHUNK_HEADER_BYTES = 28;
|
||||
const ENDPOINT_ROOT = "/api/v1/laboratory/m49/physical-safety-playback";
|
||||
|
||||
export interface M49PhysicalSafetyPlaybackFrameMetadata {
|
||||
sourceSequence: number;
|
||||
sourceFrameIndex: number;
|
||||
sessionSeconds: number;
|
||||
sampleAvailable: boolean;
|
||||
metrics: Readonly<Record<string, number>>;
|
||||
}
|
||||
|
||||
interface ArtifactDescriptor {
|
||||
url: string;
|
||||
mediaType: string;
|
||||
byteLength: number;
|
||||
sha256: string;
|
||||
}
|
||||
|
||||
interface ChunkDescriptor extends ArtifactDescriptor {
|
||||
index: number;
|
||||
start: number;
|
||||
count: number;
|
||||
headerBytes: 28;
|
||||
format: "mcpsch01-states-u8-aligned-z-bounds-f32le";
|
||||
}
|
||||
|
||||
export interface M49PhysicalSafetyPlaybackManifest {
|
||||
resultId: string;
|
||||
createdAtUtc: string;
|
||||
sourceResultId: string;
|
||||
frameCount: number;
|
||||
cellCount: number;
|
||||
cellSizeM: number;
|
||||
radiusM: number;
|
||||
sourcePaceHz: number;
|
||||
stateCodes: Readonly<Record<string, number>>;
|
||||
chunkFrameCount: 32;
|
||||
startupPrebufferChunkCount: 2;
|
||||
residentChunkCountMax: 3;
|
||||
forwardPrefetchChunkCount: 1;
|
||||
centers: ArtifactDescriptor;
|
||||
frames: ArtifactDescriptor;
|
||||
chunks: readonly ChunkDescriptor[];
|
||||
}
|
||||
|
||||
interface ResidentChunk {
|
||||
descriptor: ChunkDescriptor;
|
||||
states: Uint8Array;
|
||||
zBoundsM: Float32Array;
|
||||
byteLength: number;
|
||||
}
|
||||
|
||||
export interface M49PhysicalSafetyPlaybackFrame {
|
||||
metadata: M49PhysicalSafetyPlaybackFrameMetadata;
|
||||
centersXyM: Float32Array;
|
||||
states: Uint8Array;
|
||||
zBoundsM: Float32Array;
|
||||
cellSizeM: number;
|
||||
radiusM: number;
|
||||
}
|
||||
|
||||
export interface M49PhysicalSafetyPlaybackProgress {
|
||||
phase: "manifest" | "static" | "prebuffer" | "ready" | "seek";
|
||||
residentChunkIndexes: readonly number[];
|
||||
loadedBytes: number;
|
||||
}
|
||||
|
||||
export class M49PhysicalSafetyPlaybackContractError extends Error {}
|
||||
|
||||
function objectValue(value: unknown, label: string): Record<string, unknown> {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(`${label}: ожидался объект.`);
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function text(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(`${label}: ожидалась строка.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function finiteNumber(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(`${label}: ожидалось число.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function integer(value: unknown, label: string): number {
|
||||
const parsed = finiteNumber(value, label);
|
||||
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(`${label}: ожидалось целое число.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function booleanValue(value: unknown, label: string): boolean {
|
||||
if (typeof value !== "boolean") {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(`${label}: ожидался boolean.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function exact<T extends string | number | boolean>(value: unknown, expected: T, label: string): T {
|
||||
if (value !== expected) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(`${label}: нарушен контракт.`);
|
||||
}
|
||||
return expected;
|
||||
}
|
||||
|
||||
function sha256(value: unknown, label: string): string {
|
||||
const parsed = text(value, label);
|
||||
if (!/^[a-f0-9]{64}$/.test(parsed)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(`${label}: SHA-256 недопустим.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function localUrl(value: unknown, expected: string, label: string): string {
|
||||
const parsed = text(value, label);
|
||||
if (parsed !== expected || parsed.includes("worker")) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(`${label}: разрешён только sealed local API.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function descriptor(
|
||||
value: unknown,
|
||||
expectedUrl: string,
|
||||
label: string,
|
||||
): ArtifactDescriptor {
|
||||
const row = objectValue(value, label);
|
||||
return {
|
||||
url: localUrl(row.url, expectedUrl, `${label}.url`),
|
||||
mediaType: text(row.media_type, `${label}.media_type`),
|
||||
byteLength: integer(row.byte_length, `${label}.byte_length`),
|
||||
sha256: sha256(row.sha256, `${label}.sha256`),
|
||||
};
|
||||
}
|
||||
|
||||
async function sha256Hex(buffer: ArrayBuffer): Promise<string> {
|
||||
if (!globalThis.crypto?.subtle) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
"Браузер не поддерживает проверку playback SHA-256.",
|
||||
);
|
||||
}
|
||||
const digest = await globalThis.crypto.subtle.digest("SHA-256", buffer);
|
||||
return [...new Uint8Array(digest)]
|
||||
.map((value) => value.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
async function fetchVerified(
|
||||
artifact: ArtifactDescriptor,
|
||||
fetcher: LaboratoryFetch,
|
||||
signal?: AbortSignal,
|
||||
): Promise<ArrayBuffer> {
|
||||
const response = await fetcher(artifact.url, {
|
||||
method: "GET",
|
||||
headers: { Accept: artifact.mediaType },
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
`Sealed local playback недоступен: HTTP ${response.status}.`,
|
||||
);
|
||||
}
|
||||
const buffer = await response.arrayBuffer();
|
||||
if (buffer.byteLength !== artifact.byteLength) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
"Sealed local playback: получен неверный размер.",
|
||||
);
|
||||
}
|
||||
if (await sha256Hex(buffer) !== artifact.sha256) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
"Sealed local playback: SHA-256 не совпал.",
|
||||
);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function parseStateCodes(value: unknown): Readonly<Record<string, number>> {
|
||||
const row = objectValue(value, "M49 physical-safety state codes");
|
||||
const parsed: Record<string, number> = {};
|
||||
for (const [name, code] of Object.entries(row)) {
|
||||
const stateCode = integer(code, `M49 physical-safety state code ${name}`);
|
||||
if (stateCode > 255) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 state code превышает uint8.");
|
||||
}
|
||||
parsed[name] = stateCode;
|
||||
}
|
||||
if (parsed.UNOBSERVED !== 0 || !Object.keys(parsed).length) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 UNOBSERVED state изменился.");
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
async function fetchManifest(
|
||||
resultId: string,
|
||||
fetcher: LaboratoryFetch,
|
||||
signal?: AbortSignal,
|
||||
): Promise<M49PhysicalSafetyPlaybackManifest> {
|
||||
if (!RESULT_ID.test(resultId)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 physical-safety identity недопустима.");
|
||||
}
|
||||
const base = `${ENDPOINT_ROOT}/${encodeURIComponent(resultId)}`;
|
||||
const response = await fetcher(`${base}/manifest`, {
|
||||
method: "GET",
|
||||
headers: { Accept: "application/json" },
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
`M49 physical-safety manifest недоступен: HTTP ${response.status}.`,
|
||||
);
|
||||
}
|
||||
const payload = objectValue(await response.json(), "M49 physical-safety manifest");
|
||||
exact(payload.schema_version, SCHEMA, "M49 physical-safety schema");
|
||||
exact(payload.result_id, resultId, "M49 physical-safety result");
|
||||
exact(payload.access, "read-only-sealed-local", "M49 physical-safety access");
|
||||
const identity = objectValue(payload.identity, "M49 physical-safety identity");
|
||||
const execution = objectValue(payload.execution, "M49 physical-safety execution");
|
||||
exact(execution.execution_class, "local-sequential-offline", "M49 execution class");
|
||||
exact(execution.worker_role, "realtime-only", "M49 worker role");
|
||||
exact(execution.worker_runtime_dependency, false, "M49 worker dependency");
|
||||
exact(execution.worker_requests_required, 0, "M49 worker requests");
|
||||
const authority = objectValue(payload.authority, "M49 physical-safety authority");
|
||||
exact(authority.commands_enabled, false, "M49 commands");
|
||||
exact(authority.navigation_or_safety_accepted, false, "M49 safety authority");
|
||||
exact(authority.actuation_accepted, false, "M49 actuation authority");
|
||||
const playback = objectValue(payload.playback, "M49 physical-safety playback");
|
||||
exact(playback.coordinate_frame, "map-gravity-local", "M49 coordinate frame");
|
||||
const frameCount = integer(playback.frame_count, "M49 frame count");
|
||||
const cellCount = integer(playback.cell_count, "M49 cell count");
|
||||
if (!frameCount || !cellCount) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 playback не содержит evidence.");
|
||||
}
|
||||
const chunkFrameCount = exact(
|
||||
integer(playback.chunk_frame_count, "M49 chunk frame count"),
|
||||
32,
|
||||
"M49 chunk frame count",
|
||||
);
|
||||
const startupPrebufferChunkCount = exact(
|
||||
integer(playback.startup_prebuffer_chunk_count, "M49 startup prebuffer"),
|
||||
2,
|
||||
"M49 startup prebuffer",
|
||||
);
|
||||
const residentChunkCountMax = exact(
|
||||
integer(playback.resident_chunk_count_max, "M49 resident chunks"),
|
||||
3,
|
||||
"M49 resident chunks",
|
||||
);
|
||||
const forwardPrefetchChunkCount = exact(
|
||||
integer(playback.forward_prefetch_chunk_count, "M49 forward prefetch"),
|
||||
1,
|
||||
"M49 forward prefetch",
|
||||
);
|
||||
const centers = descriptor(playback.centers, `${base}/tracks/centers`, "M49 centers");
|
||||
const centerRow = objectValue(playback.centers, "M49 centers");
|
||||
exact(centerRow.dtype, "<f4", "M49 centers dtype");
|
||||
if (!Array.isArray(centerRow.shape)
|
||||
|| centerRow.shape.length !== 2
|
||||
|| centerRow.shape[0] !== cellCount
|
||||
|| centerRow.shape[1] !== 2
|
||||
|| centers.byteLength !== cellCount * 2 * 4) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 centers shape изменилась.");
|
||||
}
|
||||
const frames = descriptor(playback.frames, `${base}/tracks/frames`, "M49 frames");
|
||||
const frameRow = objectValue(playback.frames, "M49 frames");
|
||||
exact(frameRow.dtype, "ndjson", "M49 frames dtype");
|
||||
if (!Array.isArray(frameRow.shape)
|
||||
|| frameRow.shape.length !== 1
|
||||
|| frameRow.shape[0] !== frameCount) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 frames shape изменилась.");
|
||||
}
|
||||
if (!Array.isArray(playback.chunks)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 chunk catalog отсутствует.");
|
||||
}
|
||||
const expectedChunkCount = Math.ceil(frameCount / chunkFrameCount);
|
||||
if (playback.chunks.length !== expectedChunkCount) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 chunk accounting нарушен.");
|
||||
}
|
||||
const chunks = playback.chunks.map((value, index): ChunkDescriptor => {
|
||||
const row = objectValue(value, `M49 chunk ${index}`);
|
||||
const common = descriptor(value, `${base}/chunks/${index}`, `M49 chunk ${index}`);
|
||||
const start = index * chunkFrameCount;
|
||||
const count = Math.min(chunkFrameCount, frameCount - start);
|
||||
exact(integer(row.index, `M49 chunk ${index}.index`), index, `M49 chunk ${index}.index`);
|
||||
exact(integer(row.start, `M49 chunk ${index}.start`), start, `M49 chunk ${index}.start`);
|
||||
exact(integer(row.count, `M49 chunk ${index}.count`), count, `M49 chunk ${index}.count`);
|
||||
return {
|
||||
...common,
|
||||
index,
|
||||
start,
|
||||
count,
|
||||
headerBytes: exact(
|
||||
integer(row.header_bytes, `M49 chunk ${index}.header`),
|
||||
CHUNK_HEADER_BYTES,
|
||||
`M49 chunk ${index}.header`,
|
||||
),
|
||||
format: exact(
|
||||
row.format,
|
||||
"mcpsch01-states-u8-aligned-z-bounds-f32le",
|
||||
`M49 chunk ${index}.format`,
|
||||
),
|
||||
};
|
||||
});
|
||||
return {
|
||||
resultId,
|
||||
createdAtUtc: text(payload.created_at_utc, "M49 physical-safety created"),
|
||||
sourceResultId: text(identity.source_result_id, "M49 physical-safety source"),
|
||||
frameCount,
|
||||
cellCount,
|
||||
cellSizeM: finiteNumber(playback.cell_size_m, "M49 cell size"),
|
||||
radiusM: finiteNumber(playback.radius_m, "M49 radius"),
|
||||
sourcePaceHz: finiteNumber(playback.source_pace_hz, "M49 source pace"),
|
||||
stateCodes: parseStateCodes(playback.state_codes),
|
||||
chunkFrameCount,
|
||||
startupPrebufferChunkCount,
|
||||
residentChunkCountMax,
|
||||
forwardPrefetchChunkCount,
|
||||
centers,
|
||||
frames,
|
||||
chunks,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM49PhysicalSafetyPlaybackIdForSource(
|
||||
sourceResultId: string,
|
||||
{
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
}: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<string | null> {
|
||||
if (!SOURCE_RESULT_ID.test(sourceResultId)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 source identity недопустима.");
|
||||
}
|
||||
const response = await fetcher(
|
||||
`${ENDPOINT_ROOT}/results?limit=2&source_result_id=${encodeURIComponent(sourceResultId)}`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
`M49 physical-safety catalog недоступен: HTTP ${response.status}.`,
|
||||
);
|
||||
}
|
||||
const payload = objectValue(await response.json(), "M49 physical-safety catalog");
|
||||
exact(
|
||||
payload.schema_version,
|
||||
"missioncore.m49-physical-safety-playback-catalog/v1",
|
||||
"M49 physical-safety catalog schema",
|
||||
);
|
||||
exact(payload.worker_runtime_dependency, false, "M49 physical-safety catalog worker");
|
||||
exact(payload.access, "read-only-sealed-local", "M49 physical-safety catalog access");
|
||||
if (!Array.isArray(payload.items)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 physical-safety catalog изменился.");
|
||||
}
|
||||
if (!payload.items.length) return null;
|
||||
if (payload.items.length !== 1) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
"M49 physical-safety source имеет несколько активных playback artifacts.",
|
||||
);
|
||||
}
|
||||
const item = objectValue(payload.items[0], "M49 physical-safety catalog item");
|
||||
exact(item.source_result_id, sourceResultId, "M49 physical-safety catalog source");
|
||||
exact(item.worker_runtime_dependency, false, "M49 physical-safety item worker");
|
||||
exact(item.navigation_or_safety_accepted, false, "M49 physical-safety item authority");
|
||||
const resultId = text(item.result_id, "M49 physical-safety catalog result");
|
||||
if (!RESULT_ID.test(resultId)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
"M49 physical-safety catalog result недопустим.",
|
||||
);
|
||||
}
|
||||
return resultId;
|
||||
}
|
||||
|
||||
function parseFrames(
|
||||
buffer: ArrayBuffer,
|
||||
frameCount: number,
|
||||
): readonly M49PhysicalSafetyPlaybackFrameMetadata[] {
|
||||
const lines = new TextDecoder().decode(buffer).trim().split("\n");
|
||||
if (lines.length !== frameCount) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 frame catalog изменил размер.");
|
||||
}
|
||||
return lines.map((line, sourceSequence) => {
|
||||
const row = objectValue(JSON.parse(line), `M49 frame ${sourceSequence}`);
|
||||
const metrics: Record<string, number> = {};
|
||||
for (const [name, value] of Object.entries(row)) {
|
||||
if (name.endsWith("_count") && typeof value === "number" && Number.isFinite(value)) {
|
||||
metrics[name] = value;
|
||||
}
|
||||
}
|
||||
return {
|
||||
sourceSequence,
|
||||
sourceFrameIndex: integer(row.source_frame_index, `M49 frame ${sourceSequence}.source`),
|
||||
sessionSeconds: finiteNumber(row.session_seconds, `M49 frame ${sourceSequence}.time`),
|
||||
sampleAvailable: booleanValue(
|
||||
row.sample_available,
|
||||
`M49 frame ${sourceSequence}.available`,
|
||||
),
|
||||
metrics,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function parseChunk(
|
||||
buffer: ArrayBuffer,
|
||||
descriptorValue: ChunkDescriptor,
|
||||
cellCount: number,
|
||||
frames: readonly M49PhysicalSafetyPlaybackFrameMetadata[],
|
||||
admittedStateCodes: ReadonlySet<number>,
|
||||
): ResidentChunk {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
if (bytes.byteLength < CHUNK_HEADER_BYTES
|
||||
|| new TextDecoder("latin1").decode(bytes.subarray(0, 8)) !== CHUNK_MAGIC) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 chunk signature изменилась.");
|
||||
}
|
||||
const view = new DataView(buffer);
|
||||
const start = view.getUint32(8, true);
|
||||
const count = view.getUint32(12, true);
|
||||
const cells = view.getUint32(16, true);
|
||||
const stateBytes = view.getUint32(20, true);
|
||||
const zBytes = view.getUint32(24, true);
|
||||
const expectedStateBytes = count * cellCount;
|
||||
const expectedZBytes = count * cellCount * 2 * 4;
|
||||
const zOffset = CHUNK_HEADER_BYTES + stateBytes
|
||||
+ ((4 - ((CHUNK_HEADER_BYTES + stateBytes) % 4)) % 4);
|
||||
if (start !== descriptorValue.start
|
||||
|| count !== descriptorValue.count
|
||||
|| cells !== cellCount
|
||||
|| stateBytes !== expectedStateBytes
|
||||
|| zBytes !== expectedZBytes
|
||||
|| zOffset + zBytes !== bytes.byteLength) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 chunk layout изменился.");
|
||||
}
|
||||
const states = new Uint8Array(buffer, CHUNK_HEADER_BYTES, stateBytes);
|
||||
const zBoundsM = new Float32Array(buffer, zOffset, count * cellCount * 2);
|
||||
for (let localFrame = 0; localFrame < count; localFrame += 1) {
|
||||
const stateStart = localFrame * cellCount;
|
||||
const zStart = localFrame * cellCount * 2;
|
||||
for (let cell = 0; cell < cellCount; cell += 1) {
|
||||
const state = states[stateStart + cell];
|
||||
if (!admittedStateCodes.has(state)) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 chunk содержит неизвестный state.");
|
||||
}
|
||||
if (!frames[start + localFrame].sampleAvailable
|
||||
&& (state !== 0
|
||||
|| Number.isFinite(zBoundsM[zStart + cell * 2])
|
||||
|| Number.isFinite(zBoundsM[zStart + cell * 2 + 1]))) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError(
|
||||
"M49 missing sample перестал быть fail-closed.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { descriptor: descriptorValue, states, zBoundsM, byteLength: buffer.byteLength };
|
||||
}
|
||||
|
||||
export class M49PhysicalSafetyPlaybackBuffer {
|
||||
readonly manifest: M49PhysicalSafetyPlaybackManifest;
|
||||
readonly centersXyM: Float32Array;
|
||||
readonly frames: readonly M49PhysicalSafetyPlaybackFrameMetadata[];
|
||||
|
||||
private readonly fetcher: LaboratoryFetch;
|
||||
private readonly signal: AbortSignal | undefined;
|
||||
private readonly onProgress: ((value: M49PhysicalSafetyPlaybackProgress) => void) | undefined;
|
||||
private readonly chunks = new Map<number, ResidentChunk>();
|
||||
private readonly pending = new Map<number, Promise<ResidentChunk>>();
|
||||
private readonly admittedStateCodes: ReadonlySet<number>;
|
||||
private staticBytes: number;
|
||||
private preparedWindowKey: string | null = null;
|
||||
private pendingPrepare: { key: string; promise: Promise<void> } | null = null;
|
||||
|
||||
private constructor(
|
||||
manifest: M49PhysicalSafetyPlaybackManifest,
|
||||
centersXyM: Float32Array,
|
||||
frames: readonly M49PhysicalSafetyPlaybackFrameMetadata[],
|
||||
fetcher: LaboratoryFetch,
|
||||
signal: AbortSignal | undefined,
|
||||
onProgress: ((value: M49PhysicalSafetyPlaybackProgress) => void) | undefined,
|
||||
) {
|
||||
this.manifest = manifest;
|
||||
this.centersXyM = centersXyM;
|
||||
this.frames = frames;
|
||||
this.fetcher = fetcher;
|
||||
this.signal = signal;
|
||||
this.onProgress = onProgress;
|
||||
this.admittedStateCodes = new Set(Object.values(manifest.stateCodes));
|
||||
this.staticBytes = centersXyM.byteLength + manifest.frames.byteLength;
|
||||
}
|
||||
|
||||
static async open(
|
||||
resultId: string,
|
||||
{
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
onProgress,
|
||||
}: {
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
onProgress?: (value: M49PhysicalSafetyPlaybackProgress) => void;
|
||||
} = {},
|
||||
): Promise<M49PhysicalSafetyPlaybackBuffer> {
|
||||
onProgress?.({ phase: "manifest", residentChunkIndexes: [], loadedBytes: 0 });
|
||||
const manifest = await fetchManifest(resultId, fetcher, signal);
|
||||
const [centersBuffer, framesBuffer] = await Promise.all([
|
||||
fetchVerified(manifest.centers, fetcher, signal),
|
||||
fetchVerified(manifest.frames, fetcher, signal),
|
||||
]);
|
||||
onProgress?.({
|
||||
phase: "static",
|
||||
residentChunkIndexes: [],
|
||||
loadedBytes: centersBuffer.byteLength + framesBuffer.byteLength,
|
||||
});
|
||||
const centersXyM = new Float32Array(centersBuffer);
|
||||
const frames = parseFrames(framesBuffer, manifest.frameCount);
|
||||
const playback = new M49PhysicalSafetyPlaybackBuffer(
|
||||
manifest,
|
||||
centersXyM,
|
||||
frames,
|
||||
fetcher,
|
||||
signal,
|
||||
onProgress,
|
||||
);
|
||||
const startupCount = Math.min(
|
||||
manifest.startupPrebufferChunkCount,
|
||||
manifest.chunks.length,
|
||||
);
|
||||
await Promise.all(Array.from(
|
||||
{ length: startupCount },
|
||||
(_, index) => playback.loadChunk(index, "prebuffer"),
|
||||
));
|
||||
playback.emit("ready");
|
||||
return playback;
|
||||
}
|
||||
|
||||
get residentChunkIndexes(): readonly number[] {
|
||||
return [...this.chunks.keys()].sort((left, right) => left - right);
|
||||
}
|
||||
|
||||
get residentByteLength(): number {
|
||||
return this.staticBytes
|
||||
+ [...this.chunks.values()].reduce((sum, chunk) => sum + chunk.byteLength, 0);
|
||||
}
|
||||
|
||||
async prepare(sourceSequence: number): Promise<void> {
|
||||
const chunkIndex = this.chunkIndex(sourceSequence);
|
||||
const nextIndex = chunkIndex + this.manifest.forwardPrefetchChunkCount;
|
||||
const indexes = [chunkIndex, nextIndex].filter(
|
||||
(index) => index < this.manifest.chunks.length,
|
||||
);
|
||||
const key = indexes.join(":");
|
||||
if (this.preparedWindowKey === key && indexes.every((index) => this.chunks.has(index))) {
|
||||
return;
|
||||
}
|
||||
if (this.pendingPrepare?.key === key) return this.pendingPrepare.promise;
|
||||
const promise = Promise.all(indexes.map((index) => this.loadChunk(index, "seek")))
|
||||
.then(() => {
|
||||
this.trim(new Set(indexes));
|
||||
this.preparedWindowKey = key;
|
||||
this.emit("seek");
|
||||
})
|
||||
.finally(() => {
|
||||
if (this.pendingPrepare?.key === key) this.pendingPrepare = null;
|
||||
});
|
||||
this.pendingPrepare = { key, promise };
|
||||
return promise;
|
||||
}
|
||||
|
||||
async frame(sourceSequence: number): Promise<M49PhysicalSafetyPlaybackFrame> {
|
||||
const chunkIndex = this.chunkIndex(sourceSequence);
|
||||
const chunk = await this.loadChunk(chunkIndex, "seek");
|
||||
const frame = this.frameFromChunk(sourceSequence, chunk);
|
||||
const nextIndex = chunkIndex + this.manifest.forwardPrefetchChunkCount;
|
||||
if (nextIndex < this.manifest.chunks.length && !this.chunks.has(nextIndex)) {
|
||||
void this.loadChunk(nextIndex, "seek").catch(() => undefined);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
frameIfResident(sourceSequence: number): M49PhysicalSafetyPlaybackFrame | null {
|
||||
const chunkIndex = this.chunkIndex(sourceSequence);
|
||||
const chunk = this.chunks.get(chunkIndex);
|
||||
return chunk ? this.frameFromChunk(sourceSequence, chunk) : null;
|
||||
}
|
||||
|
||||
private frameFromChunk(
|
||||
sourceSequence: number,
|
||||
chunk: ResidentChunk,
|
||||
): M49PhysicalSafetyPlaybackFrame {
|
||||
const localFrame = sourceSequence - chunk.descriptor.start;
|
||||
const stateOffset = localFrame * this.manifest.cellCount;
|
||||
const zOffset = stateOffset * 2;
|
||||
return {
|
||||
metadata: this.frames[sourceSequence],
|
||||
centersXyM: this.centersXyM,
|
||||
states: chunk.states.subarray(stateOffset, stateOffset + this.manifest.cellCount),
|
||||
zBoundsM: chunk.zBoundsM.subarray(zOffset, zOffset + this.manifest.cellCount * 2),
|
||||
cellSizeM: this.manifest.cellSizeM,
|
||||
radiusM: this.manifest.radiusM,
|
||||
};
|
||||
}
|
||||
|
||||
private chunkIndex(sourceSequence: number): number {
|
||||
if (!Number.isSafeInteger(sourceSequence)
|
||||
|| sourceSequence < 0
|
||||
|| sourceSequence >= this.manifest.frameCount) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 source sequence недопустима.");
|
||||
}
|
||||
return Math.floor(sourceSequence / this.manifest.chunkFrameCount);
|
||||
}
|
||||
|
||||
private async loadChunk(
|
||||
index: number,
|
||||
phase: "prebuffer" | "seek",
|
||||
): Promise<ResidentChunk> {
|
||||
const existing = this.chunks.get(index);
|
||||
if (existing) {
|
||||
this.chunks.delete(index);
|
||||
this.chunks.set(index, existing);
|
||||
return existing;
|
||||
}
|
||||
const inflight = this.pending.get(index);
|
||||
if (inflight) return inflight;
|
||||
const descriptorValue = this.manifest.chunks[index];
|
||||
if (!descriptorValue) {
|
||||
throw new M49PhysicalSafetyPlaybackContractError("M49 chunk отсутствует.");
|
||||
}
|
||||
const promise = fetchVerified(descriptorValue, this.fetcher, this.signal)
|
||||
.then((buffer) => parseChunk(
|
||||
buffer,
|
||||
descriptorValue,
|
||||
this.manifest.cellCount,
|
||||
this.frames,
|
||||
this.admittedStateCodes,
|
||||
))
|
||||
.then((chunk) => {
|
||||
this.chunks.set(index, chunk);
|
||||
this.trim(new Set([index]));
|
||||
this.emit(phase);
|
||||
return chunk;
|
||||
})
|
||||
.finally(() => this.pending.delete(index));
|
||||
this.pending.set(index, promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
private trim(protectedIndexes: ReadonlySet<number>): void {
|
||||
while (this.chunks.size > this.manifest.residentChunkCountMax) {
|
||||
const removable = [...this.chunks.keys()].find((index) => !protectedIndexes.has(index));
|
||||
if (removable === undefined) break;
|
||||
this.chunks.delete(removable);
|
||||
}
|
||||
}
|
||||
|
||||
private emit(phase: M49PhysicalSafetyPlaybackProgress["phase"]): void {
|
||||
this.onProgress?.({
|
||||
phase,
|
||||
residentChunkIndexes: this.residentChunkIndexes,
|
||||
loadedBytes: this.residentByteLength,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
import type { LaboratoryFetch } from "./advancedResults";
|
||||
|
||||
const RESULT_ID = /^m49-tgs-fail-closed-[a-f0-9]{64}$/;
|
||||
|
||||
export type M49TgsProfile = "current_increment" | "causal_rolling_1s";
|
||||
export type M49TgsStateCode = 0 | 1 | 2 | 3;
|
||||
export type M49TgsPointStateCode = 1 | 2 | 3;
|
||||
|
||||
export interface M49TgsAnchorSummary {
|
||||
anchorFrameIndex: number;
|
||||
slot: number;
|
||||
pointCount: number;
|
||||
groundPointCount: number;
|
||||
nongroundPointCount: number;
|
||||
rejectedPointCount: number;
|
||||
groundCellCount: number;
|
||||
nongroundCellCount: number;
|
||||
rejectedCellCount: number;
|
||||
unobservedCellCount: number;
|
||||
allPointsAccounted: true;
|
||||
}
|
||||
|
||||
export interface M49TgsFailClosedResult {
|
||||
resultId: string;
|
||||
createdAtUtc: string;
|
||||
source: {
|
||||
sourceId: "RAVNOVES00";
|
||||
sourceSessionId: "20260720T065719Z_viewer_live";
|
||||
sourcePackSha256: string;
|
||||
linkedVisualResultId: string;
|
||||
anchorFrameIndices: readonly number[];
|
||||
};
|
||||
configuration: {
|
||||
profileId: string;
|
||||
configSha256: string;
|
||||
coordinateFrame: "map-gravity-local";
|
||||
primaryProfile: "causal_rolling_1s";
|
||||
cellSizeM: number;
|
||||
radiusM: number;
|
||||
};
|
||||
execution: {
|
||||
worker: "Worker 006";
|
||||
device: "cpu";
|
||||
gpuUsed: false;
|
||||
wrapperElapsedSeconds: number;
|
||||
};
|
||||
metrics: {
|
||||
anchorCount: number;
|
||||
anchorProfileCount: number;
|
||||
allEligiblePointsAccounted: true;
|
||||
costmapCellCount: number;
|
||||
processWallCurrentP50Ms: number;
|
||||
processWallCurrentMaxMs: number;
|
||||
processWallRollingP50Ms: number;
|
||||
processWallRollingMaxMs: number;
|
||||
processMaxRssKib: number;
|
||||
primary: readonly M49TgsAnchorSummary[];
|
||||
};
|
||||
acceptance: {
|
||||
representationComplete: true;
|
||||
allPointsAccounted: true;
|
||||
aosAbsent: true;
|
||||
gpuAbsent: true;
|
||||
visualQualityAccepted: false;
|
||||
traversabilityAccepted: false;
|
||||
};
|
||||
decision: {
|
||||
state: "visual-review-required";
|
||||
candidateRetained: true;
|
||||
nextAction: string;
|
||||
};
|
||||
limitations: readonly string[];
|
||||
}
|
||||
|
||||
export interface M49TgsAnchorSpatial {
|
||||
resultId: string;
|
||||
anchorFrameIndex: number;
|
||||
sourceSequence: number;
|
||||
profile: M49TgsProfile;
|
||||
coordinateFrame: "map-gravity-local";
|
||||
pointsXyzM: readonly (readonly [number, number, number])[];
|
||||
pointStates: readonly M49TgsPointStateCode[];
|
||||
costmap: {
|
||||
cellSizeM: number;
|
||||
radiusM: number;
|
||||
centersXyM: readonly (readonly [number, number])[];
|
||||
states: readonly M49TgsStateCode[];
|
||||
zBoundsM: readonly (readonly [number | null, number | null])[];
|
||||
};
|
||||
allPointsAccounted: true;
|
||||
aosUsed: false;
|
||||
}
|
||||
|
||||
export class M49TgsContractError extends Error {}
|
||||
|
||||
function objectValue(value: unknown, label: string): Record<string, unknown> {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
throw new M49TgsContractError(`${label}: ожидался объект.`);
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function text(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new M49TgsContractError(`${label}: ожидалась строка.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function exact<T extends string | boolean>(value: unknown, expected: T, label: string): T {
|
||||
if (value !== expected) throw new M49TgsContractError(`${label}: нарушен контракт.`);
|
||||
return expected;
|
||||
}
|
||||
|
||||
function numberValue(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
throw new M49TgsContractError(`${label}: ожидалось число.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function integer(value: unknown, label: string): number {
|
||||
const parsed = numberValue(value, label);
|
||||
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
||||
throw new M49TgsContractError(`${label}: ожидалось целое число.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function sha256(value: unknown, label: string): string {
|
||||
const parsed = text(value, label);
|
||||
if (!/^[a-f0-9]{64}$/.test(parsed)) {
|
||||
throw new M49TgsContractError(`${label}: неверный SHA-256.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function resultId(value: unknown): string {
|
||||
const parsed = text(value, "M49 result id");
|
||||
if (!RESULT_ID.test(parsed)) throw new M49TgsContractError("M49 identity недопустима.");
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function numbers(value: unknown, size: number, label: string): number[] {
|
||||
if (!Array.isArray(value) || value.length !== size) {
|
||||
throw new M49TgsContractError(`${label}: неверная размерность.`);
|
||||
}
|
||||
return value.map((item) => numberValue(item, label));
|
||||
}
|
||||
|
||||
function anchor(value: unknown, label: string): M49TgsAnchorSummary {
|
||||
const row = objectValue(value, label);
|
||||
exact(row.profile_id, "causal_rolling_1s", `${label}.profile`);
|
||||
exact(row.all_points_accounted, true, `${label}.accounting`);
|
||||
const parsed: M49TgsAnchorSummary = {
|
||||
anchorFrameIndex: integer(row.anchor_frame_index, `${label}.anchor`),
|
||||
slot: integer(row.slot, `${label}.slot`),
|
||||
pointCount: integer(row.point_count, `${label}.points`),
|
||||
groundPointCount: integer(row.ground_point_count, `${label}.ground points`),
|
||||
nongroundPointCount: integer(row.nonground_point_count, `${label}.nonground points`),
|
||||
rejectedPointCount: integer(row.rejected_point_count, `${label}.rejected points`),
|
||||
groundCellCount: integer(row.ground_cell_count, `${label}.ground cells`),
|
||||
nongroundCellCount: integer(row.nonground_cell_count, `${label}.nonground cells`),
|
||||
rejectedCellCount: integer(row.rejected_cell_count, `${label}.rejected cells`),
|
||||
unobservedCellCount: integer(row.unobserved_cell_count, `${label}.unobserved cells`),
|
||||
allPointsAccounted: true,
|
||||
};
|
||||
if (
|
||||
parsed.groundPointCount + parsed.nongroundPointCount + parsed.rejectedPointCount
|
||||
!== parsed.pointCount
|
||||
|| parsed.groundCellCount + parsed.nongroundCellCount
|
||||
+ parsed.rejectedCellCount + parsed.unobservedCellCount !== 2244
|
||||
) {
|
||||
throw new M49TgsContractError(`${label}: fail-closed accounting нарушен.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export async function fetchM49TgsFailClosedResult(
|
||||
id: string,
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<M49TgsFailClosedResult> {
|
||||
if (!RESULT_ID.test(id)) throw new M49TgsContractError("M49 identity недопустима.");
|
||||
const response = await fetcher(
|
||||
`/api/v1/laboratory/m49/tgs-fail-closed/${encodeURIComponent(id)}`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) throw new M49TgsContractError(`M49 TGS недоступен: HTTP ${response.status}.`);
|
||||
const payload = objectValue(await response.json(), "M49 TGS");
|
||||
exact(payload.schema_version, "missioncore.m49-tgs-fail-closed-view/v1", "M49 schema");
|
||||
exact(payload.result_id, id, "M49 result");
|
||||
exact(payload.ground_truth, false, "M49 ground truth");
|
||||
exact(payload.access, "read-only", "M49 access");
|
||||
const source = objectValue(payload.source, "M49 source");
|
||||
const configuration = objectValue(payload.configuration, "M49 configuration");
|
||||
const execution = objectValue(payload.execution, "M49 execution");
|
||||
const metrics = objectValue(payload.metrics, "M49 metrics");
|
||||
const acceptance = objectValue(payload.acceptance, "M49 acceptance");
|
||||
const decision = objectValue(payload.decision, "M49 decision");
|
||||
if (!Array.isArray(source.anchor_frame_indices) || !Array.isArray(metrics.primary)) {
|
||||
throw new M49TgsContractError("M49 anchors: ожидался массив.");
|
||||
}
|
||||
if (!Array.isArray(payload.limitations)) {
|
||||
throw new M49TgsContractError("M49 limitations: ожидался массив.");
|
||||
}
|
||||
const anchorFrameIndices = source.anchor_frame_indices.map(
|
||||
(item, index) => integer(item, `M49 anchor ${index}`),
|
||||
);
|
||||
const primary = metrics.primary.map((item, index) => anchor(item, `M49 primary ${index}`));
|
||||
if (
|
||||
anchorFrameIndices.length !== 10
|
||||
|| new Set(anchorFrameIndices).size !== 10
|
||||
|| primary.length !== 10
|
||||
|| integer(metrics.anchor_count, "M49 anchor count") !== 10
|
||||
|| integer(metrics.anchor_profile_count, "M49 profile count") !== 20
|
||||
|| integer(metrics.costmap_cell_count, "M49 costmap cells") !== 2244
|
||||
|| primary.some((item, index) => item.anchorFrameIndex !== anchorFrameIndices[index])
|
||||
) {
|
||||
throw new M49TgsContractError("M49 anchor set или costmap contract нарушен.");
|
||||
}
|
||||
return {
|
||||
resultId: resultId(payload.result_id),
|
||||
createdAtUtc: text(payload.created_at_utc, "M49 created"),
|
||||
source: {
|
||||
sourceId: exact(source.source_id, "RAVNOVES00", "M49 source id"),
|
||||
sourceSessionId: exact(
|
||||
source.source_session_id,
|
||||
"20260720T065719Z_viewer_live",
|
||||
"M49 source session",
|
||||
),
|
||||
sourcePackSha256: sha256(source.source_pack_sha256, "M49 source pack"),
|
||||
linkedVisualResultId: text(source.linked_visual_result_id, "M49 visual result"),
|
||||
anchorFrameIndices,
|
||||
},
|
||||
configuration: {
|
||||
profileId: text(configuration.profile_id, "M49 profile"),
|
||||
configSha256: sha256(configuration.config_sha256, "M49 config"),
|
||||
coordinateFrame: exact(configuration.coordinate_frame, "map-gravity-local", "M49 frame"),
|
||||
primaryProfile: exact(configuration.primary_profile, "causal_rolling_1s", "M49 primary"),
|
||||
cellSizeM: numberValue(configuration.cell_size_m, "M49 cell size"),
|
||||
radiusM: numberValue(configuration.radius_m, "M49 radius"),
|
||||
},
|
||||
execution: {
|
||||
worker: exact(execution.worker, "Worker 006", "M49 worker"),
|
||||
device: exact(execution.device, "cpu", "M49 device"),
|
||||
gpuUsed: exact(execution.gpu_used, false, "M49 GPU"),
|
||||
wrapperElapsedSeconds: numberValue(execution.wrapper_elapsed_seconds, "M49 wall"),
|
||||
},
|
||||
metrics: {
|
||||
anchorCount: 10,
|
||||
anchorProfileCount: 20,
|
||||
allEligiblePointsAccounted: exact(metrics.all_eligible_points_accounted, true, "M49 accounting"),
|
||||
costmapCellCount: 2244,
|
||||
processWallCurrentP50Ms: numberValue(metrics.process_wall_current_p50_ms, "M49 current p50"),
|
||||
processWallCurrentMaxMs: numberValue(metrics.process_wall_current_max_ms, "M49 current max"),
|
||||
processWallRollingP50Ms: numberValue(metrics.process_wall_rolling_p50_ms, "M49 rolling p50"),
|
||||
processWallRollingMaxMs: numberValue(metrics.process_wall_rolling_max_ms, "M49 rolling max"),
|
||||
processMaxRssKib: integer(metrics.process_max_rss_kib, "M49 RSS"),
|
||||
primary,
|
||||
},
|
||||
acceptance: {
|
||||
representationComplete: exact(acceptance.representation_complete, true, "M49 representation"),
|
||||
allPointsAccounted: exact(acceptance.all_points_accounted, true, "M49 points"),
|
||||
aosAbsent: exact(acceptance.aos_absent, true, "M49 AOS"),
|
||||
gpuAbsent: exact(acceptance.gpu_absent, true, "M49 GPU absent"),
|
||||
visualQualityAccepted: exact(acceptance.visual_quality_accepted, false, "M49 visual quality"),
|
||||
traversabilityAccepted: exact(acceptance.traversability_accepted, false, "M49 traversability"),
|
||||
},
|
||||
decision: {
|
||||
state: exact(decision.state, "visual-review-required", "M49 decision"),
|
||||
candidateRetained: exact(decision.candidate_retained, true, "M49 retained"),
|
||||
nextAction: text(decision.next_action, "M49 next action"),
|
||||
},
|
||||
limitations: payload.limitations.map((item, index) => text(item, `M49 limitation ${index}`)),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM49TgsAnchorSpatial(
|
||||
id: string,
|
||||
anchorFrameIndex: number,
|
||||
profile: M49TgsProfile = "causal_rolling_1s",
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<M49TgsAnchorSpatial> {
|
||||
if (!RESULT_ID.test(id) || !Number.isSafeInteger(anchorFrameIndex) || anchorFrameIndex < 0) {
|
||||
throw new M49TgsContractError("M49 anchor identity недопустима.");
|
||||
}
|
||||
const response = await fetcher(
|
||||
`/api/v1/laboratory/m49/tgs-fail-closed/${encodeURIComponent(id)}/anchors/${anchorFrameIndex}/spatial?profile=${encodeURIComponent(profile)}`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) throw new M49TgsContractError(`M49 anchor недоступен: HTTP ${response.status}.`);
|
||||
const payload = objectValue(await response.json(), "M49 anchor");
|
||||
exact(payload.schema_version, "missioncore.m49-tgs-anchor-spatial/v1", "M49 anchor schema");
|
||||
exact(payload.result_id, id, "M49 anchor result");
|
||||
exact(payload.coordinate_frame, "map-gravity-local", "M49 anchor frame");
|
||||
exact(payload.all_points_accounted, true, "M49 anchor accounting");
|
||||
exact(payload.aos_used, false, "M49 anchor AOS");
|
||||
if (!Array.isArray(payload.points_xyz_m) || !Array.isArray(payload.point_states)) {
|
||||
throw new M49TgsContractError("M49 points: ожидался массив.");
|
||||
}
|
||||
const costmap = objectValue(payload.costmap, "M49 costmap");
|
||||
if (!Array.isArray(costmap.centers_xy_m) || !Array.isArray(costmap.states) || !Array.isArray(costmap.z_bounds_m)) {
|
||||
throw new M49TgsContractError("M49 costmap arrays: нарушен контракт.");
|
||||
}
|
||||
const points = payload.points_xyz_m.map((item, index) => numbers(item, 3, `M49 point ${index}`) as [number, number, number]);
|
||||
const pointStates = payload.point_states.map((item, index) => {
|
||||
const state = integer(item, `M49 point state ${index}`);
|
||||
if (state !== 1 && state !== 2 && state !== 3) throw new M49TgsContractError("M49 point state неизвестен.");
|
||||
return state;
|
||||
});
|
||||
if (points.length !== pointStates.length) throw new M49TgsContractError("M49 point accounting нарушен.");
|
||||
const centers = costmap.centers_xy_m.map((item, index) => numbers(item, 2, `M49 cell ${index}`) as [number, number]);
|
||||
const states = costmap.states.map((item, index) => {
|
||||
const state = integer(item, `M49 cell state ${index}`);
|
||||
if (state !== 0 && state !== 1 && state !== 2 && state !== 3) throw new M49TgsContractError("M49 cell state неизвестен.");
|
||||
return state;
|
||||
});
|
||||
const zBounds = costmap.z_bounds_m.map((item, index) => {
|
||||
if (!Array.isArray(item) || item.length !== 2) throw new M49TgsContractError(`M49 z ${index}: размерность.`);
|
||||
return item.map((value) => value === null ? null : numberValue(value, `M49 z ${index}`)) as [number | null, number | null];
|
||||
});
|
||||
if (
|
||||
centers.length !== 2244
|
||||
|| centers.length !== states.length
|
||||
|| centers.length !== zBounds.length
|
||||
|| integer(payload.anchor_frame_index, "M49 anchor frame") !== anchorFrameIndex
|
||||
|| integer(payload.source_sequence, "M49 source sequence") !== anchorFrameIndex
|
||||
) {
|
||||
throw new M49TgsContractError("M49 costmap accounting нарушен.");
|
||||
}
|
||||
return {
|
||||
resultId: id,
|
||||
anchorFrameIndex,
|
||||
sourceSequence: anchorFrameIndex,
|
||||
profile: exact(payload.profile, profile, "M49 profile"),
|
||||
coordinateFrame: "map-gravity-local",
|
||||
pointsXyzM: points,
|
||||
pointStates,
|
||||
costmap: {
|
||||
cellSizeM: numberValue(costmap.cell_size_m, "M49 cell size"),
|
||||
radiusM: numberValue(costmap.radius_m, "M49 radius"),
|
||||
centersXyM: centers,
|
||||
states,
|
||||
zBoundsM: zBounds,
|
||||
},
|
||||
allPointsAccounted: true,
|
||||
aosUsed: false,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,658 @@
|
||||
import type { LaboratoryFetch } from "./advancedResults";
|
||||
|
||||
const RESULT_ID = /^m49-tgs-full-shadow-[a-f0-9]{64}$/;
|
||||
const SEMANTIC_RESULT_ID = /^e47-semantic-slam-[a-f0-9]{64}$/;
|
||||
|
||||
export type M49TgsFullShadowStateCode = 0 | 1 | 2 | 3;
|
||||
|
||||
export interface M49TgsFullShadowResult {
|
||||
resultId: string;
|
||||
createdAtUtc: string;
|
||||
source: {
|
||||
sourcePackSha256: string;
|
||||
linkedVisualResultId: string;
|
||||
linkedSemanticResultId: string;
|
||||
};
|
||||
configuration: {
|
||||
configSha256: string;
|
||||
cellSizeM: number;
|
||||
radiusM: number;
|
||||
historySeconds: number;
|
||||
};
|
||||
execution: {
|
||||
wrapperElapsedSeconds: number;
|
||||
};
|
||||
timeline: {
|
||||
frameCount: 4489;
|
||||
availableLidarFrameCount: 3928;
|
||||
missingLidarFrameCount: 561;
|
||||
durationSeconds: number;
|
||||
effectiveFps: number;
|
||||
};
|
||||
pointAccounting: {
|
||||
eligible: number;
|
||||
ground: number;
|
||||
nonground: number;
|
||||
rejected: number;
|
||||
unaccounted: 0;
|
||||
};
|
||||
performance: {
|
||||
candidateTgsMs: { p50: number; p95: number; p99: number; max: number };
|
||||
completionAgeMs: { p50: number; p95: number; p99: number; max: number };
|
||||
capacityDropCount: number;
|
||||
};
|
||||
acceptance: {
|
||||
representationComplete: true;
|
||||
visualQualityAccepted: false;
|
||||
integratedGraphPerformanceAccepted: false;
|
||||
allFramesAccounted: boolean;
|
||||
allEligiblePointsAccounted: boolean;
|
||||
};
|
||||
decision: {
|
||||
state: string;
|
||||
candidateRetained: boolean;
|
||||
nextAction: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface M49TgsFullShadowSpatial {
|
||||
resultId: string;
|
||||
sourceSequence: number;
|
||||
sourceFrameIndex: number;
|
||||
sessionSeconds: number;
|
||||
sampleAvailable: boolean;
|
||||
costmap: {
|
||||
cellSizeM: number;
|
||||
radiusM: number;
|
||||
centersXyM: readonly (readonly [number, number])[];
|
||||
states: readonly M49TgsFullShadowStateCode[];
|
||||
zBoundsM: readonly (readonly [number | null, number | null])[];
|
||||
};
|
||||
metrics: {
|
||||
eligiblePointCount: number;
|
||||
groundPointCount: number;
|
||||
nongroundPointCount: number;
|
||||
rejectedPointCount: number;
|
||||
occupiedCellCount: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface M49TgsFullShadowSpatialChunk {
|
||||
resultId: string;
|
||||
start: number;
|
||||
count: number;
|
||||
frames: readonly M49TgsFullShadowSpatial[];
|
||||
}
|
||||
|
||||
export type M49TgsFullShadowPlaybackTrackId =
|
||||
| "frames"
|
||||
| "centers"
|
||||
| "states"
|
||||
| "z-bounds";
|
||||
|
||||
export interface M49TgsFullShadowPlaybackProgress {
|
||||
phase: "manifest" | "download" | "verify" | "ready";
|
||||
trackId: M49TgsFullShadowPlaybackTrackId | null;
|
||||
loadedBytes: number;
|
||||
totalBytes: number;
|
||||
}
|
||||
|
||||
interface M49TgsFullShadowPlaybackTrack {
|
||||
id: M49TgsFullShadowPlaybackTrackId;
|
||||
url: string;
|
||||
mediaType: string;
|
||||
dtype: "ndjson" | "<f4" | "|u1";
|
||||
shape: readonly number[];
|
||||
byteLength: number;
|
||||
sha256: string;
|
||||
}
|
||||
|
||||
export interface M49TgsFullShadowPlaybackFrame {
|
||||
sourceSequence: number;
|
||||
sourceFrameIndex: number;
|
||||
sessionSeconds: number;
|
||||
sampleAvailable: boolean;
|
||||
metrics: M49TgsFullShadowSpatial["metrics"];
|
||||
}
|
||||
|
||||
export interface M49TgsFullShadowPlaybackPack {
|
||||
resultId: string;
|
||||
frameCount: 4489;
|
||||
cellCount: 2244;
|
||||
totalByteLength: number;
|
||||
centersXyM: Float32Array;
|
||||
states: Uint8Array;
|
||||
zBoundsM: Float32Array;
|
||||
frames: readonly M49TgsFullShadowPlaybackFrame[];
|
||||
}
|
||||
|
||||
export class M49TgsFullShadowContractError extends Error {}
|
||||
|
||||
function objectValue(value: unknown, label: string): Record<string, unknown> {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
throw new M49TgsFullShadowContractError(`${label}: ожидался объект.`);
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function text(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new M49TgsFullShadowContractError(`${label}: ожидалась строка.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function numberValue(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
throw new M49TgsFullShadowContractError(`${label}: ожидалось число.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function integer(value: unknown, label: string): number {
|
||||
const parsed = numberValue(value, label);
|
||||
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
||||
throw new M49TgsFullShadowContractError(`${label}: ожидалось целое число.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function booleanValue(value: unknown, label: string): boolean {
|
||||
if (typeof value !== "boolean") {
|
||||
throw new M49TgsFullShadowContractError(`${label}: ожидался boolean.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function exact<T extends string | boolean | number>(value: unknown, expected: T, label: string): T {
|
||||
if (value !== expected) throw new M49TgsFullShadowContractError(`${label}: нарушен контракт.`);
|
||||
return expected;
|
||||
}
|
||||
|
||||
function timing(value: unknown, label: string) {
|
||||
const row = objectValue(value, label);
|
||||
return {
|
||||
p50: numberValue(row.p50, `${label}.p50`),
|
||||
p95: numberValue(row.p95, `${label}.p95`),
|
||||
p99: numberValue(row.p99, `${label}.p99`),
|
||||
max: numberValue(row.max, `${label}.max`),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM49TgsFullShadowResult(
|
||||
id: string,
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<M49TgsFullShadowResult> {
|
||||
if (!RESULT_ID.test(id)) throw new M49TgsFullShadowContractError("M49 full-shadow identity недопустима.");
|
||||
const response = await fetcher(
|
||||
`/api/v1/laboratory/m49/tgs-full-shadow/${encodeURIComponent(id)}`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) throw new M49TgsFullShadowContractError(`M49 full shadow недоступен: HTTP ${response.status}.`);
|
||||
const payload = objectValue(await response.json(), "M49 full shadow");
|
||||
exact(payload.schema_version, "missioncore.m49-tgs-full-shadow-view/v1", "M49 full schema");
|
||||
exact(payload.result_id, id, "M49 full result");
|
||||
exact(payload.ground_truth, false, "M49 full ground truth");
|
||||
exact(payload.access, "read-only", "M49 full access");
|
||||
const source = objectValue(payload.source, "M49 full source");
|
||||
const configuration = objectValue(payload.configuration, "M49 full configuration");
|
||||
const execution = objectValue(payload.execution, "M49 full execution");
|
||||
const timeline = objectValue(payload.timeline, "M49 full timeline");
|
||||
const accounting = objectValue(payload.point_accounting, "M49 full accounting");
|
||||
const performance = objectValue(payload.performance, "M49 full performance");
|
||||
const acceptance = objectValue(payload.acceptance, "M49 full acceptance");
|
||||
const decision = objectValue(payload.decision, "M49 full decision");
|
||||
const linkedSemanticResultId = text(
|
||||
source.linked_semantic_result_id,
|
||||
"M49 full semantic result",
|
||||
);
|
||||
if (!SEMANTIC_RESULT_ID.test(linkedSemanticResultId)) {
|
||||
throw new M49TgsFullShadowContractError("M49 full semantic result: нарушена идентичность.");
|
||||
}
|
||||
return {
|
||||
resultId: text(payload.result_id, "M49 full result"),
|
||||
createdAtUtc: text(payload.created_at_utc, "M49 full created"),
|
||||
source: {
|
||||
sourcePackSha256: text(source.source_pack_sha256, "M49 full source pack"),
|
||||
linkedVisualResultId: text(source.linked_visual_result_id, "M49 full visual result"),
|
||||
linkedSemanticResultId,
|
||||
},
|
||||
configuration: {
|
||||
configSha256: text(configuration.config_sha256, "M49 full config"),
|
||||
cellSizeM: numberValue(configuration.cell_size_m, "M49 full cell size"),
|
||||
radiusM: numberValue(configuration.radius_m, "M49 full radius"),
|
||||
historySeconds: numberValue(configuration.history_seconds, "M49 full history"),
|
||||
},
|
||||
execution: { wrapperElapsedSeconds: numberValue(execution.wrapper_elapsed_seconds, "M49 full wall") },
|
||||
timeline: {
|
||||
frameCount: exact(integer(timeline.frame_count, "M49 full frames"), 4489, "M49 full frames"),
|
||||
availableLidarFrameCount: exact(integer(timeline.available_lidar_frame_count, "M49 full available"), 3928, "M49 full available"),
|
||||
missingLidarFrameCount: exact(integer(timeline.missing_lidar_frame_count, "M49 full missing"), 561, "M49 full missing"),
|
||||
durationSeconds: numberValue(timeline.duration_seconds, "M49 full duration"),
|
||||
effectiveFps: numberValue(timeline.effective_fps, "M49 full fps"),
|
||||
},
|
||||
pointAccounting: {
|
||||
eligible: integer(accounting.eligible, "M49 full eligible"),
|
||||
ground: integer(accounting.ground, "M49 full ground"),
|
||||
nonground: integer(accounting.nonground, "M49 full nonground"),
|
||||
rejected: integer(accounting.rejected, "M49 full rejected"),
|
||||
unaccounted: exact(integer(accounting.unaccounted, "M49 full unaccounted"), 0, "M49 full unaccounted"),
|
||||
},
|
||||
performance: {
|
||||
candidateTgsMs: timing(performance.candidate_tgs_ms, "M49 full TGS"),
|
||||
completionAgeMs: timing(performance.completion_age_ms, "M49 full completion"),
|
||||
capacityDropCount: integer(performance.capacity_drop_count, "M49 full drops"),
|
||||
},
|
||||
acceptance: {
|
||||
representationComplete: exact(acceptance.representation_complete, true, "M49 full representation"),
|
||||
visualQualityAccepted: exact(acceptance.visual_quality_accepted, false, "M49 full visual"),
|
||||
integratedGraphPerformanceAccepted: exact(acceptance.integrated_graph_performance_accepted, false, "M49 full integrated"),
|
||||
allFramesAccounted: booleanValue(acceptance.all_frames_accounted, "M49 full frame accounting"),
|
||||
allEligiblePointsAccounted: booleanValue(acceptance.all_eligible_points_accounted, "M49 full point accounting"),
|
||||
},
|
||||
decision: {
|
||||
state: text(decision.state, "M49 full decision"),
|
||||
candidateRetained: booleanValue(decision.candidate_retained, "M49 full retained"),
|
||||
nextAction: text(decision.next_action, "M49 full next action"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function pair(value: unknown, label: string): readonly [number, number] {
|
||||
if (!Array.isArray(value) || value.length !== 2) {
|
||||
throw new M49TgsFullShadowContractError(`${label}: неверная размерность.`);
|
||||
}
|
||||
return [numberValue(value[0], label), numberValue(value[1], label)];
|
||||
}
|
||||
|
||||
function parseSpatial(
|
||||
id: string,
|
||||
sourceSequence: number,
|
||||
payload: Record<string, unknown>,
|
||||
sharedCostmap?: Record<string, unknown>,
|
||||
): M49TgsFullShadowSpatial {
|
||||
exact(payload.source_sequence, sourceSequence, "M49 full spatial sequence");
|
||||
const costmap = sharedCostmap ?? objectValue(payload.costmap, "M49 full costmap");
|
||||
const metrics = objectValue(payload.metrics, "M49 full frame metrics");
|
||||
const centers = costmap.centers_xy_m;
|
||||
const statesRaw = sharedCostmap ? payload.states : costmap.states;
|
||||
const zBoundsRaw = sharedCostmap ? payload.z_bounds_m : costmap.z_bounds_m;
|
||||
if (!Array.isArray(centers) || !Array.isArray(statesRaw) || !Array.isArray(zBoundsRaw)
|
||||
|| centers.length !== 2244 || statesRaw.length !== 2244 || zBoundsRaw.length !== 2244) {
|
||||
throw new M49TgsFullShadowContractError("M49 full costmap: неверная размерность.");
|
||||
}
|
||||
const states = statesRaw.map((value, index) => {
|
||||
const parsed = integer(value, `M49 full state ${index}`);
|
||||
if (parsed > 3) throw new M49TgsFullShadowContractError("M49 full state недопустим.");
|
||||
return parsed as M49TgsFullShadowStateCode;
|
||||
});
|
||||
const zBounds = zBoundsRaw.map((value, index) => {
|
||||
if (!Array.isArray(value) || value.length !== 2) {
|
||||
throw new M49TgsFullShadowContractError(`M49 full z ${index}: неверная размерность.`);
|
||||
}
|
||||
return value.map((item) => item === null
|
||||
? null
|
||||
: numberValue(item, `M49 full z ${index}`)) as [number | null, number | null];
|
||||
});
|
||||
const sampleAvailable = booleanValue(payload.sample_available, "M49 full sample available");
|
||||
if (!sampleAvailable && states.some((state) => state !== 0)) {
|
||||
throw new M49TgsFullShadowContractError("M49 missing LiDAR frame не остался UNOBSERVED.");
|
||||
}
|
||||
return {
|
||||
resultId: id,
|
||||
sourceSequence,
|
||||
sourceFrameIndex: integer(payload.source_frame_index, "M49 full source frame"),
|
||||
sessionSeconds: numberValue(payload.session_seconds, "M49 full session seconds"),
|
||||
sampleAvailable,
|
||||
costmap: {
|
||||
cellSizeM: numberValue(costmap.cell_size_m, "M49 full cell size"),
|
||||
radiusM: numberValue(costmap.radius_m, "M49 full radius"),
|
||||
centersXyM: centers.map((value, index) => pair(value, `M49 full center ${index}`)),
|
||||
states,
|
||||
zBoundsM: zBounds,
|
||||
},
|
||||
metrics: {
|
||||
eligiblePointCount: integer(metrics.eligible_point_count, "M49 full eligible"),
|
||||
groundPointCount: integer(metrics.ground_point_count, "M49 full ground"),
|
||||
nongroundPointCount: integer(metrics.nonground_point_count, "M49 full nonground"),
|
||||
rejectedPointCount: integer(metrics.rejected_point_count, "M49 full rejected"),
|
||||
occupiedCellCount: integer(metrics.occupied_cell_count, "M49 full occupied cells"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM49TgsFullShadowSpatial(
|
||||
id: string,
|
||||
sourceSequence: number,
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<M49TgsFullShadowSpatial> {
|
||||
if (!RESULT_ID.test(id) || !Number.isSafeInteger(sourceSequence) || sourceSequence < 0 || sourceSequence >= 4489) {
|
||||
throw new M49TgsFullShadowContractError("M49 full-shadow frame identity недопустима.");
|
||||
}
|
||||
const response = await fetcher(
|
||||
`/api/v1/laboratory/m49/tgs-full-shadow/${encodeURIComponent(id)}/frames/${sourceSequence}/spatial`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) throw new M49TgsFullShadowContractError(`M49 full-shadow frame недоступен: HTTP ${response.status}.`);
|
||||
const payload = objectValue(await response.json(), "M49 full spatial");
|
||||
exact(payload.schema_version, "missioncore.m49-tgs-full-shadow-spatial/v1", "M49 full spatial schema");
|
||||
exact(payload.result_id, id, "M49 full spatial result");
|
||||
return parseSpatial(id, sourceSequence, payload);
|
||||
}
|
||||
|
||||
export async function fetchM49TgsFullShadowSpatialChunk(
|
||||
id: string,
|
||||
start: number,
|
||||
count = 24,
|
||||
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
|
||||
): Promise<M49TgsFullShadowSpatialChunk> {
|
||||
if (!RESULT_ID.test(id) || !Number.isSafeInteger(start) || start < 0 || start >= 4489
|
||||
|| !Number.isSafeInteger(count) || count < 1 || count > 24) {
|
||||
throw new M49TgsFullShadowContractError("M49 full-shadow chunk identity недопустима.");
|
||||
}
|
||||
const response = await fetcher(
|
||||
`/api/v1/laboratory/m49/tgs-full-shadow/${encodeURIComponent(id)}/spatial/chunk?start=${start}&count=${count}`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) throw new M49TgsFullShadowContractError(`M49 full-shadow chunk недоступен: HTTP ${response.status}.`);
|
||||
const payload = objectValue(await response.json(), "M49 full spatial chunk");
|
||||
exact(payload.schema_version, "missioncore.m49-tgs-full-shadow-spatial-chunk/v1", "M49 full chunk schema");
|
||||
exact(payload.result_id, id, "M49 full chunk result");
|
||||
exact(payload.start, start, "M49 full chunk start");
|
||||
const returnedCount = integer(payload.count, "M49 full chunk count");
|
||||
if (!Array.isArray(payload.frames) || payload.frames.length !== returnedCount
|
||||
|| returnedCount !== Math.min(count, 4489 - start)) {
|
||||
throw new M49TgsFullShadowContractError("M49 full chunk: неверная размерность.");
|
||||
}
|
||||
const costmap = objectValue(payload.costmap, "M49 full chunk costmap");
|
||||
return {
|
||||
resultId: id,
|
||||
start,
|
||||
count: returnedCount,
|
||||
frames: payload.frames.map((value, index) => parseSpatial(
|
||||
id,
|
||||
start + index,
|
||||
objectValue(value, `M49 full chunk frame ${index}`),
|
||||
costmap,
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
function playbackTrackId(value: unknown, label: string): M49TgsFullShadowPlaybackTrackId {
|
||||
const parsed = text(value, label);
|
||||
if (parsed !== "frames" && parsed !== "centers" && parsed !== "states" && parsed !== "z-bounds") {
|
||||
throw new M49TgsFullShadowContractError(`${label}: неизвестная playback-дорожка.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function playbackDtype(value: unknown, label: string): M49TgsFullShadowPlaybackTrack["dtype"] {
|
||||
const parsed = text(value, label);
|
||||
if (parsed !== "ndjson" && parsed !== "<f4" && parsed !== "|u1") {
|
||||
throw new M49TgsFullShadowContractError(`${label}: неизвестный dtype.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function playbackShape(value: unknown, label: string): readonly number[] {
|
||||
if (!Array.isArray(value) || !value.length) {
|
||||
throw new M49TgsFullShadowContractError(`${label}: ожидалась размерность.`);
|
||||
}
|
||||
return value.map((item, index) => integer(item, `${label}.${index}`));
|
||||
}
|
||||
|
||||
async function fetchPlaybackManifest(
|
||||
id: string,
|
||||
fetcher: LaboratoryFetch,
|
||||
signal: AbortSignal | undefined,
|
||||
): Promise<{
|
||||
frameCount: 4489;
|
||||
cellCount: 2244;
|
||||
totalByteLength: number;
|
||||
tracks: ReadonlyMap<M49TgsFullShadowPlaybackTrackId, M49TgsFullShadowPlaybackTrack>;
|
||||
}> {
|
||||
const response = await fetcher(
|
||||
`/api/v1/laboratory/m49/tgs-full-shadow/${encodeURIComponent(id)}/playback/manifest`,
|
||||
{ method: "GET", headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new M49TgsFullShadowContractError(`M49 playback manifest недоступен: HTTP ${response.status}.`);
|
||||
}
|
||||
const payload = objectValue(await response.json(), "M49 playback manifest");
|
||||
exact(payload.schema_version, "missioncore.m49-tgs-full-shadow-playback/v1", "M49 playback schema");
|
||||
exact(payload.result_id, id, "M49 playback result");
|
||||
exact(payload.coordinate_frame, "map-gravity-local", "M49 playback frame");
|
||||
exact(payload.access, "read-only", "M49 playback access");
|
||||
const frameCount = exact(integer(payload.frame_count, "M49 playback frames"), 4489, "M49 playback frames");
|
||||
const cellCount = exact(integer(payload.cell_count, "M49 playback cells"), 2244, "M49 playback cells");
|
||||
const totalByteLength = integer(payload.total_byte_length, "M49 playback bytes");
|
||||
if (!Array.isArray(payload.tracks) || payload.tracks.length !== 4) {
|
||||
throw new M49TgsFullShadowContractError("M49 playback tracks: неверная размерность.");
|
||||
}
|
||||
const tracks = new Map<M49TgsFullShadowPlaybackTrackId, M49TgsFullShadowPlaybackTrack>();
|
||||
for (const [index, value] of payload.tracks.entries()) {
|
||||
const row = objectValue(value, `M49 playback track ${index}`);
|
||||
const trackId = playbackTrackId(row.id, `M49 playback track ${index}.id`);
|
||||
const sha256 = text(row.sha256, `M49 playback track ${trackId}.sha256`);
|
||||
if (!/^[a-f0-9]{64}$/.test(sha256) || tracks.has(trackId)) {
|
||||
throw new M49TgsFullShadowContractError(`M49 playback track ${trackId}: нарушена идентичность.`);
|
||||
}
|
||||
tracks.set(trackId, {
|
||||
id: trackId,
|
||||
url: text(row.url, `M49 playback track ${trackId}.url`),
|
||||
mediaType: text(row.media_type, `M49 playback track ${trackId}.media_type`),
|
||||
dtype: playbackDtype(row.dtype, `M49 playback track ${trackId}.dtype`),
|
||||
shape: playbackShape(row.shape, `M49 playback track ${trackId}.shape`),
|
||||
byteLength: integer(row.byte_length, `M49 playback track ${trackId}.byte_length`),
|
||||
sha256,
|
||||
});
|
||||
}
|
||||
if ([...tracks.values()].reduce((sum, track) => sum + track.byteLength, 0) !== totalByteLength) {
|
||||
throw new M49TgsFullShadowContractError("M49 playback bytes: нарушен accounting.");
|
||||
}
|
||||
return { frameCount, cellCount, totalByteLength, tracks };
|
||||
}
|
||||
|
||||
function sha256Hex(buffer: ArrayBuffer): Promise<string> {
|
||||
if (!globalThis.crypto?.subtle) {
|
||||
throw new M49TgsFullShadowContractError("Браузер не поддерживает проверку playback SHA-256.");
|
||||
}
|
||||
return globalThis.crypto.subtle.digest("SHA-256", buffer).then((digest) => (
|
||||
[...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, "0")).join("")
|
||||
));
|
||||
}
|
||||
|
||||
async function fetchPlaybackTrack(
|
||||
track: M49TgsFullShadowPlaybackTrack,
|
||||
fetcher: LaboratoryFetch,
|
||||
signal: AbortSignal | undefined,
|
||||
completedBytes: number,
|
||||
totalBytes: number,
|
||||
onProgress: ((progress: M49TgsFullShadowPlaybackProgress) => void) | undefined,
|
||||
): Promise<ArrayBuffer> {
|
||||
const response = await fetcher(track.url, {
|
||||
method: "GET",
|
||||
headers: { Accept: track.mediaType },
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new M49TgsFullShadowContractError(`M49 playback ${track.id} недоступен: HTTP ${response.status}.`);
|
||||
}
|
||||
const bytes = new Uint8Array(track.byteLength);
|
||||
if (response.body) {
|
||||
const reader = response.body.getReader();
|
||||
let offset = 0;
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
if (offset + value.byteLength > bytes.byteLength) {
|
||||
throw new M49TgsFullShadowContractError(`M49 playback ${track.id}: превышен объявленный размер.`);
|
||||
}
|
||||
bytes.set(value, offset);
|
||||
offset += value.byteLength;
|
||||
onProgress?.({
|
||||
phase: "download",
|
||||
trackId: track.id,
|
||||
loadedBytes: completedBytes + offset,
|
||||
totalBytes,
|
||||
});
|
||||
}
|
||||
if (offset !== bytes.byteLength) {
|
||||
throw new M49TgsFullShadowContractError(`M49 playback ${track.id}: получен неполный файл.`);
|
||||
}
|
||||
} else {
|
||||
const fallback = new Uint8Array(await response.arrayBuffer());
|
||||
if (fallback.byteLength !== bytes.byteLength) {
|
||||
throw new M49TgsFullShadowContractError(`M49 playback ${track.id}: получен неверный размер.`);
|
||||
}
|
||||
bytes.set(fallback);
|
||||
}
|
||||
onProgress?.({
|
||||
phase: "verify",
|
||||
trackId: track.id,
|
||||
loadedBytes: completedBytes + bytes.byteLength,
|
||||
totalBytes,
|
||||
});
|
||||
if (await sha256Hex(bytes.buffer) !== track.sha256) {
|
||||
throw new M49TgsFullShadowContractError(`M49 playback ${track.id}: SHA-256 не совпал.`);
|
||||
}
|
||||
return bytes.buffer;
|
||||
}
|
||||
|
||||
function equalShape(actual: readonly number[], expected: readonly number[]): boolean {
|
||||
return actual.length === expected.length && actual.every((value, index) => value === expected[index]);
|
||||
}
|
||||
|
||||
export function parseM49TgsNpyTrack(
|
||||
buffer: ArrayBuffer,
|
||||
expectedDtype: "<f4" | "|u1",
|
||||
expectedShape: readonly number[],
|
||||
): Float32Array | Uint8Array {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
if (bytes.byteLength < 12
|
||||
|| bytes[0] !== 0x93
|
||||
|| String.fromCharCode(...bytes.subarray(1, 6)) !== "NUMPY") {
|
||||
throw new M49TgsFullShadowContractError("M49 playback NPY: неверная сигнатура.");
|
||||
}
|
||||
const major = bytes[6];
|
||||
const headerLength = major === 1
|
||||
? new DataView(buffer).getUint16(8, true)
|
||||
: major === 2 || major === 3
|
||||
? new DataView(buffer).getUint32(8, true)
|
||||
: -1;
|
||||
const headerOffset = major === 1 ? 10 : 12;
|
||||
if (headerLength < 0 || headerOffset + headerLength > bytes.byteLength) {
|
||||
throw new M49TgsFullShadowContractError("M49 playback NPY: неверный заголовок.");
|
||||
}
|
||||
const header = new TextDecoder("latin1").decode(bytes.subarray(headerOffset, headerOffset + headerLength));
|
||||
const dtype = header.match(/["']descr["']\s*:\s*["']([^"']+)["']/)?.[1];
|
||||
const fortran = header.match(/["']fortran_order["']\s*:\s*(True|False)/)?.[1];
|
||||
const rawShape = header.match(/["']shape["']\s*:\s*\(([^)]*)\)/)?.[1];
|
||||
const shape = rawShape?.split(",").map((value) => value.trim()).filter(Boolean).map(Number) ?? [];
|
||||
if (dtype !== expectedDtype || fortran !== "False" || !equalShape(shape, expectedShape)) {
|
||||
throw new M49TgsFullShadowContractError("M49 playback NPY: dtype или shape изменились.");
|
||||
}
|
||||
const count = expectedShape.reduce((product, value) => product * value, 1);
|
||||
const dataOffset = headerOffset + headerLength;
|
||||
const bytesPerValue = expectedDtype === "<f4" ? 4 : 1;
|
||||
if (dataOffset + count * bytesPerValue !== buffer.byteLength) {
|
||||
throw new M49TgsFullShadowContractError("M49 playback NPY: длина payload изменилась.");
|
||||
}
|
||||
return expectedDtype === "<f4"
|
||||
? new Float32Array(buffer, dataOffset, count)
|
||||
: new Uint8Array(buffer, dataOffset, count);
|
||||
}
|
||||
|
||||
function parsePlaybackFrames(buffer: ArrayBuffer): readonly M49TgsFullShadowPlaybackFrame[] {
|
||||
const lines = new TextDecoder().decode(buffer).trim().split("\n");
|
||||
if (lines.length !== 4489) {
|
||||
throw new M49TgsFullShadowContractError("M49 playback frames: неверная размерность.");
|
||||
}
|
||||
return lines.map((line, sourceSequence) => {
|
||||
const row = objectValue(JSON.parse(line), `M49 playback frame ${sourceSequence}`);
|
||||
return {
|
||||
sourceSequence,
|
||||
sourceFrameIndex: integer(row.source_frame_index, `M49 playback frame ${sourceSequence}.source`),
|
||||
sessionSeconds: numberValue(row.session_seconds, `M49 playback frame ${sourceSequence}.time`),
|
||||
sampleAvailable: booleanValue(row.sample_available, `M49 playback frame ${sourceSequence}.available`),
|
||||
metrics: {
|
||||
eligiblePointCount: integer(row.eligible_point_count, `M49 playback frame ${sourceSequence}.eligible`),
|
||||
groundPointCount: integer(row.ground_point_count, `M49 playback frame ${sourceSequence}.ground`),
|
||||
nongroundPointCount: integer(row.nonground_point_count, `M49 playback frame ${sourceSequence}.nonground`),
|
||||
rejectedPointCount: integer(row.rejected_point_count, `M49 playback frame ${sourceSequence}.rejected`),
|
||||
occupiedCellCount: integer(row.occupied_cell_count, `M49 playback frame ${sourceSequence}.occupied`),
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchM49TgsFullShadowPlaybackPack(
|
||||
id: string,
|
||||
{
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
onProgress,
|
||||
}: {
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
onProgress?: (progress: M49TgsFullShadowPlaybackProgress) => void;
|
||||
} = {},
|
||||
): Promise<M49TgsFullShadowPlaybackPack> {
|
||||
if (!RESULT_ID.test(id)) {
|
||||
throw new M49TgsFullShadowContractError("M49 playback identity недопустима.");
|
||||
}
|
||||
onProgress?.({ phase: "manifest", trackId: null, loadedBytes: 0, totalBytes: 0 });
|
||||
const manifest = await fetchPlaybackManifest(id, fetcher, signal);
|
||||
const buffers = new Map<M49TgsFullShadowPlaybackTrackId, ArrayBuffer>();
|
||||
let completedBytes = 0;
|
||||
const order: readonly M49TgsFullShadowPlaybackTrackId[] = ["frames", "centers", "states", "z-bounds"];
|
||||
for (const trackId of order) {
|
||||
const track = manifest.tracks.get(trackId);
|
||||
if (!track) throw new M49TgsFullShadowContractError(`M49 playback ${trackId}: дорожка отсутствует.`);
|
||||
const buffer = await fetchPlaybackTrack(
|
||||
track,
|
||||
fetcher,
|
||||
signal,
|
||||
completedBytes,
|
||||
manifest.totalByteLength,
|
||||
onProgress,
|
||||
);
|
||||
buffers.set(trackId, buffer);
|
||||
completedBytes += track.byteLength;
|
||||
}
|
||||
const centersTrack = manifest.tracks.get("centers")!;
|
||||
const statesTrack = manifest.tracks.get("states")!;
|
||||
const zBoundsTrack = manifest.tracks.get("z-bounds")!;
|
||||
const centersRaw = parseM49TgsNpyTrack(
|
||||
buffers.get("centers")!,
|
||||
"<f4",
|
||||
centersTrack.shape,
|
||||
) as Float32Array;
|
||||
const states = parseM49TgsNpyTrack(
|
||||
buffers.get("states")!,
|
||||
"|u1",
|
||||
statesTrack.shape,
|
||||
) as Uint8Array;
|
||||
const zBoundsM = parseM49TgsNpyTrack(
|
||||
buffers.get("z-bounds")!,
|
||||
"<f4",
|
||||
zBoundsTrack.shape,
|
||||
) as Float32Array;
|
||||
const frames = parsePlaybackFrames(buffers.get("frames")!);
|
||||
onProgress?.({
|
||||
phase: "ready",
|
||||
trackId: null,
|
||||
loadedBytes: manifest.totalByteLength,
|
||||
totalBytes: manifest.totalByteLength,
|
||||
});
|
||||
return {
|
||||
resultId: id,
|
||||
frameCount: manifest.frameCount,
|
||||
cellCount: manifest.cellCount,
|
||||
totalByteLength: manifest.totalByteLength,
|
||||
centersXyM: centersRaw,
|
||||
states,
|
||||
zBoundsM,
|
||||
frames,
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
export type M4ThreatDecision = "threat" | "not-threat" | "unknown";
|
||||
export type M4ThreatMotion = "moving" | "stationary" | "unknown";
|
||||
export type M4OccupancySource = "baseline" | "mixed" | "additive-low-step";
|
||||
export type M4Point3 = readonly [number, number, number];
|
||||
export type M4Matrix3 = readonly [M4Point3, M4Point3, M4Point3];
|
||||
|
||||
@@ -69,6 +70,14 @@ export interface M4ThreatAssessment {
|
||||
reasonCodes: readonly string[];
|
||||
}
|
||||
|
||||
export interface M4ThreatCameraObstacleProjection {
|
||||
bboxXyxy: readonly [number, number, number, number];
|
||||
nearestDepthM: number;
|
||||
projectedCellCount: number;
|
||||
projection: "factory-kb4-occupied-voxel-bounds";
|
||||
authority: "visual-derived";
|
||||
}
|
||||
|
||||
export interface M4ThreatMetricVisual {
|
||||
componentId: string;
|
||||
state: "current" | "retained" | "held" | "expired";
|
||||
@@ -76,6 +85,8 @@ export interface M4ThreatMetricVisual {
|
||||
centroidBodyXyzM: M4Point3;
|
||||
cellCentersBodyXyzM: readonly M4Point3[];
|
||||
assessment: M4ThreatAssessment;
|
||||
occupancySource: M4OccupancySource;
|
||||
cameraProjection: M4ThreatCameraObstacleProjection | null;
|
||||
}
|
||||
|
||||
export interface M4ThreatCameraProposal {
|
||||
@@ -174,6 +185,8 @@ export interface M4ThreatTimeline {
|
||||
cameraPointWindowSeconds: number;
|
||||
cameraPointSampleLimit: number;
|
||||
worldStateDelivery: "source-paced-latest-wins" | null;
|
||||
occupancyProvenanceDelivery: "baseline-versus-additive-component-diff" | null;
|
||||
cameraObstacleProjectionDelivery: "factory-kb4-actionable-added-corridor-bounds" | null;
|
||||
worldStateFrameCount: number;
|
||||
supersededFrameCount: number;
|
||||
sourceRepresentationId: "registered-map-increment-v1";
|
||||
@@ -213,6 +226,51 @@ export interface M4ThreatTimelineChunk {
|
||||
frames: readonly M4ThreatTimelineFrame[];
|
||||
}
|
||||
|
||||
export interface M4ThreatPlaybackProgress {
|
||||
phase: "manifest" | "download" | "verify" | "ready";
|
||||
loadedBytes: number;
|
||||
totalBytes: number;
|
||||
}
|
||||
|
||||
export interface M4ThreatPlaybackPointPack {
|
||||
resultId: string;
|
||||
frameCount: 4489;
|
||||
pointCount: number;
|
||||
pointOffsets: Uint32Array;
|
||||
pointsMapXyzM: Float32Array;
|
||||
pointStart?: number;
|
||||
startSequence?: number;
|
||||
sequenceCount?: number;
|
||||
}
|
||||
|
||||
export interface M4ThreatPlaybackChunkDescriptor {
|
||||
index: number;
|
||||
start: number;
|
||||
count: number;
|
||||
pointStart: number;
|
||||
pointCount: number;
|
||||
url: string;
|
||||
mediaType: "application/octet-stream";
|
||||
byteLength: number;
|
||||
sha256: string;
|
||||
}
|
||||
|
||||
export interface M4ThreatPlaybackManifest {
|
||||
resultId: string;
|
||||
frameCount: 4489;
|
||||
pointCount: number;
|
||||
pointOffsets: Uint32Array;
|
||||
chunkFrameCount: 24;
|
||||
residentChunkCountMax: 4;
|
||||
forwardPrefetchChunkCount: 1;
|
||||
chunks: readonly M4ThreatPlaybackChunkDescriptor[];
|
||||
track: {
|
||||
url: string;
|
||||
byteLength: number;
|
||||
sha256: string;
|
||||
};
|
||||
}
|
||||
|
||||
type LaboratoryFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
||||
export const M4_THREAT_TIMELINE_ENDPOINT_ROOT = "/api/v1/laboratory/m4-threat/results";
|
||||
class M4ThreatContractError extends Error {}
|
||||
@@ -320,6 +378,32 @@ function parseCameraProposal(value: unknown): M4ThreatCameraProposal {
|
||||
};
|
||||
}
|
||||
|
||||
function parseCameraObstacleProjection(value: unknown): M4ThreatCameraObstacleProjection {
|
||||
const item = object(value, "M4.8R3 camera obstacle projection");
|
||||
const bbox = vector(item.bbox_xyxy, 4, "M4.8R3 camera obstacle bbox");
|
||||
if (bbox[2]! < bbox[0]! || bbox[3]! < bbox[1]!) {
|
||||
throw new M4ThreatContractError("M4.8R3 camera obstacle bbox: нарушена геометрия.");
|
||||
}
|
||||
return {
|
||||
bboxXyxy: [bbox[0]!, bbox[1]!, bbox[2]!, bbox[3]!],
|
||||
nearestDepthM: number(item.nearest_depth_m, "M4.8R3 camera obstacle depth"),
|
||||
projectedCellCount: integer(
|
||||
item.projected_cell_count,
|
||||
"M4.8R3 camera obstacle cells",
|
||||
),
|
||||
projection: exact(
|
||||
item.projection,
|
||||
"factory-kb4-occupied-voxel-bounds",
|
||||
"M4.8R3 camera obstacle projection",
|
||||
),
|
||||
authority: exact(
|
||||
item.authority,
|
||||
"visual-derived",
|
||||
"M4.8R3 camera obstacle authority",
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
function parseMetricVisual(value: unknown): M4ThreatMetricVisual {
|
||||
const item = object(value, "M4.6 metric visual");
|
||||
const state = text(item.state, "M4.6 temporal state");
|
||||
@@ -331,6 +415,9 @@ function parseMetricVisual(value: unknown): M4ThreatMetricVisual {
|
||||
) {
|
||||
throw new M4ThreatContractError("M4.6 temporal state: неизвестное состояние.");
|
||||
}
|
||||
const occupancySource = item.occupancy_source === undefined
|
||||
? "baseline"
|
||||
: memberOccupancySource(item.occupancy_source);
|
||||
return {
|
||||
componentId: text(item.component_id, "M4.6 visual component"),
|
||||
state,
|
||||
@@ -340,9 +427,20 @@ function parseMetricVisual(value: unknown): M4ThreatMetricVisual {
|
||||
(point) => vector(point, 3, "M4.6 cell") as [number, number, number],
|
||||
),
|
||||
assessment: parseAssessment(item.assessment),
|
||||
occupancySource,
|
||||
cameraProjection: item.camera_projection === undefined
|
||||
? null
|
||||
: parseCameraObstacleProjection(item.camera_projection),
|
||||
};
|
||||
}
|
||||
|
||||
function memberOccupancySource(value: unknown): M4OccupancySource {
|
||||
if (value !== "baseline" && value !== "mixed" && value !== "additive-low-step") {
|
||||
throw new M4ThreatContractError("M4.8R3 occupancy source: неизвестное состояние.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export async function fetchM4ThreatReplayResult({
|
||||
resultId: requestedResultId,
|
||||
fetcher = fetch,
|
||||
@@ -683,6 +781,20 @@ export async function fetchM4ThreatTimeline(
|
||||
"source-paced-latest-wins",
|
||||
"M4.6 world-state delivery",
|
||||
),
|
||||
occupancyProvenanceDelivery: payload.occupancy_provenance_delivery == null
|
||||
? null
|
||||
: exact(
|
||||
payload.occupancy_provenance_delivery,
|
||||
"baseline-versus-additive-component-diff",
|
||||
"M4.8R3 occupancy provenance",
|
||||
),
|
||||
cameraObstacleProjectionDelivery: payload.camera_obstacle_projection_delivery == null
|
||||
? null
|
||||
: exact(
|
||||
payload.camera_obstacle_projection_delivery,
|
||||
"factory-kb4-actionable-added-corridor-bounds",
|
||||
"M4.8R3 camera obstacle projection delivery",
|
||||
),
|
||||
worldStateFrameCount: payload.world_state_frame_count === undefined
|
||||
? frameCount
|
||||
: integer(payload.world_state_frame_count, "M4.6 world-state frames"),
|
||||
@@ -735,16 +847,24 @@ export async function fetchM4ThreatTimelineChunk(
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
endpointRoot = M4_THREAT_TIMELINE_ENDPOINT_ROOT,
|
||||
cameraObstacleProjectionDelivery = null,
|
||||
playbackPointPack,
|
||||
}: {
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
endpointRoot?: string;
|
||||
cameraObstacleProjectionDelivery?: M4ThreatTimeline["cameraObstacleProjectionDelivery"];
|
||||
playbackPointPack?: M4ThreatPlaybackPointPack;
|
||||
} = {},
|
||||
): Promise<M4ThreatTimelineChunk> {
|
||||
const params = new URLSearchParams({
|
||||
start: String(startSequence),
|
||||
count: String(frameCount),
|
||||
});
|
||||
if (cameraObstacleProjectionDelivery !== null) {
|
||||
params.set("obstacle_projection", cameraObstacleProjectionDelivery);
|
||||
}
|
||||
if (playbackPointPack) params.set("include_points", "false");
|
||||
const response = await fetcher(
|
||||
`${endpointRoot}/${result}/timeline/chunk?${params}`,
|
||||
{ headers: { Accept: "application/json" }, signal },
|
||||
@@ -762,8 +882,12 @@ export async function fetchM4ThreatTimelineChunk(
|
||||
if (parsedStart !== startSequence) {
|
||||
throw new M4ThreatContractError("M4.6 timeline chunk start: нарушен контракт.");
|
||||
}
|
||||
const frames = array(payload.frames, "M4.6 timeline frames").map((raw, offset) =>
|
||||
parseTimelineFrame(raw, result, parsedStart + offset, endpointRoot));
|
||||
const frames = array(payload.frames, "M4.6 timeline frames").map((raw, offset) => {
|
||||
const parsed = parseTimelineFrame(raw, result, parsedStart + offset, endpointRoot);
|
||||
return playbackPointPack
|
||||
? hydrateM4ThreatTimelineFrame(parsed, playbackPointPack)
|
||||
: parsed;
|
||||
});
|
||||
const parsedCount = integer(payload.frame_count, "M4.6 timeline chunk count");
|
||||
if (parsedCount !== frames.length || parsedCount > frameCount) {
|
||||
throw new M4ThreatContractError("M4.6 timeline chunk count: нарушен контракт.");
|
||||
@@ -779,6 +903,305 @@ export async function fetchM4ThreatTimelineChunk(
|
||||
};
|
||||
}
|
||||
|
||||
function playbackSha256Hex(buffer: ArrayBuffer): Promise<string> {
|
||||
if (!globalThis.crypto?.subtle) {
|
||||
throw new M4ThreatContractError("Браузер не поддерживает проверку playback SHA-256.");
|
||||
}
|
||||
return globalThis.crypto.subtle.digest("SHA-256", buffer).then((digest) => (
|
||||
[...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, "0")).join("")
|
||||
));
|
||||
}
|
||||
|
||||
function roundedBodyCoordinate(value: number): number {
|
||||
return Math.round(value * 1_000_000) / 1_000_000;
|
||||
}
|
||||
|
||||
export function hydrateM4ThreatTimelineFrame(
|
||||
frame: M4ThreatTimelineFrame,
|
||||
pack: M4ThreatPlaybackPointPack,
|
||||
): M4ThreatTimelineFrame {
|
||||
if (
|
||||
frame.sequence >= pack.frameCount
|
||||
|| pack.resultId === ""
|
||||
|| (pack.startSequence !== undefined && (
|
||||
frame.sequence < pack.startSequence
|
||||
|| frame.sequence >= pack.startSequence + (pack.sequenceCount ?? 0)
|
||||
))
|
||||
) {
|
||||
throw new M4ThreatContractError("M4.6 binary playback frame: нарушена идентичность.");
|
||||
}
|
||||
if (!frame.sourceAvailable || !frame.spatialAvailable || !frame.bodyFrame) {
|
||||
if (frame.pointCloudSourceCount !== 0) {
|
||||
throw new M4ThreatContractError("M4.6 binary playback unavailable frame содержит точки.");
|
||||
}
|
||||
return { ...frame, pointCloudBodyXyzM: [], pointCloudSampleCount: 0 };
|
||||
}
|
||||
const start = pack.pointOffsets[frame.sequence];
|
||||
const stop = pack.pointOffsets[frame.sequence + 1];
|
||||
const pointStart = pack.pointStart ?? 0;
|
||||
const pointStop = pointStart + pack.pointCount;
|
||||
if (
|
||||
start === undefined
|
||||
|| stop === undefined
|
||||
|| stop < start
|
||||
|| start < pointStart
|
||||
|| stop > pointStop
|
||||
) {
|
||||
throw new M4ThreatContractError("M4.6 binary playback offsets: нарушена размерность.");
|
||||
}
|
||||
const count = stop - start;
|
||||
if (frame.pointCloudSourceCount !== count || frame.pointCloudSampleCount !== count) {
|
||||
throw new M4ThreatContractError("M4.6 binary playback point accounting: нарушен контракт.");
|
||||
}
|
||||
const origin = frame.bodyFrame.originMapXyzM;
|
||||
const basis = frame.bodyFrame.basisMapFromBody;
|
||||
const points = new Array<M4Point3>(count);
|
||||
for (let index = 0; index < count; index += 1) {
|
||||
const sourceOffset = (start - pointStart + index) * 3;
|
||||
const dx = pack.pointsMapXyzM[sourceOffset]! - origin[0];
|
||||
const dy = pack.pointsMapXyzM[sourceOffset + 1]! - origin[1];
|
||||
const dz = pack.pointsMapXyzM[sourceOffset + 2]! - origin[2];
|
||||
points[index] = [
|
||||
roundedBodyCoordinate(dx * basis[0][0] + dy * basis[1][0] + dz * basis[2][0]),
|
||||
roundedBodyCoordinate(dx * basis[0][1] + dy * basis[1][1] + dz * basis[2][1]),
|
||||
roundedBodyCoordinate(dx * basis[0][2] + dy * basis[1][2] + dz * basis[2][2]),
|
||||
];
|
||||
}
|
||||
return { ...frame, pointCloudBodyXyzM: points, pointCloudSampleCount: count };
|
||||
}
|
||||
|
||||
export async function fetchM4ThreatPlaybackManifest(
|
||||
result: string,
|
||||
{
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
endpointRoot = M4_THREAT_TIMELINE_ENDPOINT_ROOT,
|
||||
}: {
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
endpointRoot?: string;
|
||||
} = {},
|
||||
): Promise<M4ThreatPlaybackManifest> {
|
||||
resultId(result);
|
||||
const manifestResponse = await fetcher(`${endpointRoot}/${result}/timeline/playback`, {
|
||||
headers: { Accept: "application/json" },
|
||||
signal,
|
||||
});
|
||||
if (!manifestResponse.ok) {
|
||||
throw new M4ThreatContractError(`M4.6 playback manifest: HTTP ${manifestResponse.status}.`);
|
||||
}
|
||||
const manifest = object(await manifestResponse.json(), "M4.6 playback manifest");
|
||||
exact(manifest.schema_version, "missioncore.recorded-spatial-playback/v1", "M4.6 playback schema");
|
||||
exact(manifest.result_id, result, "M4.6 playback result");
|
||||
exact(manifest.coordinate_frame, "map", "M4.6 playback coordinate frame");
|
||||
exact(manifest.access, "read-only-sealed-binary-playback", "M4.6 playback access");
|
||||
const frameCount = exact(integer(manifest.frame_count, "M4.6 playback frames"), 4489, "M4.6 playback frames");
|
||||
const pointCount = integer(manifest.point_count, "M4.6 playback points");
|
||||
const offsetsRaw = array(manifest.point_offsets, "M4.6 playback offsets");
|
||||
if (offsetsRaw.length !== frameCount + 1) {
|
||||
throw new M4ThreatContractError("M4.6 playback offsets: неверная размерность.");
|
||||
}
|
||||
const pointOffsets = Uint32Array.from(offsetsRaw, (value) => integer(value, "M4.6 playback offset"));
|
||||
if (pointOffsets[0] !== 0 || pointOffsets[pointOffsets.length - 1] !== pointCount) {
|
||||
throw new M4ThreatContractError("M4.6 playback offsets: нарушено замыкание.");
|
||||
}
|
||||
for (let index = 1; index < pointOffsets.length; index += 1) {
|
||||
if (pointOffsets[index]! < pointOffsets[index - 1]!) {
|
||||
throw new M4ThreatContractError("M4.6 playback offsets: нарушена монотонность.");
|
||||
}
|
||||
}
|
||||
const track = object(manifest.track, "M4.6 playback track");
|
||||
exact(track.id, "points-map-f32", "M4.6 playback track id");
|
||||
exact(track.dtype, "<f4", "M4.6 playback dtype");
|
||||
const shape = array(track.shape, "M4.6 playback shape").map((value) => integer(value, "M4.6 playback shape"));
|
||||
if (shape.length !== 2 || shape[0] !== pointCount || shape[1] !== 3) {
|
||||
throw new M4ThreatContractError("M4.6 playback shape: нарушена размерность.");
|
||||
}
|
||||
const byteLength = integer(track.bytes, "M4.6 playback bytes");
|
||||
if (byteLength !== pointCount * 3 * Float32Array.BYTES_PER_ELEMENT) {
|
||||
throw new M4ThreatContractError("M4.6 playback bytes: нарушен accounting.");
|
||||
}
|
||||
const sha256 = text(track.sha256, "M4.6 playback SHA-256");
|
||||
if (!/^[a-f0-9]{64}$/.test(sha256)) {
|
||||
throw new M4ThreatContractError("M4.6 playback SHA-256: нарушен контракт.");
|
||||
}
|
||||
const trackUrl = text(track.url, "M4.6 playback URL");
|
||||
const chunkFrameCount = exact(
|
||||
integer(manifest.chunk_frame_count, "M4.6 playback chunk frames"),
|
||||
24,
|
||||
"M4.6 playback chunk frames",
|
||||
);
|
||||
const residentChunkCountMax = exact(
|
||||
integer(manifest.resident_chunk_count_max, "M4.6 playback resident chunks"),
|
||||
4,
|
||||
"M4.6 playback resident chunks",
|
||||
);
|
||||
const forwardPrefetchChunkCount = exact(
|
||||
integer(manifest.forward_prefetch_chunk_count, "M4.6 playback prefetch chunks"),
|
||||
1,
|
||||
"M4.6 playback prefetch chunks",
|
||||
);
|
||||
const chunkRows = array(manifest.chunks, "M4.6 playback chunks");
|
||||
const expectedChunkCount = Math.ceil(frameCount / chunkFrameCount);
|
||||
if (chunkRows.length !== expectedChunkCount) {
|
||||
throw new M4ThreatContractError("M4.6 playback chunk catalog: неверный размер.");
|
||||
}
|
||||
const chunks = chunkRows.map((value, index): M4ThreatPlaybackChunkDescriptor => {
|
||||
const row = object(value, `M4.6 playback chunk ${index}`);
|
||||
const start = index * chunkFrameCount;
|
||||
const count = Math.min(chunkFrameCount, frameCount - start);
|
||||
const pointStart = pointOffsets[start]!;
|
||||
const pointStop = pointOffsets[start + count]!;
|
||||
const pointChunkCount = pointStop - pointStart;
|
||||
exact(integer(row.index, `M4.6 playback chunk ${index}.index`), index, `M4.6 playback chunk ${index}.index`);
|
||||
exact(integer(row.start, `M4.6 playback chunk ${index}.start`), start, `M4.6 playback chunk ${index}.start`);
|
||||
exact(integer(row.count, `M4.6 playback chunk ${index}.count`), count, `M4.6 playback chunk ${index}.count`);
|
||||
exact(integer(row.point_start, `M4.6 playback chunk ${index}.point start`), pointStart, `M4.6 playback chunk ${index}.point start`);
|
||||
exact(integer(row.point_count, `M4.6 playback chunk ${index}.point count`), pointChunkCount, `M4.6 playback chunk ${index}.point count`);
|
||||
exact(row.media_type, "application/octet-stream", `M4.6 playback chunk ${index}.media type`);
|
||||
exact(row.dtype, "<f4", `M4.6 playback chunk ${index}.dtype`);
|
||||
const shapeValue = array(row.shape, `M4.6 playback chunk ${index}.shape`)
|
||||
.map((item) => integer(item, `M4.6 playback chunk ${index}.shape`));
|
||||
const chunkBytes = integer(row.bytes, `M4.6 playback chunk ${index}.bytes`);
|
||||
if (
|
||||
shapeValue.length !== 2
|
||||
|| shapeValue[0] !== pointChunkCount
|
||||
|| shapeValue[1] !== 3
|
||||
|| chunkBytes !== pointChunkCount * 3 * Float32Array.BYTES_PER_ELEMENT
|
||||
) {
|
||||
throw new M4ThreatContractError(`M4.6 playback chunk ${index}: нарушена размерность.`);
|
||||
}
|
||||
const chunkSha256 = text(row.sha256, `M4.6 playback chunk ${index}.SHA-256`);
|
||||
if (!/^[a-f0-9]{64}$/.test(chunkSha256)) {
|
||||
throw new M4ThreatContractError(`M4.6 playback chunk ${index}: SHA-256 недопустим.`);
|
||||
}
|
||||
const expectedUrl = `${endpointRoot}/${result}/timeline/playback/chunks/${index}`;
|
||||
const url = text(row.url, `M4.6 playback chunk ${index}.URL`);
|
||||
if (url !== expectedUrl || url.includes("worker")) {
|
||||
throw new M4ThreatContractError(`M4.6 playback chunk ${index}: разрешён только sealed local API.`);
|
||||
}
|
||||
return {
|
||||
index,
|
||||
start,
|
||||
count,
|
||||
pointStart,
|
||||
pointCount: pointChunkCount,
|
||||
url,
|
||||
mediaType: "application/octet-stream",
|
||||
byteLength: chunkBytes,
|
||||
sha256: chunkSha256,
|
||||
};
|
||||
});
|
||||
return {
|
||||
resultId: result,
|
||||
frameCount,
|
||||
pointCount,
|
||||
pointOffsets,
|
||||
chunkFrameCount,
|
||||
residentChunkCountMax,
|
||||
forwardPrefetchChunkCount,
|
||||
chunks,
|
||||
track: { url: trackUrl, byteLength, sha256 },
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM4ThreatPlaybackPointChunk(
|
||||
manifest: M4ThreatPlaybackManifest,
|
||||
chunkIndex: number,
|
||||
{
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
onProgress,
|
||||
}: {
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
onProgress?: (progress: M4ThreatPlaybackProgress) => void;
|
||||
} = {},
|
||||
): Promise<M4ThreatPlaybackPointPack> {
|
||||
const descriptor = manifest.chunks[chunkIndex];
|
||||
if (!descriptor || descriptor.index !== chunkIndex) {
|
||||
throw new M4ThreatContractError("M4.6 playback chunk отсутствует.");
|
||||
}
|
||||
onProgress?.({ phase: "download", loadedBytes: 0, totalBytes: descriptor.byteLength });
|
||||
const response = await fetcher(descriptor.url, {
|
||||
headers: { Accept: "application/octet-stream" },
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new M4ThreatContractError(`M4.6 playback chunk: HTTP ${response.status}.`);
|
||||
}
|
||||
const buffer = await response.arrayBuffer();
|
||||
if (buffer.byteLength !== descriptor.byteLength) {
|
||||
throw new M4ThreatContractError("M4.6 playback chunk: неверный размер.");
|
||||
}
|
||||
onProgress?.({
|
||||
phase: "verify",
|
||||
loadedBytes: descriptor.byteLength,
|
||||
totalBytes: descriptor.byteLength,
|
||||
});
|
||||
if (await playbackSha256Hex(buffer) !== descriptor.sha256) {
|
||||
throw new M4ThreatContractError("M4.6 playback chunk: SHA-256 не совпал.");
|
||||
}
|
||||
onProgress?.({
|
||||
phase: "ready",
|
||||
loadedBytes: descriptor.byteLength,
|
||||
totalBytes: descriptor.byteLength,
|
||||
});
|
||||
return {
|
||||
resultId: manifest.resultId,
|
||||
frameCount: manifest.frameCount,
|
||||
pointCount: descriptor.pointCount,
|
||||
pointOffsets: manifest.pointOffsets,
|
||||
pointsMapXyzM: new Float32Array(buffer),
|
||||
pointStart: descriptor.pointStart,
|
||||
startSequence: descriptor.start,
|
||||
sequenceCount: descriptor.count,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM4ThreatPlaybackPointPack(
|
||||
result: string,
|
||||
{
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
endpointRoot = M4_THREAT_TIMELINE_ENDPOINT_ROOT,
|
||||
onProgress,
|
||||
}: {
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
endpointRoot?: string;
|
||||
onProgress?: (progress: M4ThreatPlaybackProgress) => void;
|
||||
} = {},
|
||||
): Promise<M4ThreatPlaybackPointPack> {
|
||||
onProgress?.({ phase: "manifest", loadedBytes: 0, totalBytes: 0 });
|
||||
const manifest = await fetchM4ThreatPlaybackManifest(result, {
|
||||
fetcher,
|
||||
signal,
|
||||
endpointRoot,
|
||||
});
|
||||
const response = await fetcher(manifest.track.url, {
|
||||
headers: { Accept: "application/octet-stream" },
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) throw new M4ThreatContractError(`M4.6 playback points: HTTP ${response.status}.`);
|
||||
const buffer = await response.arrayBuffer();
|
||||
if (buffer.byteLength !== manifest.track.byteLength) {
|
||||
throw new M4ThreatContractError("M4.6 playback points: неверный размер.");
|
||||
}
|
||||
onProgress?.({ phase: "verify", loadedBytes: buffer.byteLength, totalBytes: buffer.byteLength });
|
||||
if (await playbackSha256Hex(buffer) !== manifest.track.sha256) {
|
||||
throw new M4ThreatContractError("M4.6 playback points: SHA-256 не совпал.");
|
||||
}
|
||||
onProgress?.({ phase: "ready", loadedBytes: buffer.byteLength, totalBytes: buffer.byteLength });
|
||||
return {
|
||||
resultId: manifest.resultId,
|
||||
frameCount: manifest.frameCount,
|
||||
pointCount: manifest.pointCount,
|
||||
pointOffsets: manifest.pointOffsets,
|
||||
pointsMapXyzM: new Float32Array(buffer),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchM4ThreatCameraPointOverlay(
|
||||
result: string,
|
||||
sequence: number,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,724 @@
|
||||
export type SimulationSceneType = "interior" | "outdoor" | "object";
|
||||
export type SimulationViewerQuality = "low" | "medium" | "high" | "ultra" | "maximum";
|
||||
export interface SimulationEulerRotation {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
}
|
||||
export type SimulationProjectStatus =
|
||||
| "uploading"
|
||||
| "queued"
|
||||
| "processing"
|
||||
| "importing"
|
||||
| "ready"
|
||||
| "failed";
|
||||
|
||||
export interface SimulationSourceFile {
|
||||
fileId: string;
|
||||
logicalPath: string;
|
||||
byteLength: number;
|
||||
uploadedBytes: number;
|
||||
sha256: string | null;
|
||||
}
|
||||
|
||||
export interface SimulationWorldManifest {
|
||||
schemaVersion: "missioncore.simulation-world-manifest/v1";
|
||||
projectId: string;
|
||||
visual: {
|
||||
previewSogUrl: string | null;
|
||||
streamedSogUrl: string | null;
|
||||
};
|
||||
collision: {
|
||||
meshUrl: string | null;
|
||||
available: boolean;
|
||||
};
|
||||
transforms: {
|
||||
worldFromVisual: number[];
|
||||
worldFromCollision: number[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface SimulationViewerSettings {
|
||||
schemaVersion: "missioncore.simulation-viewer-settings/v3";
|
||||
quality: SimulationViewerQuality;
|
||||
visual: { rotationDegrees: SimulationEulerRotation };
|
||||
collision: { rotationDegrees: SimulationEulerRotation };
|
||||
camera: { invertHorizontal: boolean; invertVertical: boolean };
|
||||
ugv: SimulationUgvPreset;
|
||||
}
|
||||
|
||||
export interface SimulationUgvPreset {
|
||||
presetName: string;
|
||||
massKg: number;
|
||||
dimensionsMeters: {
|
||||
length: number;
|
||||
width: number;
|
||||
height: number;
|
||||
groundClearance: number;
|
||||
};
|
||||
maxSpeedMetersPerSecond: number;
|
||||
maxTurnRateDegrees: number;
|
||||
invertSteering: boolean;
|
||||
}
|
||||
|
||||
export const SIMULATION_UGV_EXACT_VALUE_LIMITS = {
|
||||
massKg: { min: 0.01, max: 1_000_000_000 },
|
||||
length: { min: 0.01, max: 1_000_000_000 },
|
||||
width: { min: 0.01, max: 1_000_000_000 },
|
||||
height: { min: 0.07, max: 1_000_000_000 },
|
||||
groundClearance: { min: 0.01, max: 1_000_000_000 },
|
||||
maxSpeedMetersPerSecond: { min: 0, max: 1_000_000_000 },
|
||||
maxTurnRateDegrees: { min: 0, max: 1_000_000_000 },
|
||||
} as const;
|
||||
|
||||
export interface SimulationProject {
|
||||
schemaVersion: "missioncore.simulation-project/v1";
|
||||
projectId: string;
|
||||
name: string;
|
||||
sceneType: SimulationSceneType;
|
||||
status: SimulationProjectStatus;
|
||||
source: {
|
||||
kind: "archive" | "folder";
|
||||
totalByteLength: number;
|
||||
uploadedByteLength: number;
|
||||
files: SimulationSourceFile[];
|
||||
bundleSha256: string | null;
|
||||
};
|
||||
provider: {
|
||||
providerId: "gaussian-pipeline";
|
||||
jobId: string | null;
|
||||
jobCreatedAtUtc: string | null;
|
||||
state: string | null;
|
||||
stateStartedAtUtc: string | null;
|
||||
progress: { completed_steps?: number; total_steps?: number; stage?: string } | null;
|
||||
runtime: { source_revision?: string; image_digest?: string } | null;
|
||||
};
|
||||
artifacts: Array<{
|
||||
role: string;
|
||||
logicalPath: string;
|
||||
mediaType: string;
|
||||
sha256: string;
|
||||
byteLength: number;
|
||||
}>;
|
||||
worldManifest: SimulationWorldManifest | null;
|
||||
viewerSettings: SimulationViewerSettings;
|
||||
error: string | null;
|
||||
createdAtUtc: string;
|
||||
updatedAtUtc: string;
|
||||
}
|
||||
|
||||
export interface SimulationUploadCandidate {
|
||||
file: File;
|
||||
logicalPath: string;
|
||||
}
|
||||
|
||||
export interface SimulationUploadProgress {
|
||||
uploadedBytes: number;
|
||||
totalBytes: number;
|
||||
currentPath: string;
|
||||
bytesPerSecond: number | null;
|
||||
estimatedSecondsRemaining: number | null;
|
||||
}
|
||||
|
||||
const API_ROOT = "/api/v1/simulation-worlds/projects";
|
||||
const CHUNK_BYTES = 8 * 1024 * 1024;
|
||||
const MAX_UPLOAD_ATTEMPTS = 3;
|
||||
const REFERENCE_SOURCE_BYTES = 4_100_808_854;
|
||||
const REFERENCE_PREPARATION_SECONDS = 187;
|
||||
const REFERENCE_STREAM_SECONDS = 2_317;
|
||||
|
||||
export interface SimulationProcessingEstimate {
|
||||
percent: number;
|
||||
estimatedSecondsRemaining: number | null;
|
||||
}
|
||||
|
||||
export function estimateSimulationProcessing(
|
||||
project: SimulationProject,
|
||||
nowMilliseconds = Date.now(),
|
||||
): SimulationProcessingEstimate | null {
|
||||
if (project.status !== "processing") return null;
|
||||
const jobStarted = Date.parse(project.provider.jobCreatedAtUtc ?? "");
|
||||
if (!Number.isFinite(jobStarted)) return null;
|
||||
const elapsedSeconds = Math.max(0, (nowMilliseconds - jobStarted) / 1_000);
|
||||
const sourceScale = clamp(
|
||||
project.source.totalByteLength / REFERENCE_SOURCE_BYTES,
|
||||
0.1,
|
||||
4,
|
||||
);
|
||||
let expectedSeconds = (
|
||||
REFERENCE_PREPARATION_SECONDS + REFERENCE_STREAM_SECONDS
|
||||
) * sourceScale;
|
||||
if (project.provider.state === "building_streamed_sog") {
|
||||
const streamedStarted = Date.parse(project.provider.stateStartedAtUtc ?? "");
|
||||
if (Number.isFinite(streamedStarted) && streamedStarted >= jobStarted) {
|
||||
const preparationSeconds = Math.max(1, (streamedStarted - jobStarted) / 1_000);
|
||||
const observedLoad = clamp(
|
||||
preparationSeconds / (REFERENCE_PREPARATION_SECONDS * sourceScale),
|
||||
0.5,
|
||||
2,
|
||||
);
|
||||
expectedSeconds = preparationSeconds
|
||||
+ REFERENCE_STREAM_SECONDS * sourceScale * observedLoad;
|
||||
}
|
||||
}
|
||||
const rawPercent = expectedSeconds > 0 ? elapsedSeconds / expectedSeconds * 100 : 0;
|
||||
if (rawPercent >= 100) {
|
||||
return { percent: 99, estimatedSecondsRemaining: null };
|
||||
}
|
||||
return {
|
||||
percent: Math.max(1, Math.floor(rawPercent)),
|
||||
estimatedSecondsRemaining: Math.max(0, Math.ceil(expectedSeconds - elapsedSeconds)),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchSimulationProjects(signal?: AbortSignal): Promise<SimulationProject[]> {
|
||||
const response = await fetch(API_ROOT, { signal, cache: "no-store" });
|
||||
const document = await jsonResponse(response);
|
||||
const record = objectValue(document, "simulation project page");
|
||||
exactKeys(record, ["schema_version", "projects"], "simulation project page");
|
||||
if (record.schema_version !== "missioncore.simulation-project-page/v1" || !Array.isArray(record.projects)) {
|
||||
throw new Error("Каталог симуляций вернул неподдерживаемый контракт.");
|
||||
}
|
||||
return record.projects.map(parseProject);
|
||||
}
|
||||
|
||||
export async function createAndUploadSimulationProject(
|
||||
name: string,
|
||||
sceneType: SimulationSceneType,
|
||||
candidates: SimulationUploadCandidate[],
|
||||
onProgress: (progress: SimulationUploadProgress) => void,
|
||||
): Promise<SimulationProject> {
|
||||
const project = await createSimulationProject(name, sceneType, candidates);
|
||||
return uploadSimulationProjectSource(project, candidates, onProgress);
|
||||
}
|
||||
|
||||
export async function createSimulationProject(
|
||||
name: string,
|
||||
sceneType: SimulationSceneType,
|
||||
candidates: SimulationUploadCandidate[],
|
||||
): Promise<SimulationProject> {
|
||||
const sourceKind = sourceKindFor(candidates);
|
||||
const createdResponse = await fetch(API_ROOT, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
schema_version: "missioncore.simulation-project-create/v1",
|
||||
name,
|
||||
scene_type: sceneType,
|
||||
source_kind: sourceKind,
|
||||
files: candidates.map((candidate) => ({
|
||||
logical_path: candidate.logicalPath,
|
||||
byte_length: candidate.file.size,
|
||||
})),
|
||||
}),
|
||||
});
|
||||
return parseProject(await jsonResponse(createdResponse));
|
||||
}
|
||||
|
||||
export async function uploadSimulationProjectSource(
|
||||
project: SimulationProject,
|
||||
candidates: SimulationUploadCandidate[],
|
||||
onProgress: (progress: SimulationUploadProgress) => void,
|
||||
signal?: AbortSignal,
|
||||
): Promise<SimulationProject> {
|
||||
const byPath = new Map(candidates.map((candidate) => [candidate.logicalPath, candidate.file]));
|
||||
const totalBytes = candidates.reduce((total, candidate) => total + candidate.file.size, 0);
|
||||
let confirmedBytes = 0;
|
||||
let sampleBytes = 0;
|
||||
let sampleAt = performance.now();
|
||||
let smoothedBytesPerSecond: number | null = null;
|
||||
const reportProgress = (currentPath: string) => {
|
||||
const remainingBytes = Math.max(0, totalBytes - confirmedBytes);
|
||||
onProgress({
|
||||
uploadedBytes: confirmedBytes,
|
||||
totalBytes,
|
||||
currentPath,
|
||||
bytesPerSecond: smoothedBytesPerSecond,
|
||||
estimatedSecondsRemaining: smoothedBytesPerSecond && remainingBytes > 0
|
||||
? Math.ceil(remainingBytes / smoothedBytesPerSecond)
|
||||
: remainingBytes === 0 ? 0 : null,
|
||||
});
|
||||
};
|
||||
for (const sourceFile of project.source.files) {
|
||||
signal?.throwIfAborted();
|
||||
const file = byPath.get(sourceFile.logicalPath);
|
||||
if (!file) throw new Error(`Сервер изменил состав источника: ${sourceFile.logicalPath}`);
|
||||
const uploadUrl = `${API_ROOT}/${encodeURIComponent(project.projectId)}/source/${encodeURIComponent(sourceFile.fileId)}`;
|
||||
let offset = await readUploadOffset(uploadUrl, file.size, signal);
|
||||
confirmedBytes += offset;
|
||||
sampleBytes = confirmedBytes;
|
||||
sampleAt = performance.now();
|
||||
reportProgress(sourceFile.logicalPath);
|
||||
while (offset < file.size) {
|
||||
signal?.throwIfAborted();
|
||||
const nextOffset = Math.min(file.size, offset + CHUNK_BYTES);
|
||||
const confirmedOffset = await uploadChunk(uploadUrl, file, offset, nextOffset, signal);
|
||||
confirmedBytes += confirmedOffset - offset;
|
||||
offset = confirmedOffset;
|
||||
const now = performance.now();
|
||||
const elapsedSeconds = (now - sampleAt) / 1_000;
|
||||
const transferredBytes = confirmedBytes - sampleBytes;
|
||||
if (elapsedSeconds > 0 && transferredBytes > 0) {
|
||||
const currentBytesPerSecond = transferredBytes / elapsedSeconds;
|
||||
smoothedBytesPerSecond = smoothedBytesPerSecond === null
|
||||
? currentBytesPerSecond
|
||||
: smoothedBytesPerSecond * 0.7 + currentBytesPerSecond * 0.3;
|
||||
}
|
||||
sampleBytes = confirmedBytes;
|
||||
sampleAt = now;
|
||||
reportProgress(sourceFile.logicalPath);
|
||||
}
|
||||
}
|
||||
return startSimulationProjectBuild(project.projectId, signal);
|
||||
}
|
||||
|
||||
export async function startSimulationProjectBuild(
|
||||
projectId: string,
|
||||
signal?: AbortSignal,
|
||||
): Promise<SimulationProject> {
|
||||
const buildResponse = await fetch(`${API_ROOT}/${encodeURIComponent(projectId)}/build`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: "{}",
|
||||
signal,
|
||||
});
|
||||
return parseProject(await jsonResponse(buildResponse));
|
||||
}
|
||||
|
||||
async function readUploadOffset(
|
||||
uploadUrl: string,
|
||||
fileSize: number,
|
||||
signal?: AbortSignal,
|
||||
): Promise<number> {
|
||||
const head = await fetch(uploadUrl, { method: "HEAD", cache: "no-store", signal });
|
||||
if (!head.ok) await jsonResponse(head);
|
||||
const value = head.headers.get("Upload-Offset");
|
||||
if (!value || !/^\d+$/.test(value)) {
|
||||
throw new Error("Сервер не вернул смещение resumable-загрузки.");
|
||||
}
|
||||
const offset = Number(value);
|
||||
if (!Number.isSafeInteger(offset) || offset < 0 || offset > fileSize) {
|
||||
throw new Error("Сервер вернул некорректное смещение загрузки.");
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
async function uploadChunk(
|
||||
uploadUrl: string,
|
||||
file: File,
|
||||
offset: number,
|
||||
nextOffset: number,
|
||||
signal?: AbortSignal,
|
||||
): Promise<number> {
|
||||
let lastFailure: unknown = null;
|
||||
for (let attempt = 1; attempt <= MAX_UPLOAD_ATTEMPTS; attempt += 1) {
|
||||
let response: Response | null = null;
|
||||
try {
|
||||
signal?.throwIfAborted();
|
||||
response = await fetch(uploadUrl, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/offset+octet-stream",
|
||||
"Upload-Offset": String(offset),
|
||||
},
|
||||
body: file.slice(offset, nextOffset),
|
||||
signal,
|
||||
});
|
||||
} catch (caught) {
|
||||
if (signal?.aborted) throw caught;
|
||||
lastFailure = caught;
|
||||
}
|
||||
if (response?.ok) {
|
||||
const confirmed = response.headers.get("Upload-Offset");
|
||||
if (confirmed && Number(confirmed) === nextOffset) return nextOffset;
|
||||
throw new Error("Сервер не подтвердил непрерывность загрузки.");
|
||||
}
|
||||
if (
|
||||
response &&
|
||||
((response.status < 500 && response.status !== 409) ||
|
||||
(response.status >= 500 && attempt === MAX_UPLOAD_ATTEMPTS))
|
||||
) {
|
||||
await jsonResponse(response);
|
||||
throw new Error("Mission Core отклонил блок загрузки.");
|
||||
}
|
||||
if (response) {
|
||||
lastFailure = new Error(`Mission Core временно вернул HTTP ${response.status}.`);
|
||||
}
|
||||
try {
|
||||
const confirmed = await readUploadOffset(uploadUrl, file.size, signal);
|
||||
if (confirmed === nextOffset) return confirmed;
|
||||
if (confirmed !== offset) {
|
||||
throw new Error("Сервер подтвердил неожиданное смещение загрузки.");
|
||||
}
|
||||
} catch (caught) {
|
||||
lastFailure = caught;
|
||||
}
|
||||
}
|
||||
throw lastFailure instanceof Error
|
||||
? lastFailure
|
||||
: new Error("Не удалось продолжить resumable-загрузку.");
|
||||
}
|
||||
|
||||
export async function updateSimulationProject(
|
||||
projectId: string,
|
||||
name: string,
|
||||
sceneType: SimulationSceneType,
|
||||
): Promise<SimulationProject> {
|
||||
const response = await fetch(`${API_ROOT}/${encodeURIComponent(projectId)}`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
schema_version: "missioncore.simulation-project-update/v1",
|
||||
name,
|
||||
scene_type: sceneType,
|
||||
}),
|
||||
});
|
||||
return parseProject(await jsonResponse(response));
|
||||
}
|
||||
|
||||
export async function saveSimulationViewerSettings(
|
||||
projectId: string,
|
||||
settings: SimulationViewerSettings,
|
||||
): Promise<SimulationProject> {
|
||||
const response = await fetch(
|
||||
`${API_ROOT}/${encodeURIComponent(projectId)}/viewer-settings`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
schema_version: settings.schemaVersion,
|
||||
quality: settings.quality,
|
||||
visual: { rotation_degrees: settings.visual.rotationDegrees },
|
||||
collision: { rotation_degrees: settings.collision.rotationDegrees },
|
||||
camera: {
|
||||
invert_horizontal: settings.camera.invertHorizontal,
|
||||
invert_vertical: settings.camera.invertVertical,
|
||||
},
|
||||
ugv: {
|
||||
preset_name: settings.ugv.presetName,
|
||||
mass_kg: settings.ugv.massKg,
|
||||
dimensions_m: {
|
||||
length: settings.ugv.dimensionsMeters.length,
|
||||
width: settings.ugv.dimensionsMeters.width,
|
||||
height: settings.ugv.dimensionsMeters.height,
|
||||
ground_clearance: settings.ugv.dimensionsMeters.groundClearance,
|
||||
},
|
||||
max_speed_mps: settings.ugv.maxSpeedMetersPerSecond,
|
||||
max_turn_rate_degrees: settings.ugv.maxTurnRateDegrees,
|
||||
invert_steering: settings.ugv.invertSteering,
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
return parseProject(await jsonResponse(response));
|
||||
}
|
||||
|
||||
export const retrySimulationProject = startSimulationProjectBuild;
|
||||
|
||||
export async function deleteSimulationProject(projectId: string): Promise<void> {
|
||||
const response = await fetch(`${API_ROOT}/${encodeURIComponent(projectId)}`, { method: "DELETE" });
|
||||
if (!response.ok) await jsonResponse(response);
|
||||
}
|
||||
|
||||
function sourceKindFor(candidates: SimulationUploadCandidate[]): "archive" | "folder" {
|
||||
if (candidates.length === 1 && /\.(zip|rar|7z)$/i.test(candidates[0]?.logicalPath ?? "")) {
|
||||
return "archive";
|
||||
}
|
||||
if (candidates.some((candidate) => /\.(zip|rar|7z)$/i.test(candidate.logicalPath))) {
|
||||
throw new Error("Архив загружается отдельно; нельзя смешивать его с файлами папки.");
|
||||
}
|
||||
return "folder";
|
||||
}
|
||||
|
||||
function parseProject(value: unknown): SimulationProject {
|
||||
const record = objectValue(value, "simulation project");
|
||||
exactKeys(record, [
|
||||
"schema_version", "project_id", "name", "scene_type", "status", "source", "provider",
|
||||
"artifacts", "world_manifest", "viewer_settings", "error", "created_at_utc", "updated_at_utc",
|
||||
], "simulation project");
|
||||
if (record.schema_version !== "missioncore.simulation-project/v1") {
|
||||
throw new Error("Проект симуляции вернул неподдерживаемую версию.");
|
||||
}
|
||||
const source = objectValue(record.source, "simulation source");
|
||||
const provider = objectValue(record.provider, "simulation provider");
|
||||
if (!Array.isArray(source.files) || !Array.isArray(record.artifacts)) {
|
||||
throw new Error("Проект симуляции вернул некорректный состав файлов.");
|
||||
}
|
||||
return {
|
||||
schemaVersion: "missioncore.simulation-project/v1",
|
||||
projectId: stringValue(record.project_id, "project id"),
|
||||
name: stringValue(record.name, "project name"),
|
||||
sceneType: sceneTypeValue(record.scene_type),
|
||||
status: statusValue(record.status),
|
||||
source: {
|
||||
kind: source.kind === "archive" ? "archive" : source.kind === "folder" ? "folder" : invalid("source kind"),
|
||||
totalByteLength: numberValue(source.total_byte_length, "source bytes"),
|
||||
uploadedByteLength: numberValue(source.uploaded_byte_length, "uploaded bytes"),
|
||||
files: source.files.map((item) => {
|
||||
const file = objectValue(item, "source file");
|
||||
return {
|
||||
fileId: stringValue(file.file_id, "source file id"),
|
||||
logicalPath: stringValue(file.logical_path, "source logical path"),
|
||||
byteLength: numberValue(file.byte_length, "source file bytes"),
|
||||
uploadedBytes: numberValue(file.uploaded_bytes, "source uploaded bytes"),
|
||||
sha256: nullableString(file.sha256, "source sha256"),
|
||||
};
|
||||
}),
|
||||
bundleSha256: nullableString(source.bundle_sha256, "bundle sha256"),
|
||||
},
|
||||
provider: {
|
||||
providerId: provider.provider_id === "gaussian-pipeline" ? "gaussian-pipeline" : invalid("provider id"),
|
||||
jobId: nullableString(provider.job_id, "provider job id"),
|
||||
jobCreatedAtUtc: nullableString(provider.job_created_at_utc ?? null, "provider job creation"),
|
||||
state: nullableString(provider.state, "provider state"),
|
||||
stateStartedAtUtc: nullableString(provider.state_started_at_utc ?? null, "provider state start"),
|
||||
progress: provider.progress === null ? null : objectValue(provider.progress, "provider progress"),
|
||||
runtime: provider.runtime === null ? null : objectValue(provider.runtime, "provider runtime"),
|
||||
},
|
||||
artifacts: record.artifacts.map((item) => {
|
||||
const artifact = objectValue(item, "simulation artifact");
|
||||
return {
|
||||
role: stringValue(artifact.role, "artifact role"),
|
||||
logicalPath: stringValue(artifact.logical_path, "artifact path"),
|
||||
mediaType: stringValue(artifact.media_type, "artifact media type"),
|
||||
sha256: stringValue(artifact.sha256, "artifact sha256"),
|
||||
byteLength: numberValue(artifact.byte_length, "artifact bytes"),
|
||||
};
|
||||
}),
|
||||
worldManifest: record.world_manifest === null ? null : parseWorldManifest(record.world_manifest),
|
||||
viewerSettings: parseViewerSettings(record.viewer_settings),
|
||||
error: nullableString(record.error, "project error"),
|
||||
createdAtUtc: stringValue(record.created_at_utc, "created at"),
|
||||
updatedAtUtc: stringValue(record.updated_at_utc, "updated at"),
|
||||
};
|
||||
}
|
||||
|
||||
function parseViewerSettings(value: unknown): SimulationViewerSettings {
|
||||
const record = objectValue(value, "viewer settings");
|
||||
exactKeys(record, ["schema_version", "quality", "visual", "collision", "camera", "ugv"], "viewer settings");
|
||||
if (record.schema_version !== "missioncore.simulation-viewer-settings/v3") {
|
||||
throw new Error("Настройки сцены вернули неподдерживаемую версию.");
|
||||
}
|
||||
const visual = parseLayerViewerSettings(record.visual, "visual settings");
|
||||
const collision = parseLayerViewerSettings(record.collision, "collision settings");
|
||||
const camera = objectValue(record.camera, "camera settings");
|
||||
exactKeys(camera, ["invert_horizontal", "invert_vertical"], "camera settings");
|
||||
const ugv = parseUgvPreset(record.ugv);
|
||||
return {
|
||||
schemaVersion: "missioncore.simulation-viewer-settings/v3",
|
||||
quality: qualityValue(record.quality),
|
||||
visual,
|
||||
collision,
|
||||
camera: {
|
||||
invertHorizontal: booleanValue(camera.invert_horizontal, "horizontal camera inversion"),
|
||||
invertVertical: booleanValue(camera.invert_vertical, "vertical camera inversion"),
|
||||
},
|
||||
ugv,
|
||||
};
|
||||
}
|
||||
|
||||
function parseUgvPreset(value: unknown): SimulationUgvPreset {
|
||||
const record = objectValue(value, "UGV settings");
|
||||
exactKeys(
|
||||
record,
|
||||
["preset_name", "mass_kg", "dimensions_m", "max_speed_mps", "max_turn_rate_degrees", "invert_steering"],
|
||||
"UGV settings",
|
||||
);
|
||||
const dimensions = objectValue(record.dimensions_m, "UGV dimensions");
|
||||
exactKeys(dimensions, ["length", "width", "height", "ground_clearance"], "UGV dimensions");
|
||||
const presetName = stringValue(record.preset_name, "UGV preset name");
|
||||
if (presetName.length > 80) return invalid("UGV preset name");
|
||||
const height = finiteNumberValue(
|
||||
dimensions.height,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.height.min,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.height.max,
|
||||
"UGV height",
|
||||
);
|
||||
const groundClearance = finiteNumberValue(
|
||||
dimensions.ground_clearance,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.groundClearance.min,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.groundClearance.max,
|
||||
"UGV ground clearance",
|
||||
);
|
||||
if (groundClearance >= height - 0.05) return invalid("UGV ground clearance");
|
||||
return {
|
||||
presetName,
|
||||
massKg: finiteNumberValue(
|
||||
record.mass_kg,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.massKg.min,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.massKg.max,
|
||||
"UGV mass",
|
||||
),
|
||||
dimensionsMeters: {
|
||||
length: finiteNumberValue(
|
||||
dimensions.length,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.length.min,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.length.max,
|
||||
"UGV length",
|
||||
),
|
||||
width: finiteNumberValue(
|
||||
dimensions.width,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.width.min,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.width.max,
|
||||
"UGV width",
|
||||
),
|
||||
height,
|
||||
groundClearance,
|
||||
},
|
||||
maxSpeedMetersPerSecond: finiteNumberValue(
|
||||
record.max_speed_mps,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.maxSpeedMetersPerSecond.min,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.maxSpeedMetersPerSecond.max,
|
||||
"UGV maximum speed",
|
||||
),
|
||||
maxTurnRateDegrees: finiteNumberValue(
|
||||
record.max_turn_rate_degrees,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.maxTurnRateDegrees.min,
|
||||
SIMULATION_UGV_EXACT_VALUE_LIMITS.maxTurnRateDegrees.max,
|
||||
"UGV maximum turn rate",
|
||||
),
|
||||
invertSteering: booleanValue(record.invert_steering, "UGV steering inversion"),
|
||||
};
|
||||
}
|
||||
|
||||
function parseLayerViewerSettings(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): { rotationDegrees: SimulationEulerRotation } {
|
||||
const record = objectValue(value, label);
|
||||
exactKeys(record, ["rotation_degrees"], label);
|
||||
const rotation = objectValue(record.rotation_degrees, `${label} rotation`);
|
||||
exactKeys(rotation, ["x", "y", "z"], `${label} rotation`);
|
||||
return {
|
||||
rotationDegrees: {
|
||||
x: rotationValue(rotation.x, `${label} X rotation`),
|
||||
y: rotationValue(rotation.y, `${label} Y rotation`),
|
||||
z: rotationValue(rotation.z, `${label} Z rotation`),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function parseWorldManifest(value: unknown): SimulationWorldManifest {
|
||||
const record = objectValue(value, "world manifest");
|
||||
const visual = objectValue(record.visual, "visual manifest");
|
||||
const collision = objectValue(record.collision, "collision manifest");
|
||||
const transforms = objectValue(record.transforms, "world transforms");
|
||||
if (record.schema_version !== "missioncore.simulation-world-manifest/v1") {
|
||||
throw new Error("World manifest вернул неподдерживаемую версию.");
|
||||
}
|
||||
return {
|
||||
schemaVersion: "missioncore.simulation-world-manifest/v1",
|
||||
projectId: stringValue(record.project_id, "manifest project id"),
|
||||
visual: {
|
||||
previewSogUrl: nullableString(visual.preview_sog_url, "preview URL"),
|
||||
streamedSogUrl: nullableString(visual.streamed_sog_url, "streamed URL"),
|
||||
},
|
||||
collision: {
|
||||
meshUrl: nullableString(collision.mesh_url, "collision URL"),
|
||||
available: booleanValue(collision.available, "collision availability"),
|
||||
},
|
||||
transforms: {
|
||||
worldFromVisual: matrixValue(transforms.world_from_visual, "visual transform"),
|
||||
worldFromCollision: matrixValue(transforms.world_from_collision, "collision transform"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function jsonResponse(response: Response): Promise<unknown> {
|
||||
let value: unknown;
|
||||
try {
|
||||
value = await response.json();
|
||||
} catch {
|
||||
if (response.ok) return {};
|
||||
throw new Error(`Mission Core вернул HTTP ${response.status}.`);
|
||||
}
|
||||
if (!response.ok) {
|
||||
const detail = objectValue(value, "error response").detail;
|
||||
throw new Error(typeof detail === "string" ? detail : `Mission Core вернул HTTP ${response.status}.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function objectValue(value: unknown, label: string): Record<string, any> {
|
||||
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
||||
throw new Error(`Некорректный ${label}.`);
|
||||
}
|
||||
return value as Record<string, any>;
|
||||
}
|
||||
|
||||
function exactKeys(record: Record<string, any>, keys: string[], label: string): void {
|
||||
const actual = Object.keys(record).sort();
|
||||
const expected = [...keys].sort();
|
||||
if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
|
||||
throw new Error(`Некорректные поля ${label}.`);
|
||||
}
|
||||
}
|
||||
|
||||
function stringValue(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value) throw new Error(`Некорректный ${label}.`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function nullableString(value: unknown, label: string): string | null {
|
||||
return value === null ? null : stringValue(value, label);
|
||||
}
|
||||
|
||||
function numberValue(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
||||
throw new Error(`Некорректный ${label}.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function booleanValue(value: unknown, label: string): boolean {
|
||||
if (typeof value !== "boolean") throw new Error(`Некорректный ${label}.`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function matrixValue(value: unknown, label: string): number[] {
|
||||
if (!Array.isArray(value) || value.length !== 16 || value.some((item) => typeof item !== "number")) {
|
||||
throw new Error(`Некорректный ${label}.`);
|
||||
}
|
||||
return [...value];
|
||||
}
|
||||
|
||||
function sceneTypeValue(value: unknown): SimulationSceneType {
|
||||
if (value === "interior" || value === "outdoor" || value === "object") return value;
|
||||
return invalid("scene type");
|
||||
}
|
||||
|
||||
function rotationValue(value: unknown, label: string): number {
|
||||
if (typeof value === "number" && Number.isFinite(value) && value >= -360 && value <= 360) {
|
||||
return value;
|
||||
}
|
||||
return invalid(label);
|
||||
}
|
||||
|
||||
function finiteNumberValue(value: unknown, minimum: number, maximum: number, label: string): number {
|
||||
if (typeof value === "number" && Number.isFinite(value) && value >= minimum && value <= maximum) {
|
||||
return value;
|
||||
}
|
||||
return invalid(label);
|
||||
}
|
||||
|
||||
function qualityValue(value: unknown): SimulationViewerQuality {
|
||||
if (["low", "medium", "high", "ultra", "maximum"].includes(String(value))) {
|
||||
return value as SimulationViewerQuality;
|
||||
}
|
||||
return invalid("viewer quality");
|
||||
}
|
||||
|
||||
function statusValue(value: unknown): SimulationProjectStatus {
|
||||
if (["uploading", "queued", "processing", "importing", "ready", "failed"].includes(String(value))) {
|
||||
return value as SimulationProjectStatus;
|
||||
}
|
||||
return invalid("project status");
|
||||
}
|
||||
|
||||
function invalid(label: string): never {
|
||||
throw new Error(`Некорректный ${label}.`);
|
||||
}
|
||||
|
||||
function clamp(value: number, minimum: number, maximum: number): number {
|
||||
return Math.min(maximum, Math.max(minimum, value));
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
import type { SimulationUploadCandidate } from "./projects";
|
||||
|
||||
const ARCHIVE_PATTERN = /\.(zip|rar|7z)$/i;
|
||||
export const MAX_SIMULATION_SOURCE_BYTES = 16 * 1024 ** 3;
|
||||
|
||||
interface LegacyFileEntry {
|
||||
isFile: boolean;
|
||||
isDirectory: boolean;
|
||||
name: string;
|
||||
fullPath: string;
|
||||
file?: (callback: (file: File) => void, error?: (error: DOMException) => void) => void;
|
||||
createReader?: () => LegacyDirectoryReader;
|
||||
}
|
||||
|
||||
interface LegacyDirectoryReader {
|
||||
readEntries: (
|
||||
callback: (entries: LegacyFileEntry[]) => void,
|
||||
error?: (error: DOMException) => void,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export async function candidatesFromDrop(
|
||||
transfer: DataTransfer,
|
||||
): Promise<SimulationUploadCandidate[]> {
|
||||
const candidates: SimulationUploadCandidate[] = [];
|
||||
for (const item of Array.from(transfer.items)) {
|
||||
const entry = (item as DataTransferItem & {
|
||||
webkitGetAsEntry?: () => LegacyFileEntry | null;
|
||||
}).webkitGetAsEntry?.();
|
||||
if (entry?.isDirectory) {
|
||||
await collectEntry(entry, candidates);
|
||||
continue;
|
||||
}
|
||||
const file = item.getAsFile();
|
||||
if (file) {
|
||||
candidates.push({ file, logicalPath: file.name });
|
||||
continue;
|
||||
}
|
||||
if (entry) await collectEntry(entry, candidates);
|
||||
}
|
||||
if (!candidates.length) {
|
||||
for (const file of Array.from(transfer.files)) {
|
||||
candidates.push({ file, logicalPath: file.name });
|
||||
}
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
export async function archivesFromDrop(transfer: DataTransfer): Promise<File[]> {
|
||||
const candidates = await candidatesFromDrop(transfer);
|
||||
const invalid = candidates.filter((candidate) => !ARCHIVE_PATTERN.test(candidate.logicalPath));
|
||||
if (invalid.length) {
|
||||
throw new Error("В каталог можно перетащить только отдельные архивы ZIP, RAR или 7z.");
|
||||
}
|
||||
if (!candidates.length) {
|
||||
throw new Error("В перетаскивании не найдено архивов ZIP, RAR или 7z.");
|
||||
}
|
||||
for (const candidate of candidates) {
|
||||
if (candidate.logicalPath.includes("/")) {
|
||||
throw new Error("Перетащите сами архивы, а не содержащую их папку.");
|
||||
}
|
||||
if (candidate.file.size <= 0) {
|
||||
throw new Error(`Пустой архив: ${candidate.file.name}`);
|
||||
}
|
||||
if (candidate.file.size > MAX_SIMULATION_SOURCE_BYTES) {
|
||||
throw new Error(`Архив ${candidate.file.name} превышает лимит 16 ГБ.`);
|
||||
}
|
||||
}
|
||||
return candidates.map((candidate) => candidate.file);
|
||||
}
|
||||
|
||||
export function validateSimulationCandidates(candidates: SimulationUploadCandidate[]): void {
|
||||
if (!candidates.length) throw new Error("Выберите архив или папку с результатом LCC/LCC2.");
|
||||
const archives = candidates.filter((candidate) => ARCHIVE_PATTERN.test(candidate.logicalPath));
|
||||
if (archives.length) {
|
||||
if (candidates.length !== 1) throw new Error("Архив нужно загружать одним файлом.");
|
||||
if (archives[0]!.file.size <= 0) throw new Error(`Пустой файл: ${archives[0]!.logicalPath}`);
|
||||
if (archives[0]!.file.size > MAX_SIMULATION_SOURCE_BYTES) {
|
||||
throw new Error(`Архив ${archives[0]!.logicalPath} превышает лимит 16 ГБ.`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const descriptors = candidates.filter((candidate) => /\.lcc2?$/i.test(candidate.logicalPath));
|
||||
if (descriptors.length !== 1) {
|
||||
throw new Error("В папке должна быть ровно одна сцена .lcc или .lcc2.");
|
||||
}
|
||||
const paths = new Set<string>();
|
||||
let totalBytes = 0;
|
||||
for (const candidate of candidates) {
|
||||
const parts = candidate.logicalPath.split("/");
|
||||
if (
|
||||
!candidate.logicalPath
|
||||
|| candidate.logicalPath.startsWith("/")
|
||||
|| candidate.logicalPath.includes("\\")
|
||||
|| candidate.logicalPath.includes("\0")
|
||||
|| parts.some((part) => part === "" || part === "." || part === "..")
|
||||
) {
|
||||
throw new Error("Папка содержит небезопасный путь.");
|
||||
}
|
||||
if (candidate.file.size <= 0) throw new Error(`Пустой файл: ${candidate.logicalPath}`);
|
||||
totalBytes += candidate.file.size;
|
||||
if (paths.has(candidate.logicalPath)) throw new Error(`Повторяющийся путь: ${candidate.logicalPath}`);
|
||||
paths.add(candidate.logicalPath);
|
||||
}
|
||||
if (totalBytes > MAX_SIMULATION_SOURCE_BYTES) {
|
||||
throw new Error("Папка с исходниками превышает лимит 16 ГБ.");
|
||||
}
|
||||
}
|
||||
|
||||
export function hasDroppedFiles(transfer: DataTransfer): boolean {
|
||||
return transfer.files.length > 0
|
||||
|| Array.from(transfer.items).some((item) => item.kind === "file")
|
||||
|| Array.from(transfer.types).some((type) => type.toLowerCase() === "files");
|
||||
}
|
||||
|
||||
export function archiveProjectName(fileName: string): string {
|
||||
const name = fileName.replace(ARCHIVE_PATTERN, "").trim();
|
||||
return name || "Новая сцена";
|
||||
}
|
||||
|
||||
function collectEntry(
|
||||
entry: LegacyFileEntry,
|
||||
target: SimulationUploadCandidate[],
|
||||
): Promise<void> {
|
||||
if (entry.isFile && entry.file) {
|
||||
return new Promise<File>((resolve, reject) => entry.file?.(resolve, reject))
|
||||
.then((file) => {
|
||||
target.push({ file, logicalPath: entry.fullPath.replace(/^\//, "") || file.name });
|
||||
});
|
||||
}
|
||||
if (!entry.isDirectory || !entry.createReader) return Promise.resolve();
|
||||
return collectDirectory(entry.createReader(), target);
|
||||
}
|
||||
|
||||
async function collectDirectory(
|
||||
reader: LegacyDirectoryReader,
|
||||
target: SimulationUploadCandidate[],
|
||||
): Promise<void> {
|
||||
while (true) {
|
||||
const batch = await new Promise<LegacyFileEntry[]>((resolve, reject) => {
|
||||
reader.readEntries(resolve, reject);
|
||||
});
|
||||
if (!batch.length) return;
|
||||
for (const child of batch) await collectEntry(child, target);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,8 @@ export type WorkspaceKind =
|
||||
| "network-monitor"
|
||||
| "datasets"
|
||||
| "artifact-health"
|
||||
| "lab-archive";
|
||||
| "lab-archive"
|
||||
| "simulations";
|
||||
|
||||
export type CapabilityStatus = "active" | "ready" | "contract" | "later";
|
||||
|
||||
@@ -154,6 +155,17 @@ export const workspaces: WorkspaceDefinition[] = [
|
||||
kind: "lab-archive",
|
||||
groups: [],
|
||||
},
|
||||
{
|
||||
id: "simulations",
|
||||
root: "polygon",
|
||||
label: "Симуляции",
|
||||
title: "Симуляции",
|
||||
eyebrow: "ТЕСТОВЫЙ КОНТУР / СИМУЛЯЦИИ",
|
||||
description: "Каталог Gaussian-миров, переносимые сборки и интерактивные сцены.",
|
||||
icon: "globe",
|
||||
kind: "simulations",
|
||||
groups: [],
|
||||
},
|
||||
{
|
||||
id: "contour-health",
|
||||
root: "fleet",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
@import "./styles/l3-pointpillars-visual-audit.css";
|
||||
@import "./styles/l34-annotation.css";
|
||||
@import "./styles/laboratory-reporting.css";
|
||||
@import "./styles/simulation.css";
|
||||
@import "./styles/laboratory-evidence-report.css";
|
||||
@import "./styles/e34-temporal-layer.css";
|
||||
@import "./styles/m4-replay-threat.css";
|
||||
|
||||
@@ -81,10 +81,36 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.m4-replay-threat-visual__pane-toolbar[data-pane-toolbar="media"][data-multi-semantic="true"] {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.m4-replay-threat-visual__pane-toolbar[data-pane-toolbar="media"][data-multi-semantic="true"]
|
||||
> .m4-replay-threat-visual__pane-layer-controls {
|
||||
flex: 1 0 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.m4-replay-threat-visual__pane-toolbar[data-pane-toolbar="media"][data-multi-semantic="true"]
|
||||
> .m4-replay-threat-visual__pane-mode-controls {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.m4-replay-threat-evidence-viewer[data-mode-controls="content"]:has(
|
||||
.m4-replay-threat-visual__review-controls
|
||||
) .m4-replay-threat-visual__pane-toolbar[data-pane-toolbar="media"] {
|
||||
top: 3.8rem;
|
||||
}
|
||||
|
||||
.m4-replay-threat-visual__pane-toolbar[data-pane-toolbar="spatial"] {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.m4-replay-threat-evidence-viewer[data-mode-controls="content"]
|
||||
.m4-replay-threat-visual__pane-toolbar[data-pane-toolbar="spatial"] {
|
||||
right: 3.8rem;
|
||||
}
|
||||
|
||||
.m4-replay-threat-visual__pane-toolbar > *,
|
||||
.m4-replay-threat-visual__spatial-toolbar-end > * {
|
||||
pointer-events: auto;
|
||||
@@ -225,9 +251,10 @@
|
||||
box-sizing: border-box;
|
||||
min-width: 0;
|
||||
align-items: stretch;
|
||||
width: max-content;
|
||||
max-width: calc(var(--m4-replay-threat-overlay-pane-width, 100%) - 1.2rem);
|
||||
grid-template-columns: minmax(0, max-content);
|
||||
width: min(17.5rem, calc(var(--m4-replay-threat-overlay-pane-width, 100%) - 1.2rem));
|
||||
max-width: none;
|
||||
grid-auto-rows: 3.8rem;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 0.3rem;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
@@ -236,6 +263,9 @@
|
||||
}
|
||||
|
||||
.m4-replay-threat-visual__overlay > div {
|
||||
box-sizing: border-box;
|
||||
height: 3.8rem;
|
||||
grid-template-rows: auto auto minmax(1.32rem, 1fr);
|
||||
border-radius: var(--nodedc-radius-control-compact);
|
||||
background: color-mix(in srgb, var(--nodedc-floating-surface) 80%, transparent);
|
||||
padding: 0.55rem 0.65rem;
|
||||
@@ -243,15 +273,24 @@
|
||||
}
|
||||
|
||||
.m4-replay-threat-visual__overlay span,
|
||||
.m4-replay-threat-visual__overlay strong,
|
||||
.m4-replay-threat-visual__overlay small {
|
||||
.m4-replay-threat-visual__overlay strong {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.m4-replay-threat-visual__overlay small {
|
||||
display: -webkit-box;
|
||||
min-height: 1.32rem;
|
||||
overflow: hidden;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.m4-replay-threat-visual__overlay {
|
||||
width: min(17.5rem, calc(100% - 1.2rem));
|
||||
max-width: calc(100% - 1.2rem);
|
||||
}
|
||||
}
|
||||
@@ -334,7 +373,40 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.laboratory-metric-evidence-scene__legend span[data-decision="low-step"]::before {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid rgb(var(--nodedc-foreground-rgb));
|
||||
background: rgb(var(--nodedc-accent-rgb));
|
||||
}
|
||||
|
||||
.laboratory-metric-evidence-scene__legend span[data-decision="local-surface"]::before {
|
||||
background: rgb(var(--nodedc-accent-rgb));
|
||||
opacity: 0.72;
|
||||
}
|
||||
|
||||
.laboratory-metric-evidence-scene__legend span[data-decision="ground-support"]::before {
|
||||
background: rgb(var(--nodedc-success-rgb));
|
||||
}
|
||||
|
||||
.laboratory-metric-evidence-scene__legend span[data-decision="nonground-occupied"]::before {
|
||||
background: rgb(var(--nodedc-danger-rgb));
|
||||
}
|
||||
|
||||
.laboratory-metric-evidence-scene__legend span[data-decision="unknown-rejected"]::before {
|
||||
background: rgb(var(--nodedc-warning-rgb));
|
||||
}
|
||||
|
||||
.laboratory-metric-evidence-scene__legend span[data-decision="unobserved"]::before {
|
||||
background: var(--nodedc-text-muted);
|
||||
opacity: 0.42;
|
||||
}
|
||||
|
||||
.laboratory-metric-evidence-scene__legend span[data-decision="performance"] {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.laboratory-metric-evidence-scene__legend span[data-decision="performance"]::before {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid rgb(var(--nodedc-accent-rgb));
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,809 @@
|
||||
.simulation-workspace {
|
||||
display: grid;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
gap: 0.9rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.simulation-workspace--scene {
|
||||
height: 100%;
|
||||
min-height: 38rem;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.simulation-workspace__head,
|
||||
.simulation-workspace__scene-head,
|
||||
.simulation-viewport__toolbar,
|
||||
.simulation-viewport__notice,
|
||||
.simulation-catalog__summary,
|
||||
.simulation-catalog__state,
|
||||
.simulation-catalog__notice,
|
||||
.simulation-catalog__actions,
|
||||
.simulation-project-window__footer-state,
|
||||
.simulation-source-drop > div,
|
||||
.simulation-upload-progress {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.simulation-workspace__head,
|
||||
.simulation-workspace__scene-head {
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 0.25rem 0.2rem;
|
||||
}
|
||||
|
||||
.simulation-workspace__head h2,
|
||||
.simulation-workspace__head p,
|
||||
.simulation-workspace__scene-head h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.simulation-workspace__head h2,
|
||||
.simulation-workspace__scene-head h2 {
|
||||
margin-top: 0.3rem;
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 1.18rem;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
.simulation-workspace__head p {
|
||||
max-width: 46rem;
|
||||
margin-top: 0.38rem;
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.66rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.simulation-workspace__scene-head {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(8rem, auto) minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
.simulation-catalog {
|
||||
position: relative;
|
||||
display: grid;
|
||||
min-height: 0;
|
||||
align-content: start;
|
||||
gap: 0.55rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.simulation-catalog__summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__summary > div {
|
||||
display: grid;
|
||||
gap: 0.28rem;
|
||||
border-radius: 0.85rem;
|
||||
background: rgb(255 255 255 / 0.03);
|
||||
padding: 0.85rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__summary span {
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.58rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table th {
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.52rem;
|
||||
font-weight: 680;
|
||||
letter-spacing: 0.075em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.simulation-catalog__summary strong {
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table-wrap {
|
||||
overflow: auto;
|
||||
border-radius: 1rem;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.simulation-catalog__table {
|
||||
width: 100%;
|
||||
min-width: 52rem;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0 0.34rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table th,
|
||||
.simulation-catalog__table td {
|
||||
padding: 0.72rem 0.8rem;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.simulation-catalog__table th {
|
||||
padding-top: 0.2rem;
|
||||
padding-bottom: 0.18rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table th:first-child,
|
||||
.simulation-catalog__table td:first-child {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table th:last-child,
|
||||
.simulation-catalog__table td:last-child {
|
||||
width: 6.4rem;
|
||||
min-width: 6.4rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table tbody tr {
|
||||
transition: background var(--nodedc-duration-fast) var(--nodedc-ease-standard);
|
||||
}
|
||||
|
||||
.simulation-catalog__table tbody td {
|
||||
background: rgb(255 255 255 / 0.025);
|
||||
transition: background var(--nodedc-duration-fast) var(--nodedc-ease-standard);
|
||||
}
|
||||
|
||||
.simulation-catalog__table tbody tr:hover td {
|
||||
background: rgb(255 255 255 / 0.045);
|
||||
}
|
||||
|
||||
.simulation-catalog__table tbody td:first-child {
|
||||
border-radius: 0.85rem 0 0 0.85rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table tbody td:last-child {
|
||||
border-radius: 0 0.85rem 0.85rem 0;
|
||||
}
|
||||
|
||||
.simulation-catalog__table td {
|
||||
color: var(--nodedc-text-secondary);
|
||||
font-size: 0.64rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table td > small,
|
||||
.simulation-catalog__table td > button small {
|
||||
display: block;
|
||||
margin-top: 0.18rem;
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.54rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__table td:first-child > button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.65rem;
|
||||
min-width: 11rem;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.simulation-catalog__table td:first-child > button > span:last-child {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.simulation-catalog__table td:first-child > button strong {
|
||||
display: block;
|
||||
max-width: 20rem;
|
||||
overflow: clip;
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 0.7rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.simulation-catalog__table td:first-child > button small {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.simulation-catalog__project-icon,
|
||||
.simulation-catalog__empty > span {
|
||||
display: grid;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
flex: 0 0 auto;
|
||||
place-items: center;
|
||||
border-radius: 0.62rem;
|
||||
background: rgb(var(--nodedc-accent-rgb) / 0.07);
|
||||
color: var(--nodedc-text-secondary);
|
||||
}
|
||||
|
||||
.simulation-catalog__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.28rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__progress {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
gap: 0.26rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__progress-meta,
|
||||
.simulation-catalog__progress-stage {
|
||||
overflow: hidden;
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.54rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.simulation-catalog__progress-track {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 0.3rem;
|
||||
border-radius: 999px;
|
||||
background: rgb(255 255 255 / 0.08);
|
||||
}
|
||||
|
||||
.simulation-catalog__progress-track i {
|
||||
position: absolute;
|
||||
inset: 0 auto 0 0;
|
||||
min-width: 0;
|
||||
border-radius: inherit;
|
||||
background: rgb(var(--nodedc-accent-rgb));
|
||||
transition: width var(--nodedc-duration-fast) var(--nodedc-ease-standard);
|
||||
}
|
||||
|
||||
.simulation-catalog__progress[data-indeterminate="true"] .simulation-catalog__progress-track i {
|
||||
width: 28% !important;
|
||||
animation: simulation-progress-pulse 1.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.simulation-catalog__progress-stage {
|
||||
font-size: 0.52rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__state,
|
||||
.simulation-catalog__empty {
|
||||
min-height: 20rem;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
color: var(--nodedc-text-muted);
|
||||
border-radius: 1rem;
|
||||
background: rgb(255 255 255 / 0.025);
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__notice {
|
||||
justify-content: flex-start;
|
||||
gap: 0.55rem;
|
||||
border-radius: 0.85rem;
|
||||
background: rgb(var(--nodedc-danger-rgb) / 0.08);
|
||||
color: var(--nodedc-danger);
|
||||
padding: 0.7rem 0.85rem;
|
||||
font-size: 0.62rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__drop-overlay {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
inset: 0;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
justify-items: center;
|
||||
gap: 0.55rem;
|
||||
border-radius: 1rem;
|
||||
background: var(--nodedc-canvas);
|
||||
color: var(--nodedc-text-muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.simulation-catalog__drop-mark {
|
||||
display: grid;
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
margin-bottom: 0.25rem;
|
||||
place-items: center;
|
||||
border-radius: 50%;
|
||||
background: var(--nodedc-glass-control-active);
|
||||
color: var(--nodedc-glass-control-active-text);
|
||||
}
|
||||
|
||||
.simulation-catalog__drop-overlay strong {
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 0.86rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__drop-overlay span {
|
||||
font-size: 0.64rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__drop-overlay small {
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.56rem;
|
||||
}
|
||||
|
||||
@keyframes simulation-progress-pulse {
|
||||
from { transform: translateX(-105%); }
|
||||
to { transform: translateX(360%); }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.simulation-catalog__progress[data-indeterminate="true"] .simulation-catalog__progress-track i {
|
||||
animation: none;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.simulation-catalog__state > div {
|
||||
display: grid;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.simulation-catalog__state strong,
|
||||
.simulation-catalog__empty strong {
|
||||
color: var(--nodedc-text-primary);
|
||||
}
|
||||
|
||||
.simulation-catalog__empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.simulation-catalog__empty p {
|
||||
max-width: 30rem;
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.simulation-project-window {
|
||||
display: grid;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.simulation-project-window .nodedc-select-anchor,
|
||||
.simulation-project-window .nodedc-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.simulation-source-drop {
|
||||
display: grid;
|
||||
min-height: 12rem;
|
||||
place-items: center;
|
||||
align-content: center;
|
||||
gap: 0.55rem;
|
||||
border: 1px dashed var(--nodedc-glass-outline);
|
||||
border-radius: 0.85rem;
|
||||
background: rgb(255 255 255 / 0.018);
|
||||
color: var(--nodedc-text-muted);
|
||||
text-align: center;
|
||||
transition: border-color var(--nodedc-duration-fast) var(--nodedc-ease-standard),
|
||||
background var(--nodedc-duration-fast) var(--nodedc-ease-standard);
|
||||
}
|
||||
|
||||
.simulation-source-drop[data-dragging="true"] {
|
||||
border-color: rgb(var(--nodedc-accent-rgb) / 0.72);
|
||||
background: rgb(var(--nodedc-accent-rgb) / 0.08);
|
||||
}
|
||||
|
||||
.simulation-source-drop > strong {
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.simulation-source-drop > span {
|
||||
max-width: 30rem;
|
||||
font-size: 0.58rem;
|
||||
}
|
||||
|
||||
.simulation-source-drop > div {
|
||||
gap: 0.45rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.simulation-upload-progress {
|
||||
gap: 0.7rem;
|
||||
border-radius: 0.72rem;
|
||||
background: rgb(255 255 255 / 0.025);
|
||||
padding: 0.7rem;
|
||||
}
|
||||
|
||||
.simulation-upload-progress > span {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-width: 12rem;
|
||||
flex: 1 1 auto;
|
||||
height: 0.28rem;
|
||||
border-radius: 999px;
|
||||
background: rgb(255 255 255 / 0.08);
|
||||
}
|
||||
|
||||
.simulation-upload-progress > span i {
|
||||
position: absolute;
|
||||
inset: 0 auto 0 0;
|
||||
border-radius: inherit;
|
||||
background: rgb(var(--nodedc-accent-rgb));
|
||||
}
|
||||
|
||||
.simulation-upload-progress > div {
|
||||
display: grid;
|
||||
min-width: 9rem;
|
||||
max-width: 13rem;
|
||||
flex: 0 1 13rem;
|
||||
gap: 0.14rem;
|
||||
}
|
||||
|
||||
.simulation-upload-progress strong {
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 0.62rem;
|
||||
}
|
||||
|
||||
.simulation-upload-progress small {
|
||||
overflow: hidden;
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.54rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.simulation-project-window__footer-state {
|
||||
gap: 0.4rem;
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.58rem;
|
||||
}
|
||||
|
||||
.simulation-project-window__error {
|
||||
margin: 0;
|
||||
border-radius: 0.65rem;
|
||||
background: rgb(var(--nodedc-danger-rgb) / 0.08);
|
||||
color: var(--nodedc-danger);
|
||||
padding: 0.65rem 0.75rem;
|
||||
font-size: 0.6rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.simulation-viewport {
|
||||
container-type: inline-size;
|
||||
display: grid;
|
||||
min-height: 0;
|
||||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||
overflow: hidden;
|
||||
border-radius: 1rem;
|
||||
background: #07090d;
|
||||
}
|
||||
|
||||
.simulation-viewport__toolbar {
|
||||
position: sticky;
|
||||
z-index: 10;
|
||||
top: 0;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(12rem, 1fr) auto minmax(12rem, 1fr);
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
border-bottom: 1px solid var(--station-hairline);
|
||||
background: var(--nodedc-glass-panel-bg-soft);
|
||||
padding: 0.55rem 0.65rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__toolbar > div:first-child {
|
||||
display: flex;
|
||||
min-width: 12rem;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__controls {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-anchor {
|
||||
position: relative;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings {
|
||||
position: absolute;
|
||||
z-index: 12;
|
||||
top: calc(100% + 0.65rem);
|
||||
right: 0;
|
||||
display: grid;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
width: min(21rem, calc(100cqw - 1.3rem));
|
||||
max-height: min(44rem, calc(100vh - 7rem));
|
||||
overflow: clip;
|
||||
gap: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-head {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
background: var(--nodedc-glass-panel-bg-strong);
|
||||
padding: 0.8rem;
|
||||
box-shadow: 0 0.55rem 1rem rgb(0 0 0 / 0.18);
|
||||
backdrop-filter: blur(18px);
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-scroll {
|
||||
display: grid;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 0.8rem 0.8rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-head > div,
|
||||
.simulation-viewport__settings-group,
|
||||
.simulation-viewport__settings-switches {
|
||||
display: grid;
|
||||
gap: 0.32rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-head strong {
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings span,
|
||||
.simulation-viewport__settings p {
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.56rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-group {
|
||||
gap: 0.55rem;
|
||||
border-radius: 0.72rem;
|
||||
background: rgb(255 255 255 / 0.035);
|
||||
padding: 0.65rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-group-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-group-head strong {
|
||||
color: var(--nodedc-text-secondary);
|
||||
font-size: 0.62rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-switches {
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-rotations {
|
||||
display: grid;
|
||||
gap: 0.7rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__rotation-row {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__rotation-row > strong {
|
||||
color: var(--nodedc-text-secondary);
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__rotation-fields {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__rotation-field {
|
||||
gap: 0.22rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__rotation-field .nodedc-field__label-row {
|
||||
padding-inline: 0.15rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__rotation-field .nodedc-field__label {
|
||||
font-size: 0.54rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__rotation-input {
|
||||
min-height: 1.75rem;
|
||||
padding: 0.2rem 0.55rem;
|
||||
font-size: 0.64rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.simulation-viewport__rotation-input:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.simulation-viewport__settings-error {
|
||||
border-radius: 0.65rem;
|
||||
background: rgb(var(--nodedc-danger-rgb) / 0.08);
|
||||
color: var(--nodedc-danger) !important;
|
||||
padding: 0.55rem 0.65rem;
|
||||
}
|
||||
|
||||
.simulation-ugv-settings {
|
||||
gap: 0.7rem;
|
||||
}
|
||||
|
||||
.simulation-ugv-settings__subhead {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.65rem;
|
||||
margin-top: 0.1rem;
|
||||
padding-top: 0.55rem;
|
||||
border-top: 1px solid rgb(255 255 255 / 0.055);
|
||||
}
|
||||
|
||||
.simulation-ugv-settings__subhead strong {
|
||||
color: var(--nodedc-text-secondary);
|
||||
font-size: 0.58rem;
|
||||
}
|
||||
|
||||
.simulation-ugv-settings__save {
|
||||
width: 100%;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__toolbar-balance {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.simulation-viewport__toolbar > div:first-child > span:last-child,
|
||||
.simulation-viewport__notice > span:last-child {
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.55rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__stage {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
min-height: 18rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.simulation-viewport__stage canvas {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.simulation-viewport__stage canvas:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.simulation-viewport[data-control-mode="ugv"] .simulation-viewport__stage canvas,
|
||||
.simulation-viewport[data-control-mode="ugv"] .simulation-viewport__stage canvas:active {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.simulation-viewport[data-control-mode="ugv"] .simulation-viewport__stage canvas.is-orbiting,
|
||||
.simulation-viewport[data-control-mode="ugv"] .simulation-viewport__stage canvas.is-orbiting:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.simulation-viewport__stage canvas:focus-visible {
|
||||
box-shadow: inset 0 0 0 2px rgb(var(--nodedc-accent-rgb) / 0.7);
|
||||
}
|
||||
|
||||
.simulation-viewport__state {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
align-content: center;
|
||||
gap: 0.55rem;
|
||||
background: rgb(7 9 13 / 0.84);
|
||||
color: var(--nodedc-text-muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.simulation-viewport__state strong {
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__state p {
|
||||
max-width: 34rem;
|
||||
margin: 0;
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.simulation-viewport__notice {
|
||||
gap: 0.55rem;
|
||||
border-top: 1px solid var(--station-hairline);
|
||||
padding: 0.48rem 0.65rem;
|
||||
}
|
||||
|
||||
@container (max-width: 68rem) {
|
||||
.simulation-viewport__toolbar {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.simulation-viewport__controls {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.simulation-viewport__toolbar-balance {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.simulation-workspace__processing {
|
||||
display: flex;
|
||||
min-height: 18rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.simulation-workspace__processing-copy {
|
||||
display: grid;
|
||||
max-width: 40rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.simulation-workspace__processing-actions {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
.simulation-workspace__processing strong {
|
||||
color: var(--nodedc-text-primary);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.simulation-workspace__processing p {
|
||||
margin: 0;
|
||||
color: var(--nodedc-text-muted);
|
||||
font-size: 0.62rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.simulation-catalog__summary {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.simulation-workspace__scene-head {
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
|
||||
.simulation-workspace__scene-head > .nodedc-button {
|
||||
grid-column: 1 / -1;
|
||||
justify-self: start;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
declare module "playcanvas/scripts/esm/camera-controls.mjs" {
|
||||
import { Script, Vec2, Vec3 } from "playcanvas";
|
||||
|
||||
export class CameraControls extends Script {
|
||||
static scriptName: "cameraControls";
|
||||
enableFly: boolean;
|
||||
enableOrbit: boolean;
|
||||
focusPoint: Vec3;
|
||||
zoomRange: Vec2;
|
||||
focus(focus: Vec3, resetZoom?: boolean): void;
|
||||
look(focus: Vec3, resetZoom?: boolean): void;
|
||||
reset(focus: Vec3, position: Vec3): void;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
GlassSurface,
|
||||
Icon,
|
||||
StatusBadge,
|
||||
} from "@nodedc/ui-react";
|
||||
import { Button, GlassSurface, Icon, StatusBadge } from "@nodedc/ui-react";
|
||||
import {
|
||||
ObservationMedia,
|
||||
ObservationSourcePicker,
|
||||
@@ -41,6 +36,7 @@ import { DatasetGatewayWorkspace } from "./DatasetGatewayWorkspace";
|
||||
import { ArtifactHealthWorkspace } from "./data/ArtifactHealthWorkspace";
|
||||
import { ContourHealthWorkspace } from "./ContourHealthWorkspace";
|
||||
import { LaboratoryArchiveWorkspace } from "./laboratory/LaboratoryArchiveWorkspace";
|
||||
import { SimulationWorkspace } from "./simulation/SimulationWorkspace";
|
||||
import { ComputeModulesWorkspace } from "./system/ComputeModulesWorkspace";
|
||||
import { NetworkWorkspace } from "./system/NetworkWorkspace";
|
||||
import { WorldMapWorkspace } from "./map/WorldMapWorkspace";
|
||||
@@ -1193,6 +1189,8 @@ export function WorkspaceRenderer(props: WorkspaceRendererProps) {
|
||||
SpatialView={SpatialWorkspace}
|
||||
/>
|
||||
);
|
||||
case "simulations":
|
||||
return <SimulationWorkspace />;
|
||||
case "device":
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,14 @@ import { M4ReplayThreatResultView } from "./M4ReplayThreatResult";
|
||||
import { M47ReferenceGraphResultView } from "./M47ReferenceGraphResult";
|
||||
import { M48ObjectCentricQualityResultView } from "./M48ObjectCentricQualityResult";
|
||||
import { M48SmallStaticPassageRegressionResultView } from "./M48SmallStaticPassageRegressionResult";
|
||||
import { M48StaticOccupancyQualificationResultView } from "./M48StaticOccupancyQualificationResult";
|
||||
import { M48R3StaticOccupancyShadowResultView } from "./M48R3StaticOccupancyShadowResult";
|
||||
import { M48SFixedClassDetectorResultView } from "./M48SFixedClassDetectorResult";
|
||||
import { M48TRiskQualityResultView } from "./M48TRiskQualityResult";
|
||||
import { M49TgsFailClosedResultView } from "./M49TgsFailClosedResult";
|
||||
import { M49TgsFullShadowResultView } from "./M49TgsFullShadowResult";
|
||||
import { VegetationShadowResultView } from "./VegetationShadowResult";
|
||||
import { VegetationBenchmarkResultView } from "./VegetationBenchmarkResult";
|
||||
|
||||
export { isAdvancedLaboratoryWorkId };
|
||||
export type { AdvancedLaboratoryWorkId };
|
||||
@@ -87,15 +94,36 @@ export function AdvancedLaboratoryResult({
|
||||
failedSessionId: string | null;
|
||||
replayError: string | null;
|
||||
}) {
|
||||
if (workId === "lab-v1-vegetation-benchmark" && results.vegetationBenchmark) {
|
||||
return <VegetationBenchmarkResultView rigLabel={rigLabel} result={results.vegetationBenchmark} />;
|
||||
}
|
||||
if (workId === "lab-v1-vegetation-shadow" && results.vegetationShadow) {
|
||||
return <VegetationShadowResultView rigLabel={rigLabel} result={results.vegetationShadow} />;
|
||||
}
|
||||
if (workId === "m48-object-centric-quality" && results.m48) {
|
||||
return <M48ObjectCentricQualityResultView rigLabel={rigLabel} result={results.m48} />;
|
||||
}
|
||||
if (workId === "m48-small-static-passage-regression" && results.m48SmallStatic) {
|
||||
return <M48SmallStaticPassageRegressionResultView rigLabel={rigLabel} result={results.m48SmallStatic} />;
|
||||
}
|
||||
if (workId === "m48-static-occupancy-qualification" && results.m48StaticOccupancy) {
|
||||
return <M48StaticOccupancyQualificationResultView rigLabel={rigLabel} result={results.m48StaticOccupancy} />;
|
||||
}
|
||||
if (workId === "m48r3-static-occupancy-shadow" && results.m48r3StaticOccupancy) {
|
||||
return <M48R3StaticOccupancyShadowResultView rigLabel={rigLabel} result={results.m48r3StaticOccupancy} />;
|
||||
}
|
||||
if (workId === "m48s-fixed-class-detector" && results.m48s) {
|
||||
return <M48SFixedClassDetectorResultView rigLabel={rigLabel} result={results.m48s} />;
|
||||
}
|
||||
if (workId === "m48t-risk-quality-temporal" && results.m48t) {
|
||||
return <M48TRiskQualityResultView rigLabel={rigLabel} result={results.m48t} />;
|
||||
}
|
||||
if (workId === "m49-tgs-fail-closed-evidence" && results.m49Tgs) {
|
||||
return <M49TgsFailClosedResultView rigLabel={rigLabel} result={results.m49Tgs} />;
|
||||
}
|
||||
if (workId === "m49-tgs-full-shadow" && results.m49TgsFull) {
|
||||
return <M49TgsFullShadowResultView rigLabel={rigLabel} result={results.m49TgsFull} />;
|
||||
}
|
||||
if (workId === "m47-reference-graph-shadow" && results.m47Graph) {
|
||||
return <M47ReferenceGraphResultView rigLabel={rigLabel} result={results.m47Graph} />;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,119 @@ const ATLAS_MODES = [
|
||||
] as const;
|
||||
type AtlasMode = typeof ATLAS_MODES[number]["value"];
|
||||
|
||||
const MASK_COMPARISON_MODES = [
|
||||
{ value: "source", label: "SOURCE" },
|
||||
{ value: "truth", label: "TRUTH" },
|
||||
{ value: "prediction", label: "PREDICTION" },
|
||||
{ value: "error", label: "ERROR" },
|
||||
] as const;
|
||||
const MASK_COMPARISON_CANDIDATES = [
|
||||
{ value: "ddrnet", label: "DDRNET" },
|
||||
{ value: "ppliteseg", label: "PPLITE" },
|
||||
] as const;
|
||||
type MaskComparisonMode = typeof MASK_COMPARISON_MODES[number]["value"];
|
||||
type MaskComparisonCandidate = typeof MASK_COMPARISON_CANDIDATES[number]["value"];
|
||||
|
||||
export interface M48MaskComparisonCase {
|
||||
caseId: string;
|
||||
title: string;
|
||||
context?: string;
|
||||
sourceUrl: string;
|
||||
truthUrl: string;
|
||||
predictions: Readonly<Record<MaskComparisonCandidate, string>>;
|
||||
errors: Readonly<Record<MaskComparisonCandidate, string>>;
|
||||
}
|
||||
|
||||
function M48MaskComparisonScene({
|
||||
item,
|
||||
mode,
|
||||
candidate,
|
||||
}: {
|
||||
item: M48MaskComparisonCase;
|
||||
mode: MaskComparisonMode;
|
||||
candidate: MaskComparisonCandidate;
|
||||
}) {
|
||||
const overlay = mode === "truth"
|
||||
? item.truthUrl
|
||||
: mode === "prediction"
|
||||
? item.predictions[candidate]
|
||||
: mode === "error"
|
||||
? item.errors[candidate]
|
||||
: null;
|
||||
return (
|
||||
<div className="recorded-evidence-image-scene">
|
||||
<img src={item.sourceUrl} alt="" draggable={false} />
|
||||
{overlay ? <img src={overlay} alt="" draggable={false} /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function M48MaskComparisonVisual({
|
||||
cases,
|
||||
initialCandidate,
|
||||
}: {
|
||||
cases: readonly M48MaskComparisonCase[];
|
||||
initialCandidate: MaskComparisonCandidate;
|
||||
}) {
|
||||
const [index, setIndex] = useState(0);
|
||||
const [mode, setMode] = useState<MaskComparisonMode>("error");
|
||||
const [candidate, setCandidate] = useState<MaskComparisonCandidate>(initialCandidate);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const item = cases[index] ?? null;
|
||||
return (
|
||||
<LaboratoryEvidenceViewer
|
||||
label="M4.8 vegetation truth comparison"
|
||||
className="m48-atlas-visual"
|
||||
mode={mode}
|
||||
modes={MASK_COMPARISON_MODES}
|
||||
secondaryMode={{
|
||||
value: candidate,
|
||||
modes: MASK_COMPARISON_CANDIDATES,
|
||||
label: "Сравниваемая модель",
|
||||
onChange: setCandidate,
|
||||
}}
|
||||
expanded={expanded}
|
||||
onModeChange={setMode}
|
||||
onExpandedChange={setExpanded}
|
||||
chromeLayout="stacked"
|
||||
actions={(
|
||||
<>
|
||||
<IconButton
|
||||
label="Предыдущий vegetation hard case"
|
||||
disabled={!cases.length}
|
||||
onClick={() => setIndex((current) => (current - 1 + cases.length) % cases.length)}
|
||||
>
|
||||
<Icon name="chevron-left" size={16} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
label="Следующий vegetation hard case"
|
||||
disabled={!cases.length}
|
||||
onClick={() => setIndex((current) => (current + 1) % cases.length)}
|
||||
>
|
||||
<Icon name="chevron-right" size={16} />
|
||||
</IconButton>
|
||||
</>
|
||||
)}
|
||||
overlay={item ? (
|
||||
<div className="m48-atlas-visual__case">
|
||||
<StatusBadge tone="accent">GOOSE TRUTH · {index + 1}/{cases.length}</StatusBadge>
|
||||
<strong>{item.title}</strong>
|
||||
{item.context ? <small>{item.context}</small> : null}
|
||||
</div>
|
||||
) : null}
|
||||
>
|
||||
{item ? (
|
||||
<M48MaskComparisonScene item={item} mode={mode} candidate={candidate} />
|
||||
) : (
|
||||
<div className="m48-atlas-visual__state" role="alert">
|
||||
<Icon name="alert" size={18} />
|
||||
Vegetation hard-case каталог пуст.
|
||||
</div>
|
||||
)}
|
||||
</LaboratoryEvidenceViewer>
|
||||
);
|
||||
}
|
||||
|
||||
function message(error: unknown): string {
|
||||
return error instanceof Error && error.message.trim() ? error.message : "M4.8 evidence недоступно.";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Icon } from "@nodedc/ui-react";
|
||||
|
||||
import {
|
||||
fetchM48R3StaticOccupancyCases,
|
||||
type M48R3StaticOccupancyCase,
|
||||
type M48R3StaticOccupancyShadowResult,
|
||||
} from "../../core/laboratory/m48r3StaticOccupancyShadow";
|
||||
import {
|
||||
M4ReplayThreatVisual,
|
||||
type M4ReplayThreatReviewAnchor,
|
||||
} from "./M4ReplayThreatVisual";
|
||||
|
||||
function message(error: unknown): string {
|
||||
return error instanceof Error && error.message.trim()
|
||||
? error.message
|
||||
: "M4.8R3 timeline недоступен.";
|
||||
}
|
||||
|
||||
export function M48R3StaticOccupancyShadowEvidence({
|
||||
result,
|
||||
}: {
|
||||
result: M48R3StaticOccupancyShadowResult;
|
||||
}) {
|
||||
const [cases, setCases] = useState<readonly M48R3StaticOccupancyCase[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
void fetchM48R3StaticOccupancyCases(result.resultId, { signal: controller.signal })
|
||||
.then((nextCases) => {
|
||||
if (!controller.signal.aborted) setCases(nextCases);
|
||||
})
|
||||
.catch((caught: unknown) => {
|
||||
if (!controller.signal.aborted) setError(message(caught));
|
||||
})
|
||||
.finally(() => {
|
||||
if (!controller.signal.aborted) setLoading(false);
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [result.resultId]);
|
||||
|
||||
const reviewAnchors = useMemo<readonly M4ReplayThreatReviewAnchor[]>(() => (
|
||||
cases.map((item) => ({
|
||||
id: item.anchorId,
|
||||
sourceSequence: item.sourceSequence,
|
||||
extentXyxyNormalized: item.extentXyxy,
|
||||
matchedAtThreshold: item.matched,
|
||||
}))
|
||||
), [cases]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="l3-visual-audit__state" role="status">
|
||||
<span className="busy-indicator" aria-hidden="true" />
|
||||
<span>Открываем полный M4.8R3 Worker timeline</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (error) {
|
||||
return (
|
||||
<div className="l3-visual-audit__state" role="alert">
|
||||
<Icon name="alert" size={18} />
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<M4ReplayThreatVisual
|
||||
resultId={result.resultId}
|
||||
reviewAnchors={reviewAnchors}
|
||||
showReviewAnchorBoxes={false}
|
||||
reviewLabel="Контрольные кадры M4.8R3 · без ручных рамок"
|
||||
timelineEndpointRoot="/api/v1/laboratory/m48r3/static-occupancy"
|
||||
evidenceLabel="M4.8R3"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import type { M48R3StaticOccupancyShadowResult } from "../../core/laboratory/m48r3StaticOccupancyShadow";
|
||||
import { M48R3StaticOccupancyShadowEvidence } from "./M48R3StaticOccupancyShadowEvidence";
|
||||
|
||||
function number(value: number, digits = 2): string {
|
||||
return value.toLocaleString("ru-RU", { maximumFractionDigits: digits });
|
||||
}
|
||||
|
||||
function percent(value: number): string {
|
||||
return `${number(value * 100, 1)}%`;
|
||||
}
|
||||
|
||||
export function M48R3StaticOccupancyShadowResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: M48R3StaticOccupancyShadowResult;
|
||||
}) {
|
||||
const candidate = result.metrics.performance.candidate;
|
||||
const occupancy = result.metrics.occupancy;
|
||||
const separation = result.metrics.anchors.separation;
|
||||
const separated = separation.every((item) => item.passed);
|
||||
const status = result.accepted
|
||||
? "Полный Worker shadow принят: realtime и раздельные препятствия сохранены"
|
||||
: "Worker shadow не прошёл один или несколько предобъявленных gate";
|
||||
const separatedLabel = separation.length
|
||||
? separation.map((item) => `${item.observedComponents}/${item.expectedMinimumComponents}`).join(" · ")
|
||||
: "—";
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.8R3 · full Worker static occupancy shadow"
|
||||
description="Полный 4 489-кадровый прогон проверяет additive low-step occupied-only слой внутри штатного graph pipeline. Камера и RF-DETR не получают дополнительного inference; ручные прямоугольники используются только для перехода к контрольным кадрам и не рисуются как системный результат."
|
||||
status={status}
|
||||
statusTone={result.accepted ? "success" : "warning"}
|
||||
facts={[
|
||||
{ label: "Конфигурация", value: `${rigLabel} RIGHT · VIDEO/CAMERA/3D/PLAN · LOW-STEP provenance` },
|
||||
{ label: "Профиль", value: `${result.profile.id} · minimum points ${result.profile.minimumPoints}` },
|
||||
{ label: "Прогон", value: `${result.metrics.frames.candidateDelivered}/${result.metrics.frames.expected} · immutable ${result.resultId}` },
|
||||
{ label: "Нагрузка", value: `12 Hz source-paced · ${number(candidate.fps, 3)} effective FPS · +0 inference` },
|
||||
{ label: "Authority", value: "REPLAY-SIMULATED · production/navigation/actuation OFF" },
|
||||
]}
|
||||
brief={{
|
||||
question: "Можно ли добавить геометрическое обнаружение низких статических препятствий, не разрушив realtime и не склеив отдельные столбики/шары в один объект?",
|
||||
approach: `Кандидат сравнен покадрово с native baseline на всех ${result.metrics.frames.expected} кадрах. Проверены latency, FPS, рост occupancy, capacity drops, отсутствие потерянных baseline-ячеек и отдельные компоненты на кадре 1856.`,
|
||||
principalResult: `${number(candidate.fps, 3)} FPS; world-state p95 ${number(candidate.worldP95Ms, 2)} мс; geometry p95/p99 ${number(candidate.geometryP95Ms, 2)}/${number(candidate.geometryP99Ms, 2)} мс; разделение ${separatedLabel}.`,
|
||||
limitation: "Это воспроизводимый Worker shadow, а не доказательство физической проходимости. Просвет между компонентами сохраняется как геометрия, но допустимость проезда зависит от будущего габарита шасси и отдельного free-space контракта.",
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "deterministic",
|
||||
pipelineId: "m48r3-native-plus-low-step-reference-graph/v1",
|
||||
components: [
|
||||
{ kind: "source", name: "native reference graph baseline", version: "M4.7/M4.8R2", role: "immutable occupied/unknown baseline", identitySha256: null },
|
||||
{ kind: "algorithm", name: "additive low-step occupied-only", version: "v1", role: "CPU geometry; never clearing; no semantic class", identitySha256: result.profile.sha256 },
|
||||
{ kind: "runtime", name: "full source-paced Worker shadow", version: "4 489 frames", role: "predeclared realtime, growth, separation and safety gates", identitySha256: result.resultId.split("-").at(-1) ?? null },
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.8R3 VISUAL EVIDENCE · SYSTEM COMPONENTS"
|
||||
title="Полный timeline; LOW-STEP показывает добавленные системой компоненты, ручные рамки скрыты"
|
||||
kind="recorded-replay"
|
||||
resizable
|
||||
>
|
||||
<M48R3StaticOccupancyShadowEvidence result={result} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Что доказал прогон"
|
||||
status={status}
|
||||
statusTone={result.accepted ? "success" : "warning"}
|
||||
metrics={[
|
||||
{ label: "Realtime", value: `${number(candidate.fps, 3)} FPS`, hint: `p95 ${number(candidate.worldP95Ms, 2)} мс · gate ≥11,5 FPS / ≤60 мс` },
|
||||
{ label: "Geometry", value: `${number(candidate.geometryP95Ms, 2)} / ${number(candidate.geometryP99Ms, 2)} мс`, hint: "p95 / p99 · gates 9 / 16 мс" },
|
||||
{ label: "Occupancy delta", value: `+${occupancy.addedCellTotal.toLocaleString("ru-RU")}`, hint: `${percent(occupancy.meanCellGrowthFraction)} cells · ${percent(occupancy.meanComponentGrowthFraction)} components` },
|
||||
{ label: "Кадр 1856", value: separated ? `раздельно · ${separatedLabel}` : `не принят · ${separatedLabel}`, hint: "два столбика и две полусферы проверяются отдельными component gates" },
|
||||
{ label: "Потери / false free", value: `${occupancy.lostCellTotal} / ${result.metrics.falseFreeCount}`, hint: `capacity drops ${result.metrics.capacityDropCount}` },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: `Система сама добавила ${result.metrics.provider.additiveObservationCount.toLocaleString("ru-RU")} low-step observations на ${result.metrics.provider.framesWithAdditions.toLocaleString("ru-RU")} кадрах, сохранила baseline без потерь и выдержала полный realtime shadow.`,
|
||||
notProved: "Не доказаны физический clearance, planner-authoritative free space, независимые precision/recall и безопасность движения на реальном шасси.",
|
||||
decision: result.accepted
|
||||
? "Worker-кандидат принят в ограниченном replay-shadow контуре. Следующий шаг — отдельное решение о cutover и регрессия на новых сценах; ручная разметка не становится runtime-зависимостью."
|
||||
: "Cutover запрещён. Исправить провалившийся gate и повторить полный immutable shadow без ослабления порогов.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -19,9 +19,24 @@ export function M48SFixedClassDetectorResultView({
|
||||
result: M48SFixedClassDetectorResult;
|
||||
}) {
|
||||
const selected = result.metrics.candidates.find((candidate) => candidate.selected);
|
||||
const load = result.metrics.detectorLoad;
|
||||
const detectorLoad = result.metrics.detectorLoad;
|
||||
const integrated = result.metrics.integratedWorldState;
|
||||
const status = integrated
|
||||
const hardening = result.metrics.runtimeHardening;
|
||||
const loadEnvelope = result.metrics.loadEnvelope;
|
||||
const production = loadEnvelope?.scenarios.find((scenario) => scenario.id === "production-10fps");
|
||||
const reserve = loadEnvelope?.scenarios.find((scenario) => scenario.id === "reserve-12fps");
|
||||
const limit = loadEnvelope?.scenarios.find((scenario) => scenario.id === "limit-15fps");
|
||||
const load = loadEnvelope && production && reserve && limit
|
||||
? { comparison: loadEnvelope, production, reserve, limit }
|
||||
: null;
|
||||
const loadAccepted = load?.comparison.loadEnvelopeAccepted === true;
|
||||
const status = load
|
||||
? loadAccepted
|
||||
? "3 × 10 / 12 / 15 FPS прошли; realtime envelope ≥ 15 FPS принят"
|
||||
: "Capacity ≥ 15 FPS подтверждён; repeatability 10 FPS требует закрытия"
|
||||
: hardening
|
||||
? `После hardening: ${hardening.hardened.deliveredWorldStates.toLocaleString("ru-RU")} из ${hardening.hardened.sourceFramesAdmitted.toLocaleString("ru-RU")} world states доставлены`
|
||||
: integrated
|
||||
? "Полный RF-DETR reference graph выдержал realtime shadow"
|
||||
: "RF-DETR-L выдержал detector-only realtime shadow";
|
||||
return (
|
||||
@@ -29,9 +44,11 @@ export function M48SFixedClassDetectorResultView({
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.8S · fixed-class semantics риск-объектов"
|
||||
description="Сравнение трёх готовых COCO-детекторов на точных кадрах RAVNOVES00, 30-минутная квалификация RF-DETR-L и полный source-paced прогон RF-DETR → geometry → temporal → motion → rolling map → threat на Worker 006. Статические препятствия остаются в геометрическом контуре; классы используются только там, где меняется ожидаемое поведение."
|
||||
description={loadAccepted
|
||||
? "RF-DETR-L встроен в полный source-paced граф RF-DETR → geometry → temporal → motion → rolling map → threat. Холодный video decode вынесен до допуска источника, после чего один immutable проход выполнен по три раза на 10, 12 и 15 FPS. LAB показывает худший результат каждой серии, хвосты decode/pacing и каждый из девяти sealed-прогонов."
|
||||
: "RF-DETR-L встроен в полный source-paced граф RF-DETR → geometry → temporal → motion → rolling map → threat. Исторический immutable проход отдельно измерен на 10, 12 и 15 FPS; незакрытый 10 FPS delivery gate сохранён без постфактум-сдвига thresholds."}
|
||||
status={status}
|
||||
statusTone="success"
|
||||
statusTone={load && !loadAccepted ? "warning" : "success"}
|
||||
facts={[
|
||||
{ label: "Источник", value: `${rigLabel} RIGHT · raw KB4 · ${result.source.evidenceFrameCount} diagnostic frames` },
|
||||
{ label: "Сравнение", value: "YOLOX-S · D-FINE-S · RF-DETR-L · единый threshold 0.50" },
|
||||
@@ -39,12 +56,28 @@ export function M48SFixedClassDetectorResultView({
|
||||
{ label: "Authority", value: "SHADOW ONLY · commands OFF · actuation OFF · production NO" },
|
||||
]}
|
||||
brief={{
|
||||
question: "Можно ли заменить слабую class-семантику YOLOX готовой моделью, не потеряв realtime на предельном Worker с RTX 4090?",
|
||||
approach: `YOLOX-S, D-FINE-S и RF-DETR-L сравнили на одинаковых ${result.source.evidenceFrameCount} raw-KB4 кадрах с порогом 0.50. RF-DETR-L отдельно квалифицировали ${decimal(load.durationSeconds / 60, 0)} минут, затем встроили в полный reference graph без дополнительного inference-прохода.`,
|
||||
principalResult: integrated
|
||||
question: load
|
||||
? "Какой realtime-запас имеет неизменный single-pass RF-DETR graph на Worker 006 и где начинается его вычислительный предел?"
|
||||
: "Можно ли заменить слабую class-семантику YOLOX готовой моделью, не потеряв realtime на предельном Worker с RTX 4090?",
|
||||
approach: loadAccepted
|
||||
? "Один и тот же проход из 4489 кадров прогнали строго последовательно девять раз: по три повтора на 10, 12 и 15 FPS. Bounded prefetch на 64 кадра завершался до source admission; sensor timestamps, модель, providers, очереди и single inference не менялись. Пороги и порядок были записаны заранее."
|
||||
: load
|
||||
? "Один и тот же проход из 4489 кадров прогнали последовательно на 10, 12 и 15 FPS. Sensor timestamps, модель, graph providers, очереди, prewarm и single inference не менялись; менялся только wall-clock pacing. Пороги delivery/FPS/p95 были записаны до запусков."
|
||||
: `YOLOX-S, D-FINE-S и RF-DETR-L сравнили на одинаковых ${result.source.evidenceFrameCount} raw-KB4 кадрах с порогом 0.50. RF-DETR-L отдельно квалифицировали ${decimal(result.metrics.detectorLoad.durationSeconds / 60, 0)} минут, затем встроили в полный reference graph без дополнительного inference-прохода.`,
|
||||
principalResult: loadAccepted && load
|
||||
? `Все девять прогонов прошли integrity и predeclared target gates. Худший результат: 10 FPS — ${load.production.deliveredWorldStates.toLocaleString("ru-RU")}/${load.production.sourceFramesAdmitted.toLocaleString("ru-RU")}, 12 FPS — ${load.reserve.deliveredWorldStates.toLocaleString("ru-RU")}/${load.reserve.sourceFramesAdmitted.toLocaleString("ru-RU")}, 15 FPS — ${load.limit.deliveredWorldStates.toLocaleString("ru-RU")}/${load.limit.sourceFramesAdmitted.toLocaleString("ru-RU")}. Во всех сериях сохранён один inference на кадр.`
|
||||
: load
|
||||
? `12 FPS прошли reserve-gate: ${load.reserve.deliveredWorldStates.toLocaleString("ru-RU")}/${load.reserve.sourceFramesAdmitted.toLocaleString("ru-RU")} доставлено. 15 FPS также прошли: ${load.limit.deliveredWorldStates.toLocaleString("ru-RU")}/${load.limit.sourceFramesAdmitted.toLocaleString("ru-RU")}. Но 10 FPS не добрали заранее заданный delivery ratio: ${load.production.deliveredWorldStates.toLocaleString("ru-RU")}/${load.production.sourceFramesAdmitted.toLocaleString("ru-RU")}.`
|
||||
: hardening
|
||||
? `На одинаковых ${hardening.baseline.sourceFramesAdmitted.toLocaleString("ru-RU")} входных кадрах полный граф увеличил доставку с ${hardening.baseline.deliveredWorldStates.toLocaleString("ru-RU")} до ${hardening.hardened.deliveredWorldStates.toLocaleString("ru-RU")} world states, а число вытесненных кадров снизил с ${hardening.baseline.supersededFrames} до ${hardening.hardened.supersededFrames}. Отдельный ${hardening.startup.validationFrames.toLocaleString("ru-RU")}-кадровый прогон подтвердил prewarm до допуска источника.`
|
||||
: integrated
|
||||
? `Полный граф доставил ${integrated.deliveredWorldStates.toLocaleString("ru-RU")} world states при ${decimal(integrated.effectiveWorldStateFps, 3)} FPS и p95 ${decimal(integrated.worldStateCompletionAgeP95Ms, 3)} ms; ${integrated.supersededFrames} входных кадров штатно вытеснены latest-wins очередью.`
|
||||
: `RF-DETR-L выбран из трёх кандидатов и обработал ${load.sourceFramesConsumed.toLocaleString("ru-RU")} кадров detector-only без замен и ошибок.`,
|
||||
limitation: "Прогон доказывает runtime envelope, а не истинность классов, качество track identity, корректность risk policy или безопасность движения. Production authority и команды отключены.",
|
||||
: `RF-DETR-L выбран из трёх кандидатов и обработал ${detectorLoad.sourceFramesConsumed.toLocaleString("ru-RU")} кадров detector-only без замен и ошибок.`,
|
||||
limitation: loadAccepted
|
||||
? "Runtime repeatability и capacity полного графа закрыты как минимум до 15 FPS. Это не доказывает истинность классов, track/risk truth, collision safety или physical-live поведение; команды и production authority по-прежнему отключены."
|
||||
: load
|
||||
? "Capacity полного графа доказан как минимум до 15 FPS, но исторический production repeatability gate не принят. Истинность классов, collision safety и physical-live не проверялись; команды отключены."
|
||||
: "Прогон доказывает runtime envelope, а не истинность классов, качество track identity, корректность risk policy или безопасность движения. Production authority и команды отключены.",
|
||||
}}
|
||||
method={{
|
||||
completeness: result.method.completeness,
|
||||
@@ -73,28 +106,67 @@ export function M48SFixedClassDetectorResultView({
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title={integrated
|
||||
title={hardening
|
||||
? load
|
||||
? "Что сравнивать: один graph на 10 / 12 / 15 FPS"
|
||||
: "Что сравнивать: один и тот же полный прогон до и после hardening"
|
||||
: integrated
|
||||
? "Что дал прогон: полный world-state graph проходит realtime envelope"
|
||||
: "Что дал прогон: RF-DETR-L проходит detector-only realtime envelope"}
|
||||
status={status}
|
||||
statusTone="success"
|
||||
metrics={integrated ? [
|
||||
statusTone={load && !loadAccepted ? "warning" : "success"}
|
||||
metrics={load ? [
|
||||
{ label: "Effective world-state FPS", value: `${decimal(load.production.effectiveWorldStateFps, 3)} / ${decimal(load.reserve.effectiveWorldStateFps, 3)} / ${decimal(load.limit.effectiveWorldStateFps, 3)}`, hint: "вход 10 / 12 / 15 FPS" },
|
||||
{ label: "Worst delivered / superseded", value: `${load.production.deliveredWorldStates.toLocaleString("ru-RU")}/${load.production.supersededFrames} · ${load.reserve.deliveredWorldStates.toLocaleString("ru-RU")}/${load.reserve.supersededFrames} · ${load.limit.deliveredWorldStates.toLocaleString("ru-RU")}/${load.limit.supersededFrames}`, hint: "минимальная доставка / максимум вытеснений из трёх повторов" },
|
||||
{ label: "World-state p95", value: `${decimal(load.production.worldStateCompletionAgeP95Ms, 3)} / ${decimal(load.reserve.worldStateCompletionAgeP95Ms, 3)} / ${decimal(load.limit.worldStateCompletionAgeP95Ms, 3)} ms`, hint: "10 / 12 / 15 FPS" },
|
||||
{ label: "World-state p99", value: `${decimal(load.production.worldStateCompletionAgeP99Ms, 3)} / ${decimal(load.reserve.worldStateCompletionAgeP99Ms, 3)} / ${decimal(load.limit.worldStateCompletionAgeP99Ms, 3)} ms`, hint: "хвост не растёт вместе с rate" },
|
||||
{ label: loadAccepted ? "Hot-loop decode p95" : "Decode p95", value: `${decimal(load.production.hotLoopDecodeP95Ms, 3)} / ${decimal(load.reserve.hotLoopDecodeP95Ms, 3)} / ${decimal(load.limit.hotLoopDecodeP95Ms, 3)} ms`, hint: loadAccepted ? "холодный open/decode исключён из realtime" : "исторический decode включает cold tail" },
|
||||
loadAccepted
|
||||
? { label: "Prefetch / pacing max", value: `${decimal(Math.max(...load.comparison.scenarios.map((scenario) => scenario.sourcePrefetchPreparationMaximumMs)) / 1000, 2)} s / ${decimal(Math.max(...load.comparison.scenarios.map((scenario) => scenario.sourcePacingLatenessMaximumMs)), 3)} ms`, hint: "prefetch до admission / wall-clock pacing в hot loop" }
|
||||
: { label: "Decode maximum", value: `${decimal(load.production.hotLoopDecodeMaximumMs, 0)} / ${decimal(load.reserve.hotLoopDecodeMaximumMs, 0)} / ${decimal(load.limit.hotLoopDecodeMaximumMs, 0)} ms`, hint: "редкий cold source/decode tail" },
|
||||
{ label: "Detector p95", value: `${decimal(load.production.detectorP95Ms, 3)} / ${decimal(load.reserve.detectorP95Ms, 3)} / ${decimal(load.limit.detectorP95Ms, 3)} ms`, hint: "тот же RF-DETR · один inference" },
|
||||
{ label: "GPU mean", value: `${decimal(load.production.gpuUtilizationMeanPercent)}% / ${decimal(load.reserve.gpuUtilizationMeanPercent)}% / ${decimal(load.limit.gpuUtilizationMeanPercent)}%`, hint: "10 / 12 / 15 FPS · насыщения нет" },
|
||||
{ label: "VRAM / process RAM peak", value: `${decimal(Math.max(...load.comparison.scenarios.map((scenario) => scenario.gpuMemoryMaximumMib)) / 1024, 2)} / ${decimal(Math.max(...load.comparison.scenarios.map((scenario) => scenario.processPeakRssMib)) / 1024, 2)} GiB`, hint: "общий GPU counter / graph process RSS" },
|
||||
] : hardening ? [
|
||||
{ label: "World-state FPS", value: `${decimal(hardening.baseline.effectiveWorldStateFps, 3)} → ${decimal(hardening.hardened.effectiveWorldStateFps, 3)}`, hint: "до → после · target ≥ 9.5 FPS" },
|
||||
{ label: "Задержка p95", value: `${decimal(hardening.baseline.worldStateCompletionAgeP95Ms, 3)} → ${decimal(hardening.hardened.worldStateCompletionAgeP95Ms, 3)} ms`, hint: `p99 ${decimal(hardening.baseline.worldStateCompletionAgeP99Ms, 3)} → ${decimal(hardening.hardened.worldStateCompletionAgeP99Ms, 3)} ms` },
|
||||
{ label: "Максимальная задержка", value: `${decimal(hardening.baseline.worldStateCompletionAgeMaximumMs, 3)} → ${decimal(hardening.hardened.worldStateCompletionAgeMaximumMs, 3)} ms`, hint: "полный прогон без prewarm" },
|
||||
{ label: "Доставлено / вытеснено", value: `${hardening.baseline.deliveredWorldStates.toLocaleString("ru-RU")}/${hardening.baseline.supersededFrames} → ${hardening.hardened.deliveredWorldStates.toLocaleString("ru-RU")}/${hardening.hardened.supersededFrames}`, hint: `${hardening.hardened.sourceFramesAdmitted.toLocaleString("ru-RU")} одинаковых входных кадров` },
|
||||
{ label: "Rolling max", value: `${decimal(hardening.baseline.rollingMaximumMs, 3)} → ${decimal(hardening.hardened.rollingMaximumMs, 3)} ms`, hint: "убран длинный стоп realtime-контура" },
|
||||
{ label: "Geometry max", value: `${decimal(hardening.baseline.geometryMaximumMs, 3)} → ${decimal(hardening.hardened.geometryMaximumMs, 3)} ms`, hint: "тот же полный source-paced прогон" },
|
||||
{ label: "Первый detector frame", value: `${decimal(hardening.startup.baseline.detectorMs, 3)} → ${decimal(hardening.startup.prewarmed.detectorMs, 3)} ms`, hint: `prewarm ${decimal(hardening.startup.prewarmDurationMs, 3)} ms до допуска source` },
|
||||
{ label: "Первый world state", value: `${decimal(hardening.startup.baseline.worldStateMs, 3)} → ${decimal(hardening.startup.prewarmed.worldStateMs, 3)} ms`, hint: `${hardening.startup.validationFrames.toLocaleString("ru-RU")} кадров · ${hardening.startup.prewarmInferencePasses} warmup inference` },
|
||||
] : integrated ? [
|
||||
{ label: "Complete graph", value: `${decimal(integrated.effectiveWorldStateFps, 3)} FPS`, hint: "target ≥ 9.5 FPS · source-paced" },
|
||||
{ label: "World-state age p95", value: `${decimal(integrated.worldStateCompletionAgeP95Ms, 3)} ms`, hint: `p99 ${decimal(integrated.worldStateCompletionAgeP99Ms, 3)} ms · target ≤ 175 ms` },
|
||||
{ label: "Delivered / superseded", value: `${integrated.deliveredWorldStates.toLocaleString("ru-RU")} / ${integrated.supersededFrames}`, hint: `${integrated.failures} failures · queues ${Math.max(...Object.values(integrated.queueHighWatermarks))}/${integrated.queueCapacity}` },
|
||||
{ label: "GPU / VRAM peak", value: `${decimal(integrated.gpuUtilizationMaximumPercent, 0)}% / ${decimal(integrated.gpuMemoryMaximumMib / 1024)} GiB`, hint: `GPU mean ${decimal(integrated.gpuUtilizationMeanPercent)}% · ${decimal(integrated.gpuPowerMaximumW)} W` },
|
||||
] : [
|
||||
{ label: "Detector capacity", value: `${decimal(selected?.capacityFps ?? 0)} FPS`, hint: "RF-DETR-L TensorRT/Triton" },
|
||||
{ label: "Completion age p95", value: `${decimal(load.completionAgeP95Ms)} ms`, hint: "detector-only · target ≤ 175 ms" },
|
||||
{ label: "Consumed / replaced", value: `${load.sourceFramesConsumed.toLocaleString("ru-RU")} / ${load.sourceFrameReplacements}`, hint: `${decimal(load.effectiveConsumedFps, 3)} source FPS · ${load.failures} failures` },
|
||||
{ label: "GPU / VRAM peak", value: `${decimal(load.gpuUtilizationMaximumPercent, 0)}% / ${decimal(load.gpuMemoryMaximumMib / 1024)} GiB`, hint: `GPU mean ${decimal(load.gpuUtilizationMeanPercent)}% · queue ${load.queueMaximumDepth}/${load.queueCapacity}` },
|
||||
{ label: "Completion age p95", value: `${decimal(detectorLoad.completionAgeP95Ms)} ms`, hint: "detector-only · target ≤ 175 ms" },
|
||||
{ label: "Consumed / replaced", value: `${detectorLoad.sourceFramesConsumed.toLocaleString("ru-RU")} / ${detectorLoad.sourceFrameReplacements}`, hint: `${decimal(detectorLoad.effectiveConsumedFps, 3)} source FPS · ${detectorLoad.failures} failures` },
|
||||
{ label: "GPU / VRAM peak", value: `${decimal(detectorLoad.gpuUtilizationMaximumPercent, 0)}% / ${decimal(detectorLoad.gpuMemoryMaximumMib / 1024)} GiB`, hint: `GPU mean ${decimal(detectorLoad.gpuUtilizationMeanPercent)}% · queue ${detectorLoad.queueMaximumDepth}/${detectorLoad.queueCapacity}` },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: integrated
|
||||
proved: load
|
||||
? `Все ${load.comparison.repeatCountPerRate * load.comparison.scenarios.length} полных single-pass прогона сохранили bounded queues 2/2, нулевые failed/stale/rejected/unavailable и нулевые дополнительные inference-проходы. Худший 10 FPS delivery — ${(load.production.deliveryRatio * 100).toLocaleString("ru-RU", { maximumFractionDigits: 3 })}%, 12 FPS — ${(load.reserve.deliveryRatio * 100).toLocaleString("ru-RU", { maximumFractionDigits: 3 })}%, 15 FPS — ${(load.limit.deliveryRatio * 100).toLocaleString("ru-RU", { maximumFractionDigits: 3 })}%. Realtime capacity доказана как минимум до 15 FPS без более мощного Worker.`
|
||||
: hardening
|
||||
? `На полном сравнительном прогоне с ${hardening.hardened.sourceFramesAdmitted.toLocaleString("ru-RU")} одинаковыми входными кадрами hardening сохранил realtime FPS, доставил на ${(hardening.hardened.deliveredWorldStates - hardening.baseline.deliveredWorldStates).toLocaleString("ru-RU")} world states больше и сократил вытеснения ${hardening.baseline.supersededFrames} → ${hardening.hardened.supersededFrames}. Максимальный стоп rolling stage уменьшился ${decimal(hardening.baseline.rollingMaximumMs, 3)} → ${decimal(hardening.hardened.rollingMaximumMs, 3)} ms. Отдельный prewarm-прогон снизил первый detector frame ${decimal(hardening.startup.baseline.detectorMs, 3)} → ${decimal(hardening.startup.prewarmed.detectorMs, 3)} ms и первый world state ${decimal(hardening.startup.baseline.worldStateMs, 3)} → ${decimal(hardening.startup.prewarmed.worldStateMs, 3)} ms без дополнительного inference на кадрах.`
|
||||
: integrated
|
||||
? `На Worker 006 полный граф обработал ${integrated.sourceFramesAdmitted.toLocaleString("ru-RU")} входных кадров, доставил ${integrated.deliveredWorldStates.toLocaleString("ru-RU")} состояний без ошибок, удержал все очереди в пределах ${integrated.queueCapacity} и p95 ${decimal(integrated.worldStateCompletionAgeP95Ms, 3)} ms. Advisory сформировал публикации по семействам: geometry-only (${integrated.advisoryFamilyCounts["generic-obstacle"].toLocaleString("ru-RU")}), люди (${integrated.advisoryFamilyCounts.person.toLocaleString("ru-RU")}), животные (${integrated.advisoryFamilyCounts.animal.toLocaleString("ru-RU")}) и транспорт (${integrated.advisoryFamilyCounts.vehicle.toLocaleString("ru-RU")}); это не количество уникальных физических объектов и не потребовало второго inference.`
|
||||
: `RF-DETR-L ${decimal(load.durationSeconds / 60, 0)} минут устойчиво потреблял source-paced поток около 10 FPS: ${load.sourceFramesConsumed.toLocaleString("ru-RU")} кадров, 0 замен, 0 ошибок, completion-age p95 ${decimal(load.completionAgeP95Ms, 3)} ms.`,
|
||||
notProved: "Не доказаны unbiased precision/recall классов, независимое качество track identity и risk policy, поведение planner или collision safety. Кадровые рамки не заменяют геометрическую occupancy-карту.",
|
||||
decision: "Сохранить RF-DETR-L как risk-semantic shadow provider полного reference graph. Не классифицировать миллионы статических форм: неизвестное неподвижное препятствие остаётся geometry-owned и объезжается; классы сохраняются для людей, животных и транспорта. Production switch не разрешён.",
|
||||
: `RF-DETR-L ${decimal(detectorLoad.durationSeconds / 60, 0)} минут устойчиво потреблял source-paced поток около 10 FPS: ${detectorLoad.sourceFramesConsumed.toLocaleString("ru-RU")} кадров, 0 замен, 0 ошибок, completion-age p95 ${decimal(detectorLoad.completionAgeP95Ms, 3)} ms.`,
|
||||
notProved: loadAccepted
|
||||
? "Не доказаны unbiased precision/recall классов, независимая истинность track identity и risk policy, работа planner, collision safety или physical-live режим. Принятый runtime envelope не включает production/navigation authority."
|
||||
: load
|
||||
? `Не закрыта repeatability delivery на production-rate: 10 FPS дали ${(load.production.deliveryRatio * 100).toLocaleString("ru-RU", { maximumFractionDigits: 3 })}% при gate ${(load.production.thresholds.minimumDeliveryRatio * 100).toLocaleString("ru-RU", { maximumFractionDigits: 1 })}%. Исторический v1 результат сохранён; он не переинтерпретируется после появления v2.`
|
||||
: "Не доказаны unbiased precision/recall классов, независимое качество track identity и risk policy, поведение planner или collision safety. Кадровые рамки не заменяют геометрическую occupancy-карту.",
|
||||
decision: loadAccepted
|
||||
? "Сохранить bounded 64-frame prefetch до source admission как runtime baseline. Не усиливать GPU и не добавлять второй детектор: Worker 006 уже держит как минимум 15 FPS. Следующий этап — semantic/track/risk truth и physical-live shadow; production switch не разрешён."
|
||||
: load
|
||||
? "Историческое решение v1: не усиливать GPU и не добавлять второй детектор; изолировать cold video decode и повторить sealed 10/12/15 FPS серией прогонов. Результат v2 закрывает этот следующий этап отдельно, не переписывая v1."
|
||||
: hardening
|
||||
? "Сохранить разгрузку cyclic GC и обязательный detector prewarm как текущий runtime baseline. Следующий этап — измерять запас realtime при росте сцены и числа семантических объектов, не добавляя второй детектор и не расширяя inference-нагрузку. Production switch не разрешён."
|
||||
: "Сохранить RF-DETR-L как risk-semantic shadow provider полного reference graph. Не классифицировать миллионы статических форм: неизвестное неподвижное препятствие остаётся geometry-owned и объезжается; классы сохраняются для людей, животных и транспорта. Production switch не разрешён.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Icon } from "@nodedc/ui-react";
|
||||
|
||||
import { fetchM47ReferenceGraphLab, type M47ReferenceGraphLabResult } from "../../core/laboratory/m47ReferenceGraph";
|
||||
import {
|
||||
fetchM48StaticOccupancyCases,
|
||||
type M48StaticOccupancyCase,
|
||||
type M48StaticOccupancyQualificationResult,
|
||||
} from "../../core/laboratory/m48StaticOccupancyQualification";
|
||||
import {
|
||||
M4ReplayThreatVisual,
|
||||
type M4ReplayThreatReviewAnchor,
|
||||
} from "./M4ReplayThreatVisual";
|
||||
|
||||
function message(error: unknown): string {
|
||||
return error instanceof Error && error.message.trim()
|
||||
? error.message
|
||||
: "Каноническое graph evidence M4.8R2 недоступно.";
|
||||
}
|
||||
|
||||
export function M48StaticOccupancyQualificationEvidence({
|
||||
result,
|
||||
}: {
|
||||
result: M48StaticOccupancyQualificationResult;
|
||||
}) {
|
||||
const [graph, setGraph] = useState<M47ReferenceGraphLabResult | null>(null);
|
||||
const [cases, setCases] = useState<readonly M48StaticOccupancyCase[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
void Promise.all([
|
||||
fetchM47ReferenceGraphLab({
|
||||
resultId: result.referenceGraphLabResultId,
|
||||
signal: controller.signal,
|
||||
}),
|
||||
fetchM48StaticOccupancyCases(result.resultId, { signal: controller.signal }),
|
||||
])
|
||||
.then(([nextGraph, nextCases]) => {
|
||||
if (controller.signal.aborted) return;
|
||||
if (nextCases.some((item) => item.sequence < 1 || item.sequence > nextGraph.frames.expected)) {
|
||||
throw new Error("M4.8R2 anchor вышел за immutable timeline Canonical Reference Graph.");
|
||||
}
|
||||
setGraph(nextGraph);
|
||||
setCases(nextCases);
|
||||
})
|
||||
.catch((caught: unknown) => {
|
||||
if (!controller.signal.aborted) setError(message(caught));
|
||||
})
|
||||
.finally(() => {
|
||||
if (!controller.signal.aborted) setLoading(false);
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [result.referenceGraphLabResultId, result.resultId]);
|
||||
|
||||
const reviewAnchors = useMemo<readonly M4ReplayThreatReviewAnchor[]>(() => (
|
||||
cases.map((item) => ({
|
||||
id: item.anchorId,
|
||||
sourceSequence: item.sequence - 1,
|
||||
extentXyxyNormalized: item.extentXyxy,
|
||||
matchedAtThreshold: item.candidateQualified,
|
||||
}))
|
||||
), [cases]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="l3-visual-audit__state" role="status">
|
||||
<span className="busy-indicator" aria-hidden="true" />
|
||||
<span>Открываем M4.7 graph и M4.8R2 static anchors</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (error || !graph) {
|
||||
return (
|
||||
<div className="l3-visual-audit__state" role="alert">
|
||||
<Icon name="alert" size={18} />
|
||||
<span>{error ?? "Canonical Reference Graph не связан с M4.8R2."}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<M4ReplayThreatVisual
|
||||
resultId={graph.visual.resultId}
|
||||
semantic={{ resultId: graph.semantic.resultId, taxonomy: graph.semantic.taxonomy }}
|
||||
reviewAnchors={reviewAnchors}
|
||||
/>
|
||||
);
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import type { M48StaticOccupancyQualificationResult } from "../../core/laboratory/m48StaticOccupancyQualification";
|
||||
import { M48StaticOccupancyQualificationEvidence } from "./M48StaticOccupancyQualificationEvidence";
|
||||
|
||||
function percent(value: number): string {
|
||||
return `${(value * 100).toLocaleString("ru-RU", { maximumFractionDigits: 1 })}%`;
|
||||
}
|
||||
|
||||
export function M48StaticOccupancyQualificationResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: M48StaticOccupancyQualificationResult;
|
||||
}) {
|
||||
const nearReady = result.decision.criticalNearCandidateReadyForShadow;
|
||||
const status = nearReady
|
||||
? "0–8 м: кандидат закрыл все assisted-якоря; готов к Worker shadow"
|
||||
: "0–8 м: статическая occupancy ещё не закрыта";
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.8R2 · консервативная static occupancy"
|
||||
description="RF-DETR не изменяется. Отдельный детерминированный прогон проверяет, удерживает ли current/rolling LiDAR низкие полусферы, столбы и другие безымянные ограничения, и оценивает уже вычисляемый CPU-признак low-step как additive occupied-only слой."
|
||||
status={status}
|
||||
statusTone={nearReady ? "success" : "warning"}
|
||||
facts={[
|
||||
{ label: "Конфигурация", value: `${rigLabel} RIGHT · Canonical Reference Graph · VIDEO/CAMERA/3D/PLAN/SEMANTICS` },
|
||||
{ label: "Пайплайн", value: result.pipelineId },
|
||||
{ label: "Прогон", value: `${result.runLabel} · immutable ${result.resultId}` },
|
||||
{ label: "Нагрузка", value: "CPU-only geometry · 0 дополнительных detector inference" },
|
||||
{ label: "Authority", value: "REPLAY-SIMULATED · free-space/commands/actuation OFF" },
|
||||
]}
|
||||
brief={{
|
||||
question: "Не превратятся ли близкие полусферы, столбы и другие статические ограничения в пропуск только потому, что камера не знает их название?",
|
||||
approach: `На ${result.metrics.operatorStaticAnchorCount} существующих operator-assisted static anchors принятую current/rolling occupancy сравнили с additive low-step evidence. Отдельно сохранены четыре канонических hemisphere-якоря кадров 1880/2584.`,
|
||||
principalResult: `Принятый граф покрывает ${result.metrics.baselineQualifiedCount}/${result.metrics.operatorStaticAnchorCount}; additive кандидат — ${result.metrics.candidateQualifiedCount}/${result.metrics.operatorStaticAnchorCount}. В критической зоне 0–8 м: ${percent(result.metrics.criticalNearCandidateRecall)}.`,
|
||||
limitation: "Это assisted diagnostic, а не independent truth. Кандидат пока не включён в Worker и может увеличить ложную занятость; требуются полный shadow-прогон, FPS и occupancy-volume gate.",
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "deterministic",
|
||||
pipelineId: result.pipelineId,
|
||||
components: [
|
||||
{ kind: "source", name: result.referenceGraphLabResultId, version: "accepted M4.7", role: "immutable current/rolling occupied/unknown + threat graph", identitySha256: result.referenceGraphLabResultId.split("-").at(-1) ?? null },
|
||||
{ kind: "source", name: result.smallStaticResultId, version: "M4.8R1 assisted seed", role: "static avoidance anchors · not independent truth", identitySha256: result.smallStaticResultId.split("-").at(-1) ?? null },
|
||||
{ kind: "algorithm", name: "low-step occupied-only candidate", version: "v1", role: "additive CPU geometry; never clearing", identitySha256: result.resultId.split("-").at(-1) ?? null },
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence eyebrow="M4.8R2 VISUAL EVIDENCE · CANONICAL REFERENCE GRAPH" title="Те же CAMERA/3D/PLAN, 11 static anchors и неизменённый M4.7 timeline" kind="recorded-replay" resizable>
|
||||
<M48StaticOccupancyQualificationEvidence result={result} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Что дал прогон: локализован лёгкий геометрический слой для близких препятствий"
|
||||
status={status}
|
||||
statusTone={nearReady ? "success" : "warning"}
|
||||
metrics={[
|
||||
{ label: "Current graph", value: `${result.metrics.baselineQualifiedCount}/${result.metrics.operatorStaticAnchorCount}`, hint: `${percent(result.metrics.criticalNearBaselineRecall)} в 0–8 м` },
|
||||
{ label: "+ low-step candidate", value: `${result.metrics.candidateQualifiedCount}/${result.metrics.operatorStaticAnchorCount}`, hint: `${percent(result.metrics.criticalNearCandidateRecall)} в 0–8 м` },
|
||||
{ label: "8–12 м", value: percent(result.metrics.approachCandidateRecall), hint: `${result.metrics.approachAnchorCount} assisted anchors · ещё не gate` },
|
||||
{ label: "False free", value: result.metrics.falseFreeCount.toLocaleString("ru-RU"), hint: `${result.metrics.canonicalEngineeringAnchorCount}/${result.metrics.canonicalEngineeringAnchorCount} canonical anchors retained` },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: `На замороженном assisted seed additive low-step evidence поднял покрытие близких static anchors до ${percent(result.metrics.criticalNearCandidateRecall)} без дополнительной нейросети и без единого free-space утверждения.`,
|
||||
notProved: "Не доказаны independent precision/recall, приемлемый рост консервативной occupancy, realtime Worker FPS после интеграции, физический clearance и collision safety.",
|
||||
decision: nearReady
|
||||
? "Интегрировать low-step только как occupied/unknown Worker shadow. Затем прогнать все 4 489 кадров и принять по FPS, росту компонентов, отсутствию capacity drops и повторному static-anchor gate."
|
||||
: "Не интегрировать в Worker до исправления близких пропусков.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import type {
|
||||
M48QNativeRiskQualityResult,
|
||||
M48TLegacyRiskQualityResult,
|
||||
M48TRiskQualityResult,
|
||||
} from "../../core/laboratory/m48tRiskQuality";
|
||||
import { M48TRiskQualityVisual } from "./M48TRiskQualityVisual";
|
||||
|
||||
function percent(value: number, digits = 1): string {
|
||||
return `${(value * 100).toLocaleString("ru-RU", { maximumFractionDigits: digits })}%`;
|
||||
}
|
||||
|
||||
function decimal(value: number, digits = 1): string {
|
||||
return value.toLocaleString("ru-RU", { maximumFractionDigits: digits });
|
||||
}
|
||||
|
||||
export function M48TRiskQualityResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: M48TRiskQualityResult;
|
||||
}) {
|
||||
if (result.variant === "native-risk-review") {
|
||||
return <M48QNativeRiskQualityResultView rigLabel={rigLabel} result={result} />;
|
||||
}
|
||||
return <M48TLegacyRiskQualityResultView rigLabel={rigLabel} result={result} />;
|
||||
}
|
||||
|
||||
function M48TLegacyRiskQualityResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: M48TLegacyRiskQualityResult;
|
||||
}) {
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.8T · semantic quality + temporal identity"
|
||||
description="RF-DETR-L проверен на полном независимом COCO val2017 по заранее записанным risk-family гейтам. Отдельно тот же advisory-класс стабилизирован на geometry-owned ID полного RAVNOVES00 replay; семантика не участвует в association или occupancy."
|
||||
status="Quality gate failed · temporal invariant passed"
|
||||
statusTone="warning"
|
||||
facts={[
|
||||
{ label: "Quality truth", value: `COCO val2017 · ${result.source.quality.truthInstances.toLocaleString("ru-RU")} risk instances` },
|
||||
{ label: "Candidate", value: `${result.candidate.modelId} · threshold ${decimal(result.candidate.minimumScore, 2)}` },
|
||||
{ label: "Temporal source", value: `${rigLabel} · ${result.source.temporal.frames.toLocaleString("ru-RU")} world states` },
|
||||
{ label: "Authority", value: "SHADOW ONLY · geometry-owned occupancy · production NO" },
|
||||
]}
|
||||
brief={{
|
||||
question: "Достаточно ли качественна текущая risk-семантика RF-DETR и можно ли убрать кадровое мерцание класса без влияния на геометрию?",
|
||||
approach: `Все ${result.source.quality.riskImages.toLocaleString("ru-RU")} COCO-изображений с risk-классами оценены при неизменном score ${decimal(result.candidate.minimumScore, 2)}. Затем bounded history 5 / confirm 2 / switch 3 применена только к advisory-классу уже существующих component ID.`,
|
||||
principalResult: `Recall прошёл: ${percent(result.quality.microRecall)} overall и ${percent(result.quality.mediumLargeRecall)} medium+large. Precision ${percent(result.quality.microPrecision)} и vehicle recall ${percent(result.quality.families.vehicle)} не прошли гейты. Temporal shadow сократил class switches ${result.temporal.rawClassSwitches} → ${result.temporal.stableClassSwitches} и family switches ${result.temporal.rawFamilySwitches} → ${result.temporal.stableFamilySwitches}.`,
|
||||
limitation: "COCO не является truth городского маршрута RAVNOVES00, а temporal replay не имеет независимой track/class truth. Batch timing не принимается как realtime-гейт.",
|
||||
}}
|
||||
method={result.method}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.8T VISUAL EVIDENCE · INDEPENDENT COCO TRUTH"
|
||||
title="16 hash-bound review cases: human truth против RF-DETR"
|
||||
kind="diagnostic-model"
|
||||
resizable
|
||||
>
|
||||
<M48TRiskQualityVisual result={result} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Temporal anti-flicker принят как инвариант; detector quality не принят"
|
||||
status="2/10 predeclared quality checks failed"
|
||||
statusTone="warning"
|
||||
metrics={[
|
||||
{ label: "Precision / recall", value: `${percent(result.quality.microPrecision)} / ${percent(result.quality.microRecall)}`, hint: "gates ≥ 80% / ≥ 75%" },
|
||||
{ label: "Vehicle family", value: percent(result.quality.families.vehicle), hint: "gate ≥ 85% · failed" },
|
||||
{ label: "TP / FP / FN", value: `${result.counts.truePositive.toLocaleString("ru-RU")} / ${result.counts.falsePositive.toLocaleString("ru-RU")} / ${result.counts.falseNegative.toLocaleString("ru-RU")}`, hint: `${result.counts.predictions.toLocaleString("ru-RU")} predictions` },
|
||||
{ label: "Class / family switches", value: `${result.temporal.rawClassSwitches}→${result.temporal.stableClassSwitches} / ${result.temporal.rawFamilySwitches}→${result.temporal.stableFamilySwitches}`, hint: `peak active ${result.temporal.peakActiveComponents}/${result.temporal.maximumActiveComponents}` },
|
||||
{ label: "Batch throughput", value: `${decimal(result.execution.effectiveImagesPerSecond, 2)} image/s`, hint: `image p95 ${decimal(result.execution.imageP95Ms, 2)} ms · non-admission` },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: `На независимой COCO truth текущий RF-DETR сохраняет высокий recall: ${percent(result.quality.microRecall)} overall и ${percent(result.quality.mediumLargeRecall)} medium+large. Bounded temporal state подавил или отложил ${result.temporal.suppressedClassSwitches} class-switch и ${result.temporal.suppressedFamilySwitches} family-switch, сохранив association и occupancy class-independent; active state ${result.temporal.peakActiveComponents}/${result.temporal.maximumActiveComponents}, eviction 0.`,
|
||||
notProved: `Semantic candidate не принят: precision ${percent(result.quality.microPrecision)} при gate 80%, vehicle recall ${percent(result.quality.families.vehicle)} при gate 85%. Не доказаны RAVNOVES class truth, physical track identity, child/adult, unknown moving hazards, risk policy и realtime admission этой batch-командой.`,
|
||||
decision: "Не менять зафиксированные гейты и не добавлять второй detector. RF-DETR остаётся shadow-кандидатом; temporal stabilizer допустим только как advisory-слой поверх geometry-owned ID.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function M48QNativeRiskQualityResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: M48QNativeRiskQualityResult;
|
||||
}) {
|
||||
const classes = Object.entries(result.selection.classCounts)
|
||||
.map(([name, count]) => `${name} ${count}`)
|
||||
.join(" · ");
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.8Q · native raw-fisheye risk review"
|
||||
description="Нативный RF-DETR прогнан внутри полного reference graph прямо на исходном KB4 raster 800×600: без rectification, warp, resize и обратного преобразования. Из immutable frame ledger детерминированно отобраны реальные risk-кейсы для операторской проверки в существующем M4.8 image-case instrument."
|
||||
status="Runtime принят · 24 native cases готовы · quality ещё не adjudicated"
|
||||
statusTone="success"
|
||||
facts={[
|
||||
{ label: "Source", value: `${rigLabel} · ${result.source.frameCount.toLocaleString("ru-RU")} raw frames · 800×600` },
|
||||
{ label: "Candidate", value: `${result.candidate.modelId} · score ≥ ${decimal(result.candidate.minimumScore, 2)}` },
|
||||
{ label: "Image path", value: "RAW KB4 → fused GPU graph · geometric resampling NO" },
|
||||
{ label: "Authority", value: "SHADOW ONLY · independent quality NO · production NO" },
|
||||
]}
|
||||
brief={{
|
||||
question: "Работает ли нативная risk-классификация на нашей исходной fisheye-картинке в realtime envelope, и какие реальные кадры надо проверить человеком?",
|
||||
approach: `Полный ${result.source.frameCount.toLocaleString("ru-RU")}-кадровый native graph оставлен неизменным. Повторной инференс-сессии для лабы нет: 24 кадра выбраны из его hash-bound ledger по person, animal, light-road-user, vehicle, low-confidence, fisheye-edge и расхождениям с диагностической legacy 704 веткой.`,
|
||||
principalResult: `${decimal(result.execution.effectiveWorldStateFps, 3)} FPS при detector p95 ${decimal(result.execution.detectorTotalP95Ms, 2)} ms и world-state p95 ${decimal(result.execution.worldStateCompletionP95Ms, 2)} ms. В review pack реально попали ${classes}.`,
|
||||
limitation: "Это диагностическая выборка маршрута без независимой разметки. Наличие бокса и класса можно осмотреть, но precision/recall и корректность каждого класса этой фазой ещё не доказаны.",
|
||||
}}
|
||||
method={result.method}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.8Q VISUAL EVIDENCE · NATIVE RAW KB4"
|
||||
title="24 исходных fisheye-кадра с отключаемым client-side overlay"
|
||||
kind="diagnostic-model"
|
||||
resizable
|
||||
>
|
||||
<M48TRiskQualityVisual result={result} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Native runtime закрыт; следующий честный шаг — adjudication этих кейсов"
|
||||
status="Review-ready · quality-not-adjudicated"
|
||||
statusTone="success"
|
||||
metrics={[
|
||||
{ label: "Full graph", value: `${decimal(result.execution.effectiveWorldStateFps, 3)} FPS`, hint: `delivery ${percent(result.runtime.deliveryRatio, 2)} · 4 489/4 489` },
|
||||
{ label: "Detector / world-state p95", value: `${decimal(result.execution.detectorTotalP95Ms, 2)} / ${decimal(result.execution.worldStateCompletionP95Ms, 2)} ms`, hint: "один native pass · additional inference 0" },
|
||||
{ label: "GPU / VRAM peak", value: `${decimal(result.execution.gpuUtilizationP95Percent, 1)}% / ${decimal(result.execution.gpuMemoryMaximumMib / 1024, 2)} GiB`, hint: "Worker 006 · RTX 4090 envelope" },
|
||||
{ label: "Native parity", value: `${percent(result.parity.precision, 2)} / ${percent(result.parity.recall, 2)}`, hint: `precision / recall · mean IoU ${percent(result.parity.meanIou, 2)}` },
|
||||
{ label: "Review pack", value: `${result.selection.caseCount}/24 cases`, hint: "8 diagnostic buckets · raw 800×600" },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: `Полный reference graph доставил все ${result.source.frameCount.toLocaleString("ru-RU")} world states на ${decimal(result.execution.effectiveWorldStateFps, 3)} FPS. Детектор использовал ровно один native 800×600 KB4 pass без геометрического resampling. Hash-bound review содержит person, dog, bicycle, skateboard, car и truck; боксы рисуются поверх чистого кадра и отключаются кнопкой.`,
|
||||
notProved: "Не доказаны route-domain precision/recall, истинность 24 классов и боксов, child/adult, поведение объектов, физическая track identity и безопасность навигации. Legacy 704 count delta остаётся только диагностикой, потому что старая ветка растягивала 4:3 raster.",
|
||||
decision: "Не добавлять второй detector и не менять realtime graph. Использовать эти 24 кейса как вход существующего M4.8 review/correction workflow; только после независимой adjudication считать route-domain semantic quality.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { Icon, IconButton } from "@nodedc/ui-react";
|
||||
|
||||
import { LaboratoryEvidenceViewer } from "../../components/laboratory/LaboratoryEvidenceViewer";
|
||||
import { RecordedEvidenceImageScene } from "../../components/laboratory/RecordedEvidenceImageScene";
|
||||
import type {
|
||||
RecordedEvidenceBox,
|
||||
RecordedEvidenceBoxTone,
|
||||
} from "../../components/laboratory/RecordedEvidenceBoxOverlay";
|
||||
import type {
|
||||
M48QNativeRiskQualityResult,
|
||||
M48QRiskFamily,
|
||||
M48TLegacyRiskQualityResult,
|
||||
M48TRiskQualityResult,
|
||||
} from "../../core/laboratory/m48tRiskQuality";
|
||||
|
||||
function navigateIndex(current: number, offset: -1 | 1, length: number): number {
|
||||
return (current + offset + length) % length;
|
||||
}
|
||||
|
||||
function familyTone(family: M48QRiskFamily): RecordedEvidenceBoxTone {
|
||||
if (family === "person" || family === "animal") return "danger";
|
||||
if (family === "light-road-user") return "warning";
|
||||
return "accent";
|
||||
}
|
||||
|
||||
function LegacyVisual({ result }: { result: M48TLegacyRiskQualityResult }) {
|
||||
const [index, setIndex] = useState(0);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const item = result.review.cases[index] ?? null;
|
||||
const navigate = (offset: -1 | 1) =>
|
||||
setIndex((current) => navigateIndex(current, offset, result.review.cases.length));
|
||||
|
||||
return (
|
||||
<div className="l3-visual-audit">
|
||||
<LaboratoryEvidenceViewer
|
||||
label="M4.8T independent COCO quality review"
|
||||
mode="quality"
|
||||
modes={[{ value: "quality", label: "COCO TRUTH" }]}
|
||||
expanded={expanded}
|
||||
onModeChange={() => undefined}
|
||||
onExpandedChange={setExpanded}
|
||||
actions={(
|
||||
<div className="l3-visual-audit__pagination">
|
||||
<IconButton label="Предыдущий M4.8T review case" onClick={() => navigate(-1)}>
|
||||
<Icon name="chevron-left" size={16} />
|
||||
</IconButton>
|
||||
<IconButton label="Следующий M4.8T review case" onClick={() => navigate(1)}>
|
||||
<Icon name="chevron-right" size={16} />
|
||||
</IconButton>
|
||||
</div>
|
||||
)}
|
||||
overlay={item ? (
|
||||
<div className="l3-visual-audit__overlay">
|
||||
<div>
|
||||
<span>COCO val2017 · independent human truth</span>
|
||||
<strong>case {index + 1}/{result.review.cases.length} · image {item.imageId}</strong>
|
||||
<small>Зелёный — truth · жёлтый — RF-DETR prediction · score ≥ 0,25</small>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
>
|
||||
{item ? (
|
||||
<div className="l32-camera-scene">
|
||||
<img
|
||||
src={item.imageUrl}
|
||||
alt={`M4.8T COCO review image ${item.imageId}: truth and RF-DETR boxes`}
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="l3-visual-audit__state" role="alert">
|
||||
<Icon name="alert" size={18} />
|
||||
M4.8T visual evidence недоступно.
|
||||
</div>
|
||||
)}
|
||||
</LaboratoryEvidenceViewer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NativeVisual({ result }: { result: M48QNativeRiskQualityResult }) {
|
||||
const [index, setIndex] = useState(0);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [boxesVisible, setBoxesVisible] = useState(true);
|
||||
const item = result.review.cases[index] ?? null;
|
||||
const boxes = useMemo<readonly RecordedEvidenceBox[]>(() => {
|
||||
if (!item || !boxesVisible) return [];
|
||||
return item.proposals.map((proposal) => ({
|
||||
boxXyxy: proposal.boxXyxy,
|
||||
label: `${proposal.className} · ${proposal.score.toFixed(2)}`,
|
||||
tone: familyTone(proposal.riskFamily),
|
||||
}));
|
||||
}, [boxesVisible, item]);
|
||||
const navigate = (offset: -1 | 1) =>
|
||||
setIndex((current) => navigateIndex(current, offset, result.review.cases.length));
|
||||
|
||||
return (
|
||||
<div className="l3-visual-audit">
|
||||
<LaboratoryEvidenceViewer
|
||||
label="M4.8Q native raw-fisheye risk review"
|
||||
mode="native"
|
||||
modes={[{ value: "native", label: "NATIVE RF-DETR" }]}
|
||||
expanded={expanded}
|
||||
onModeChange={() => undefined}
|
||||
onExpandedChange={setExpanded}
|
||||
actions={(
|
||||
<div className="l3-visual-audit__pagination">
|
||||
<IconButton label="Предыдущий M4.8Q review case" onClick={() => navigate(-1)}>
|
||||
<Icon name="chevron-left" size={16} />
|
||||
</IconButton>
|
||||
<IconButton label="Следующий M4.8Q review case" onClick={() => navigate(1)}>
|
||||
<Icon name="chevron-right" size={16} />
|
||||
</IconButton>
|
||||
</div>
|
||||
)}
|
||||
trailingActions={(
|
||||
<IconButton
|
||||
label={boxesVisible ? "Скрыть native RF-DETR боксы" : "Показать native RF-DETR боксы"}
|
||||
onClick={() => setBoxesVisible((visible) => !visible)}
|
||||
>
|
||||
<Icon name={boxesVisible ? "eye-off" : "eye"} size={16} />
|
||||
</IconButton>
|
||||
)}
|
||||
overlay={item ? (
|
||||
<div className="l3-visual-audit__overlay">
|
||||
<div>
|
||||
<span>RAVNOVES00 · raw KB4 800×600 · resampling NO</span>
|
||||
<strong>
|
||||
case {index + 1}/{result.review.cases.length} · frame {item.sequence} · {item.proposals.length} native boxes
|
||||
</strong>
|
||||
<small>
|
||||
{item.selectionBuckets.join(" · ")} · native/legacy {item.nativeDetectionCount}/{item.legacyDetectionCount} (diagnostic only)
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
>
|
||||
{item ? (
|
||||
<RecordedEvidenceImageScene
|
||||
src={item.imageUrl}
|
||||
imageWidth={item.width}
|
||||
imageHeight={item.height}
|
||||
boxes={boxes}
|
||||
ariaLabel={`M4.8Q frame ${item.sequence}: ${boxes.length} visible native risk boxes`}
|
||||
/>
|
||||
) : (
|
||||
<div className="l3-visual-audit__state" role="alert">
|
||||
<Icon name="alert" size={18} />
|
||||
M4.8Q native visual evidence недоступно.
|
||||
</div>
|
||||
)}
|
||||
</LaboratoryEvidenceViewer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function M48TRiskQualityVisual({ result }: { result: M48TRiskQualityResult }) {
|
||||
return result.variant === "native-risk-review"
|
||||
? <NativeVisual result={result} />
|
||||
: <LegacyVisual result={result} />;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import type {
|
||||
RecordedEvidenceSemanticClass,
|
||||
RecordedEvidenceSemanticPaletteEntry,
|
||||
} from "../../components/laboratory/RecordedEvidenceSemanticMaskOverlay";
|
||||
import {
|
||||
fetchM49TgsAnchorSpatial,
|
||||
type M49TgsAnchorSpatial,
|
||||
type M49TgsFailClosedResult,
|
||||
type M49TgsStateCode,
|
||||
} from "../../core/laboratory/m49TgsFailClosed";
|
||||
import {
|
||||
M4ReplayThreatVisual,
|
||||
type M4ReplayClassifiedSpatialFrame,
|
||||
type M4ReplayThreatReviewAnchor,
|
||||
} from "./M4ReplayThreatVisual";
|
||||
|
||||
const CLASSES: readonly RecordedEvidenceSemanticClass[] = [
|
||||
{ id: 1, label: "Ground support" },
|
||||
{ id: 2, label: "Non-ground occupied" },
|
||||
{ id: 3, label: "Unknown / rejected" },
|
||||
];
|
||||
|
||||
const PALETTE: readonly RecordedEvidenceSemanticPaletteEntry[] = [
|
||||
{ classId: 1, color: { kind: "token", token: "--nodedc-success-rgb" } },
|
||||
{ classId: 2, color: { kind: "token", token: "--nodedc-danger-rgb" } },
|
||||
{ classId: 3, color: { kind: "token", token: "--nodedc-warning-rgb" } },
|
||||
];
|
||||
|
||||
function cellState(code: M49TgsStateCode): M4ReplayClassifiedSpatialFrame["cellsMapGravityLocal"][number]["state"] {
|
||||
if (code === 1) return "ground-support";
|
||||
if (code === 2) return "nonground-occupied";
|
||||
if (code === 3) return "unknown-rejected";
|
||||
return "unobserved";
|
||||
}
|
||||
|
||||
function message(error: unknown): string {
|
||||
return error instanceof Error && error.message.trim()
|
||||
? error.message
|
||||
: "M49 TGS spatial evidence недоступно.";
|
||||
}
|
||||
|
||||
export function M49TgsFailClosedEvidence({
|
||||
result,
|
||||
}: {
|
||||
result: M49TgsFailClosedResult;
|
||||
}) {
|
||||
const [activeSequence, setActiveSequence] = useState<number | null>(null);
|
||||
const [spatial, setSpatial] = useState<M49TgsAnchorSpatial | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const spatialCacheRef = useRef(new Map<string, M49TgsAnchorSpatial>());
|
||||
const anchorSequences = useMemo(
|
||||
() => new Set(result.metrics.primary.map((item) => item.anchorFrameIndex)),
|
||||
[result.metrics.primary],
|
||||
);
|
||||
const expectedAtSequence = activeSequence !== null && anchorSequences.has(activeSequence);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeSequence === null || !anchorSequences.has(activeSequence)) {
|
||||
setSpatial(null);
|
||||
setLoading(false);
|
||||
setError(null);
|
||||
return;
|
||||
}
|
||||
const cacheKey = `${result.resultId}:${activeSequence}`;
|
||||
const cached = spatialCacheRef.current.get(cacheKey);
|
||||
if (cached) {
|
||||
setSpatial(cached);
|
||||
setLoading(false);
|
||||
setError(null);
|
||||
return;
|
||||
}
|
||||
const controller = new AbortController();
|
||||
setSpatial(null);
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
void fetchM49TgsAnchorSpatial(
|
||||
result.resultId,
|
||||
activeSequence,
|
||||
"causal_rolling_1s",
|
||||
{ signal: controller.signal },
|
||||
)
|
||||
.then((next) => {
|
||||
if (!controller.signal.aborted) {
|
||||
spatialCacheRef.current.set(cacheKey, next);
|
||||
setSpatial(next);
|
||||
}
|
||||
})
|
||||
.catch((caught: unknown) => {
|
||||
if (!controller.signal.aborted) setError(message(caught));
|
||||
})
|
||||
.finally(() => {
|
||||
if (!controller.signal.aborted) setLoading(false);
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [activeSequence, anchorSequences, result.resultId]);
|
||||
|
||||
const reviewAnchors = useMemo<readonly M4ReplayThreatReviewAnchor[]>(
|
||||
() => result.metrics.primary.map((item) => ({
|
||||
id: `m49-tgs-${item.anchorFrameIndex}`,
|
||||
sourceSequence: item.anchorFrameIndex,
|
||||
extentXyxyNormalized: [0, 0, 0, 0],
|
||||
matchedAtThreshold: false,
|
||||
statusLabel: "визуальная проверка",
|
||||
})),
|
||||
[result.metrics.primary],
|
||||
);
|
||||
|
||||
const classifiedFrame = useMemo<M4ReplayClassifiedSpatialFrame | null>(() => {
|
||||
if (!spatial) return null;
|
||||
return {
|
||||
sourceSequence: spatial.sourceSequence,
|
||||
pointsMapGravityLocalXyzM: spatial.pointsXyzM,
|
||||
pointClassIds: spatial.pointStates,
|
||||
cellsMapGravityLocal: spatial.costmap.centersXyM.map((center, index) => ({
|
||||
centerXyM: center,
|
||||
zBoundsM: spatial.costmap.zBoundsM[index]!,
|
||||
state: cellState(spatial.costmap.states[index]!),
|
||||
})),
|
||||
cellSizeM: spatial.costmap.cellSizeM,
|
||||
classes: CLASSES,
|
||||
palette: PALETTE,
|
||||
};
|
||||
}, [spatial]);
|
||||
|
||||
const handleSequenceChange = useCallback((sequence: number | null) => {
|
||||
setActiveSequence(sequence);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<M4ReplayThreatVisual
|
||||
resultId={result.source.linkedVisualResultId}
|
||||
reviewAnchors={reviewAnchors}
|
||||
showReviewAnchorBoxes={false}
|
||||
reviewLabel="10 gravity-aligned TGS anchors"
|
||||
evidenceLabel="M49 · TGS fail-closed"
|
||||
initialSpatialMode="3d"
|
||||
onActiveSequenceChange={handleSequenceChange}
|
||||
classifiedSpatialLayer={{
|
||||
label: "TGS fail-closed · causal rolling 1 s",
|
||||
pointLayerLabel: "TGS POINTS",
|
||||
cellLayerLabel: "COSTMAP",
|
||||
expectedAtSequence,
|
||||
frame: classifiedFrame,
|
||||
loading,
|
||||
error,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import type { M49TgsFailClosedResult } from "../../core/laboratory/m49TgsFailClosed";
|
||||
import { M49TgsFailClosedEvidence } from "./M49TgsFailClosedEvidence";
|
||||
|
||||
function number(value: number, digits = 1): string {
|
||||
return value.toLocaleString("ru-RU", { maximumFractionDigits: digits });
|
||||
}
|
||||
|
||||
export function M49TgsFailClosedResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: M49TgsFailClosedResult;
|
||||
}) {
|
||||
const worst = [...result.metrics.primary].sort(
|
||||
(left, right) => (
|
||||
right.nongroundPointCount / Math.max(right.pointCount, 1)
|
||||
- left.nongroundPointCount / Math.max(left.pointCount, 1)
|
||||
),
|
||||
)[0]!;
|
||||
const status = "Representation complete; визуальное качество ещё не принято";
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.9T4 · TRAVEL TGS fail-closed evidence"
|
||||
description="TRAVEL GroundSeg запущен без AOS на десяти immutable RAVNOVES00 anchors. Вход сохранён в gravity-aligned map frame; каждый eligible point получил состояние, а каждая costmap-ячейка остаётся ground, occupied, rejected или unobserved."
|
||||
status={status}
|
||||
statusTone="warning"
|
||||
facts={[
|
||||
{ label: "Конфигурация", value: `${rigLabel} RIGHT · Camera + gravity-aligned LiDAR · 10 anchors` },
|
||||
{ label: "Метод", value: "TRAVEL TGS only · AOS OFF · causal rolling 1 s" },
|
||||
{ label: "Evidence", value: `${result.metrics.anchorCount} anchors · ${result.metrics.costmapCellCount.toLocaleString("ru-RU")} cells/anchor · all points accounted` },
|
||||
{ label: "Нагрузка", value: `Worker 006 CPU-only · GPU 0 · wrapper ${number(result.execution.wrapperElapsedSeconds, 2)} с` },
|
||||
{ label: "Authority", value: "REPLAY-SIMULATED · visual/traversability/navigation/actuation OFF" },
|
||||
]}
|
||||
brief={{
|
||||
question: "Отделяет ли готовый TRAVEL TGS опорную поверхность от неизвестной занятой геометрии достаточно чисто, чтобы заменить самодельный static-obstacle threshold pipeline?",
|
||||
approach: "На десяти сложных кадрах проверяется полный gravity-aligned point set и fail-closed costmap. Зелёное — опора, красное — non-ground occupied, жёлтое — rejected/unknown, тёмное — unobserved; камера остаётся синхронным первичным контекстом.",
|
||||
principalResult: `Контракт представления закрыт: ${result.metrics.anchorProfileCount}/20 профилей, ни одной потерянной eligible point, AOS и GPU отсутствуют. Process wall rolling p50/max: ${number(result.metrics.processWallRollingP50Ms, 0)}/${number(result.metrics.processWallRollingMaxMs, 0)} мс.`,
|
||||
limitation: `Качество не принято: особенно проверить кадр ${worst.anchorFrameIndex + 1}, где ${number(worst.nongroundPointCount / Math.max(worst.pointCount, 1) * 100)}% rolling points помечены non-ground. Это может быть реальная боковая геометрия либо ложная блокировка поверхности.`,
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "deterministic",
|
||||
pipelineId: "travel-tgs-gravity-aligned-fail-closed/v1",
|
||||
components: [
|
||||
{ kind: "source", name: "RAVNOVES00", version: "10 immutable anchors", role: "camera + registered map increments", identitySha256: result.source.sourcePackSha256 },
|
||||
{ kind: "algorithm", name: "TRAVEL GroundSeg", version: "95dc2fbd66a343efd9060c45a5711b6307a950a4", role: "ground/nonground separation; AOS excluded", identitySha256: result.configuration.configSha256 },
|
||||
{ kind: "algorithm", name: "fail-closed complement adapter", version: "v1", role: "explicit rejected points and unobserved cells", identitySha256: result.resultId.split("-").at(-1) ?? null },
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.9T4 VISUAL EVIDENCE · CAMERA + GRAVITY-ALIGNED TGS"
|
||||
title="10 anchors: полный TGS point set и четырёхсостояний costmap на том же recorded timeline"
|
||||
kind="recorded-replay"
|
||||
resizable
|
||||
>
|
||||
<M49TgsFailClosedEvidence result={result} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Что уже доказано и что проверяем глазами"
|
||||
status={status}
|
||||
statusTone="warning"
|
||||
metrics={[
|
||||
{ label: "Point accounting", value: "100%", hint: "ground + non-ground + rejected = exact eligible input" },
|
||||
{ label: "Anchors", value: `${result.metrics.anchorCount}/10`, hint: "current + causal rolling 1 s" },
|
||||
{ label: "Costmap", value: `${result.metrics.costmapCellCount.toLocaleString("ru-RU")} cells`, hint: `${number(result.configuration.cellSizeM, 2)} м · radius ${number(result.configuration.radiusM, 0)} м` },
|
||||
{ label: "Process wall rolling", value: `${number(result.metrics.processWallRollingP50Ms, 0)} / ${number(result.metrics.processWallRollingMaxMs, 0)} мс`, hint: "p50 / max · CPU process envelope, не realtime integration" },
|
||||
{ label: "GPU / AOS", value: "0 / OFF", hint: "Worker 006; Frigate budget не затронут" },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: "Готовый TGS можно встроить fail-closed: исходные точки не теряются, unknown не становится free, AOS не нужен, а вычисление укладывается в лёгкий CPU-контур на этих anchors.",
|
||||
notProved: "Не доказано, что красный non-ground слой не режет дорогу, траву или допустимые просветы. Нет независимой terrain truth, полного replay, realtime graph integration и модели корпуса.",
|
||||
decision: "Открыть десять anchors по очереди. Если красное остаётся на реальных препятствиях и не перекрывает видимую опорную поверхность, TGS идёт в полный shadow; иначе кандидат отклоняется без ручной подгонки порогов под эти кадры.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
|
||||
import type {
|
||||
RecordedEvidenceSemanticClass,
|
||||
RecordedEvidenceSemanticPaletteEntry,
|
||||
} from "../../components/laboratory/RecordedEvidenceSemanticMaskOverlay";
|
||||
import {
|
||||
fetchE47SemanticSlamResult,
|
||||
type E47SemanticSlamResult,
|
||||
} from "../../core/laboratory/e47SemanticSlam";
|
||||
import {
|
||||
fetchM49PhysicalSafetyPlaybackIdForSource,
|
||||
M49PhysicalSafetyPlaybackBuffer,
|
||||
type M49PhysicalSafetyPlaybackProgress,
|
||||
} from "../../core/laboratory/m49PhysicalSafetyPlayback";
|
||||
import {
|
||||
fetchM49TgsFullShadowPlaybackPack,
|
||||
type M49TgsFullShadowResult,
|
||||
type M49TgsFullShadowPlaybackPack,
|
||||
type M49TgsFullShadowPlaybackProgress,
|
||||
} from "../../core/laboratory/m49TgsFullShadow";
|
||||
import {
|
||||
M4ReplayThreatVisual,
|
||||
type M4ReplayClassifiedSpatialFrame,
|
||||
type M4ReplayThreatSemanticLayer,
|
||||
} from "./M4ReplayThreatVisual";
|
||||
|
||||
const CLASSES: readonly RecordedEvidenceSemanticClass[] = [
|
||||
{ id: 1, label: "Ground support" },
|
||||
{ id: 2, label: "Non-ground occupied" },
|
||||
{ id: 3, label: "Unknown / rejected" },
|
||||
];
|
||||
|
||||
const PALETTE: readonly RecordedEvidenceSemanticPaletteEntry[] = [
|
||||
{ classId: 1, color: { kind: "token", token: "--nodedc-success-rgb" } },
|
||||
{ classId: 2, color: { kind: "token", token: "--nodedc-danger-rgb" } },
|
||||
{ classId: 3, color: { kind: "token", token: "--nodedc-warning-rgb" } },
|
||||
];
|
||||
|
||||
function message(error: unknown): string {
|
||||
return error instanceof Error && error.message.trim()
|
||||
? error.message
|
||||
: "Полный TGS spatial frame недоступен.";
|
||||
}
|
||||
|
||||
export function M49TgsFullShadowEvidence({
|
||||
result,
|
||||
semanticOverride,
|
||||
evidenceLabel = "M49 · full TGS shadow",
|
||||
}: {
|
||||
result: M49TgsFullShadowResult;
|
||||
semanticOverride?: M4ReplayThreatSemanticLayer;
|
||||
evidenceLabel?: string;
|
||||
}) {
|
||||
const [activeSequence, setActiveSequence] = useState<number | null>(null);
|
||||
const [semantic, setSemantic] = useState<E47SemanticSlamResult | null>(null);
|
||||
const [semanticError, setSemanticError] = useState<string | null>(null);
|
||||
const [playbackPack, setPlaybackPack] = useState<M49TgsFullShadowPlaybackPack | null>(null);
|
||||
const [physicalPlayback, setPhysicalPlayback] = useState<M49PhysicalSafetyPlaybackBuffer | null>(null);
|
||||
const [physicalProgress, setPhysicalProgress] = useState<M49PhysicalSafetyPlaybackProgress | null>(null);
|
||||
const [physicalRevision, setPhysicalRevision] = useState(0);
|
||||
const [playbackProgress, setPlaybackProgress] = useState<M49TgsFullShadowPlaybackProgress>({
|
||||
phase: "manifest",
|
||||
trackId: null,
|
||||
loadedBytes: 0,
|
||||
totalBytes: 0,
|
||||
});
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
setSemantic(null);
|
||||
setSemanticError(null);
|
||||
void fetchE47SemanticSlamResult({
|
||||
resultId: result.source.linkedSemanticResultId,
|
||||
signal: controller.signal,
|
||||
})
|
||||
.then((next) => {
|
||||
if (controller.signal.aborted) return;
|
||||
if (!next || next.baseM4ResultId !== result.source.linkedVisualResultId) {
|
||||
throw new Error("Semantic archive не совпал с исходным M4 timeline.");
|
||||
}
|
||||
setSemantic(next);
|
||||
})
|
||||
.catch((caught: unknown) => {
|
||||
if (!controller.signal.aborted) setSemanticError(message(caught));
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [result.source.linkedSemanticResultId, result.source.linkedVisualResultId]);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
setPlaybackPack(null);
|
||||
setPhysicalPlayback(null);
|
||||
setPhysicalProgress(null);
|
||||
setPhysicalRevision(0);
|
||||
setPlaybackProgress({ phase: "manifest", trackId: null, loadedBytes: 0, totalBytes: 0 });
|
||||
setError(null);
|
||||
void fetchM49PhysicalSafetyPlaybackIdForSource(result.resultId, {
|
||||
signal: controller.signal,
|
||||
}).then(async (physicalResultId) => {
|
||||
if (controller.signal.aborted) return;
|
||||
if (physicalResultId) {
|
||||
const playback = await M49PhysicalSafetyPlaybackBuffer.open(physicalResultId, {
|
||||
signal: controller.signal,
|
||||
onProgress: setPhysicalProgress,
|
||||
});
|
||||
if (!controller.signal.aborted) setPhysicalPlayback(playback);
|
||||
return;
|
||||
}
|
||||
const pack = await fetchM49TgsFullShadowPlaybackPack(result.resultId, {
|
||||
signal: controller.signal,
|
||||
onProgress: setPlaybackProgress,
|
||||
});
|
||||
if (!controller.signal.aborted) setPlaybackPack(pack);
|
||||
}).catch((caught: unknown) => {
|
||||
if (!controller.signal.aborted) setError(message(caught));
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [result.resultId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeSequence === null || !physicalPlayback) return;
|
||||
let active = true;
|
||||
const resident = physicalPlayback.frameIfResident(activeSequence);
|
||||
void physicalPlayback.prepare(activeSequence).then(() => {
|
||||
if (active && !resident) setPhysicalRevision((value) => value + 1);
|
||||
}).catch((caught: unknown) => {
|
||||
if (active) setError(message(caught));
|
||||
});
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [activeSequence, physicalPlayback]);
|
||||
|
||||
const classifiedFrame = useMemo<M4ReplayClassifiedSpatialFrame | null>(() => {
|
||||
if (activeSequence === null) return null;
|
||||
if (physicalPlayback) {
|
||||
const frame = physicalPlayback.frameIfResident(activeSequence);
|
||||
if (!frame) return null;
|
||||
return {
|
||||
sourceSequence: activeSequence,
|
||||
sampleAvailable: frame.metadata.sampleAvailable,
|
||||
sourcePointCount: frame.metadata.metrics.eligible_point_count ?? 0,
|
||||
pointsMapGravityLocalXyzM: [],
|
||||
pointClassIds: [],
|
||||
cellsMapGravityLocal: [],
|
||||
packedCellsMapGravityLocal: {
|
||||
centersXyM: frame.centersXyM,
|
||||
stateCodes: frame.states,
|
||||
zBoundsM: frame.zBoundsM,
|
||||
},
|
||||
cellSizeM: frame.cellSizeM,
|
||||
classes: CLASSES,
|
||||
palette: PALETTE,
|
||||
};
|
||||
}
|
||||
if (!playbackPack) return null;
|
||||
const frame = playbackPack.frames[activeSequence];
|
||||
if (!frame) return null;
|
||||
const cellOffset = activeSequence * playbackPack.cellCount;
|
||||
const zOffset = cellOffset * 2;
|
||||
return {
|
||||
sourceSequence: activeSequence,
|
||||
sampleAvailable: frame.sampleAvailable,
|
||||
sourcePointCount: frame.metrics.eligiblePointCount,
|
||||
pointsMapGravityLocalXyzM: [],
|
||||
pointClassIds: [],
|
||||
cellsMapGravityLocal: [],
|
||||
packedCellsMapGravityLocal: {
|
||||
centersXyM: playbackPack.centersXyM,
|
||||
stateCodes: playbackPack.states.subarray(
|
||||
cellOffset,
|
||||
cellOffset + playbackPack.cellCount,
|
||||
),
|
||||
zBoundsM: playbackPack.zBoundsM.subarray(
|
||||
zOffset,
|
||||
zOffset + playbackPack.cellCount * 2,
|
||||
),
|
||||
},
|
||||
cellSizeM: result.configuration.cellSizeM,
|
||||
classes: CLASSES,
|
||||
palette: PALETTE,
|
||||
};
|
||||
}, [activeSequence, physicalPlayback, physicalRevision, playbackPack, result.configuration.cellSizeM]);
|
||||
const loading = activeSequence !== null && !classifiedFrame && !error;
|
||||
const progressPercent = playbackProgress.totalBytes > 0
|
||||
? Math.min(100, Math.round((playbackProgress.loadedBytes / playbackProgress.totalBytes) * 100))
|
||||
: 0;
|
||||
const loadingLabel = physicalProgress
|
||||
? physicalProgress.phase === "ready"
|
||||
? "Sealed TGS playback готов"
|
||||
: `Буферизуем sealed TGS · ${physicalProgress.residentChunkIndexes.length}/3 chunks · ${(physicalProgress.loadedBytes / 1_048_576).toFixed(1)} МБ`
|
||||
: playbackProgress.phase === "manifest"
|
||||
? "Проверяем playback manifest"
|
||||
: playbackProgress.phase === "ready"
|
||||
? "TGS playback готов"
|
||||
: `Подготавливаем TGS playback · ${progressPercent}% · ${(playbackProgress.loadedBytes / 1_048_576).toFixed(1)}/${(playbackProgress.totalBytes / 1_048_576).toFixed(1)} МБ`;
|
||||
|
||||
const handleSequenceChange = useCallback((sequence: number | null) => {
|
||||
setActiveSequence(sequence);
|
||||
}, []);
|
||||
const semanticLayers = useMemo<readonly M4ReplayThreatSemanticLayer[]>(() => [
|
||||
...(semantic ? [{
|
||||
id: "urban",
|
||||
controlLabel: "ГОРОД · EoMT",
|
||||
resultId: semantic.resultId,
|
||||
taxonomy: semantic.taxonomy,
|
||||
label: "EoMT Cityscapes semantic · recorded video",
|
||||
maskAriaLabel: "EoMT urban semantic prediction",
|
||||
}] : []),
|
||||
...(semanticOverride ? [{
|
||||
...semanticOverride,
|
||||
id: semanticOverride.id ?? "vegetation",
|
||||
controlLabel: semanticOverride.controlLabel ?? "ПРИРОДА · DDRNet",
|
||||
}] : []),
|
||||
], [semantic, semanticOverride]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<M4ReplayThreatVisual
|
||||
resultId={result.source.linkedVisualResultId}
|
||||
semanticLayers={semanticLayers}
|
||||
initialSemanticLayerId={semanticOverride ? "vegetation" : "urban"}
|
||||
showReviewAnchorBoxes={false}
|
||||
reviewLabel="4 489 source-paced TGS frames"
|
||||
evidenceLabel={evidenceLabel}
|
||||
initialSpatialMode="3d"
|
||||
onActiveSequenceChange={handleSequenceChange}
|
||||
classifiedSpatialLayer={{
|
||||
label: "TGS full shadow · causal rolling 1 s",
|
||||
pointLayerLabel: "SOURCE POINTS",
|
||||
cellLayerLabel: "TGS COSTMAP",
|
||||
expectedAtSequence: true,
|
||||
frame: classifiedFrame,
|
||||
loading,
|
||||
loadingLabel,
|
||||
error,
|
||||
replacePointCloud: false,
|
||||
}}
|
||||
/>
|
||||
{semanticError ? (
|
||||
<div className="m4-replay-threat-visual__pane-status" role="alert">
|
||||
Semantic overlay недоступен: {semanticError}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import type { M49TgsFullShadowResult } from "../../core/laboratory/m49TgsFullShadow";
|
||||
import { M49TgsFullShadowEvidence } from "./M49TgsFullShadowEvidence";
|
||||
|
||||
function number(value: number, digits = 1): string {
|
||||
return value.toLocaleString("ru-RU", { maximumFractionDigits: digits });
|
||||
}
|
||||
|
||||
export function M49TgsFullShadowResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: M49TgsFullShadowResult;
|
||||
}) {
|
||||
const accepted = result.decision.candidateRetained;
|
||||
const status = accepted
|
||||
? "Source-paced CPU shadow принят; визуальное и integrated-graph качество ещё проверяются"
|
||||
: "Source-paced CPU shadow не прошёл performance gate";
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.9T5 · полный source-paced TRAVEL TGS shadow"
|
||||
description="Один CPU-only процесс прошёл весь recorded timeline RAVNOVES00 в исходном темпе. Камера остаётся владельцем времени; dense source cloud сохраняется, поверх него показывается четырёхсостояний TGS costmap."
|
||||
status={status}
|
||||
statusTone={accepted ? "success" : "danger"}
|
||||
facts={[
|
||||
{ label: "Конфигурация", value: `${rigLabel} RIGHT · gravity-aligned LiDAR · causal ${number(result.configuration.historySeconds)} с` },
|
||||
{ label: "Timeline", value: `${result.timeline.frameCount.toLocaleString("ru-RU")} кадров · ${result.timeline.availableLidarFrameCount.toLocaleString("ru-RU")} LiDAR · ${result.timeline.missingLidarFrameCount} UNOBSERVED` },
|
||||
{ label: "Нагрузка", value: `Worker 006 CPU-only · GPU 0 · ${number(result.timeline.effectiveFps, 3)} source FPS` },
|
||||
{ label: "Authority", value: "REPLAY-SIMULATED · navigation/actuation OFF · integrated graph отдельно" },
|
||||
]}
|
||||
brief={{
|
||||
question: "Удерживает ли готовый TRAVEL TGS полный десятигерцовый replay без очереди и потери кадров?",
|
||||
approach: "Все 4 489 camera frames планируются по исходным timestamps. Для 3 928 доступных LiDAR frames выполняется causal rolling 1 s; 561 пропуск остаётся полностью UNOBSERVED.",
|
||||
principalResult: `${result.timeline.frameCount}/4 489 frames и ${result.pointAccounting.eligible.toLocaleString("ru-RU")} eligible points учтены; TGS p95/p99 ${number(result.performance.candidateTgsMs.p95, 2)}/${number(result.performance.candidateTgsMs.p99, 2)} мс, completion age p99 ${number(result.performance.completionAgeMs.p99, 2)} мс, capacity drops ${result.performance.capacityDropCount}.`,
|
||||
limitation: "Это isolated CPU shadow. Он ещё не доказывает качество красных occupied-ячеек, проходимость для конкретного корпуса или регрессию FPS полного world-state graph.",
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "deterministic",
|
||||
pipelineId: "travel-tgs-full-source-paced-shadow/v1",
|
||||
components: [
|
||||
{ kind: "source", name: "RAVNOVES00", version: "4 489-frame recorded timeline", role: "camera-owned source clock + registered LiDAR", identitySha256: result.source.sourcePackSha256 },
|
||||
{ kind: "algorithm", name: "TRAVEL GroundSeg", version: "95dc2fbd66a343efd9060c45a5711b6307a950a4", role: "gravity-aligned ground/non-ground separation; AOS OFF", identitySha256: result.configuration.configSha256 },
|
||||
{ kind: "algorithm", name: "fail-closed costmap adapter", version: "v1", role: "occupied > rejected > ground > unobserved; no free inference", identitySha256: result.resultId.split("-").at(-1) ?? null },
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.9T5 VISUAL EVIDENCE · FULL CAMERA TIMELINE + SOURCE CLOUD + TGS COSTMAP"
|
||||
title="Полный timeline: dense исходные точки сохранены, TGS-ячейки синхронны каждому кадру"
|
||||
kind="recorded-replay"
|
||||
resizable
|
||||
>
|
||||
<M49TgsFullShadowEvidence result={result} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Что доказал полный прогон"
|
||||
status={status}
|
||||
statusTone={accepted ? "success" : "danger"}
|
||||
metrics={[
|
||||
{ label: "Timeline", value: `${result.timeline.frameCount}/4 489`, hint: `${result.timeline.availableLidarFrameCount} LiDAR + ${result.timeline.missingLidarFrameCount} explicit UNOBSERVED` },
|
||||
{ label: "TGS p95 / p99", value: `${number(result.performance.candidateTgsMs.p95, 2)} / ${number(result.performance.candidateTgsMs.p99, 2)} мс`, hint: "чистый candidate stage на CPU" },
|
||||
{ label: "Completion age p99", value: `${number(result.performance.completionAgeMs.p99, 2)} мс`, hint: "от source timestamp до готового frame result" },
|
||||
{ label: "Capacity drops", value: String(result.performance.capacityDropCount), hint: "кадры не отбрасывались ради темпа" },
|
||||
{ label: "Point accounting", value: "100%", hint: `${result.pointAccounting.eligible.toLocaleString("ru-RU")} eligible points` },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: "Полный CPU-only TGS shadow воспроизводимо проходит recorded source clock, сохраняет fail-closed представление и не использует AOS/GPU.",
|
||||
notProved: "Не приняты visual traversability, модель корпуса, камера-проекция TGS и нагрузка после встраивания в полный realtime world-state graph.",
|
||||
decision: accepted
|
||||
? "Кандидат остаётся. Просмотреть полный timeline, затем подключить shadow к realtime graph и измерить общий FPS/latency regression."
|
||||
: "Кандидат не встраивать; сначала локализовать performance gate, который не прошёл полный replay.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useRef, useState, type CSSProperties } from "react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from "react";
|
||||
import {
|
||||
Button,
|
||||
Icon,
|
||||
@@ -12,7 +12,9 @@ import {
|
||||
import { ObservationTimeline } from "../../components/ObservationTimeline";
|
||||
import {
|
||||
LaboratoryMetricEvidenceScene,
|
||||
type LaboratoryMetricCellEvidence,
|
||||
type LaboratoryMetricEvidenceSceneHandle,
|
||||
type LaboratoryMetricPackedCellEvidence,
|
||||
type LaboratoryMetricSceneMode,
|
||||
} from "../../components/laboratory/LaboratoryMetricEvidenceScene";
|
||||
import { LaboratoryEvidenceViewer } from "../../components/laboratory/LaboratoryEvidenceViewer";
|
||||
@@ -47,6 +49,7 @@ import {
|
||||
useM4ThreatTimelineMetadata,
|
||||
} from "./useM4ThreatTimeline";
|
||||
import { useE47SemanticTimelineFrame } from "./useE47SemanticTimeline";
|
||||
import { buildM4StaticObstacleBoxes } from "./m4StaticObstacleBoxes";
|
||||
|
||||
type M4ThreatMediaMode = "video" | "camera";
|
||||
type M4ThreatMediaSelection = M4ThreatMediaMode | "none";
|
||||
@@ -93,8 +96,19 @@ function SpatialState({ message: text }: { message: string }) {
|
||||
}
|
||||
|
||||
export interface M4ReplayThreatSemanticLayer {
|
||||
id?: string;
|
||||
controlLabel?: string;
|
||||
resultId: string;
|
||||
taxonomy: readonly E47SemanticClass[];
|
||||
spatialResultId?: string | null;
|
||||
maskUrl?: (sequence: number) => string;
|
||||
label?: string;
|
||||
maskAriaLabel?: string;
|
||||
taxonomy: readonly {
|
||||
classId: number;
|
||||
label: string;
|
||||
disposition: "labeled" | "ambiguous" | "prediction" | "undefined";
|
||||
colorRgb: readonly [number, number, number];
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface M4ReplayThreatReviewAnchor {
|
||||
@@ -102,6 +116,40 @@ export interface M4ReplayThreatReviewAnchor {
|
||||
sourceSequence: number;
|
||||
extentXyxyNormalized: readonly [number, number, number, number];
|
||||
matchedAtThreshold: boolean;
|
||||
statusLabel?: string;
|
||||
}
|
||||
|
||||
export interface M4ReplayClassifiedSpatialFrame {
|
||||
sourceSequence: number;
|
||||
sampleAvailable?: boolean;
|
||||
sourcePointCount?: number;
|
||||
pointsMapGravityLocalXyzM: readonly (readonly [number, number, number])[];
|
||||
pointClassIds: readonly (number | null)[];
|
||||
cellsMapGravityLocal: readonly {
|
||||
centerXyM: readonly [number, number];
|
||||
zBoundsM: readonly [number | null, number | null];
|
||||
state: LaboratoryMetricCellEvidence["state"];
|
||||
}[];
|
||||
packedCellsMapGravityLocal?: {
|
||||
centersXyM: Float32Array;
|
||||
zBoundsM: Float32Array;
|
||||
stateCodes: Uint8Array;
|
||||
};
|
||||
cellSizeM: number;
|
||||
classes: readonly RecordedEvidenceSemanticClass[];
|
||||
palette: readonly RecordedEvidenceSemanticPaletteEntry[];
|
||||
}
|
||||
|
||||
export interface M4ReplayClassifiedSpatialLayer {
|
||||
label: string;
|
||||
pointLayerLabel: string;
|
||||
cellLayerLabel: string;
|
||||
expectedAtSequence: boolean;
|
||||
frame: M4ReplayClassifiedSpatialFrame | null;
|
||||
loading: boolean;
|
||||
loadingLabel?: string;
|
||||
error: string | null;
|
||||
replacePointCloud?: boolean;
|
||||
}
|
||||
|
||||
const EMPTY_REVIEW_ANCHORS: readonly M4ReplayThreatReviewAnchor[] = [];
|
||||
@@ -109,24 +157,46 @@ const EMPTY_REVIEW_ANCHORS: readonly M4ReplayThreatReviewAnchor[] = [];
|
||||
export function M4ReplayThreatVisual({
|
||||
resultId,
|
||||
semantic,
|
||||
semanticLayers,
|
||||
initialSemanticLayerId,
|
||||
reviewAnchors = EMPTY_REVIEW_ANCHORS,
|
||||
showReviewAnchorBoxes = true,
|
||||
reviewLabel = "Контрольные примеры M4.8R1",
|
||||
timelineEndpointRoot,
|
||||
evidenceLabel = "M4.6",
|
||||
initialSpatialMode = null,
|
||||
classifiedSpatialLayer,
|
||||
showReferenceMediaLayers = true,
|
||||
showSpatialOverlaySummary = true,
|
||||
onActiveSequenceChange,
|
||||
}: {
|
||||
resultId: string;
|
||||
semantic?: M4ReplayThreatSemanticLayer;
|
||||
semanticLayers?: readonly M4ReplayThreatSemanticLayer[];
|
||||
initialSemanticLayerId?: string;
|
||||
reviewAnchors?: readonly M4ReplayThreatReviewAnchor[];
|
||||
showReviewAnchorBoxes?: boolean;
|
||||
reviewLabel?: string;
|
||||
timelineEndpointRoot?: string;
|
||||
evidenceLabel?: string;
|
||||
initialSpatialMode?: LaboratoryMetricSceneMode | null;
|
||||
classifiedSpatialLayer?: M4ReplayClassifiedSpatialLayer;
|
||||
showReferenceMediaLayers?: boolean;
|
||||
showSpatialOverlaySummary?: boolean;
|
||||
onActiveSequenceChange?: (sequence: number | null) => void;
|
||||
}) {
|
||||
const [mediaMode, setMediaMode] = useState<M4ThreatMediaMode | null>("video");
|
||||
const [spatialMode, setSpatialMode] = useState<LaboratoryMetricSceneMode | null>(null);
|
||||
const [spatialMode, setSpatialMode] = useState<LaboratoryMetricSceneMode | null>(
|
||||
initialSpatialMode,
|
||||
);
|
||||
const [showCurrentIncrement, setShowCurrentIncrement] = useState(true);
|
||||
const [showLocalSurface, setShowLocalSurface] = useState(true);
|
||||
const [showRollingMap, setShowRollingMap] = useState(true);
|
||||
const [showLowStep, setShowLowStep] = useState(true);
|
||||
const [showMediaSemantic, setShowMediaSemantic] = useState(true);
|
||||
const [showSpatialSemantic, setShowSpatialSemantic] = useState(true);
|
||||
const [showMediaPoints, setShowMediaPoints] = useState(false);
|
||||
const [showStaticObstacles, setShowStaticObstacles] = useState(true);
|
||||
const [splitPrimarySize, setSplitPrimarySize] = useState(50);
|
||||
const [splitOrientation, setSplitOrientation] = useState<SplitPaneOrientation>(() => (
|
||||
typeof window !== "undefined" && window.matchMedia("(max-width: 900px)").matches
|
||||
@@ -135,6 +205,35 @@ export function M4ReplayThreatVisual({
|
||||
));
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [selectedReviewAnchorIndex, setSelectedReviewAnchorIndex] = useState(0);
|
||||
const availableSemanticLayers = useMemo<readonly M4ReplayThreatSemanticLayer[]>(
|
||||
() => semanticLayers?.length ? semanticLayers : semantic ? [semantic] : [],
|
||||
[semantic, semanticLayers],
|
||||
);
|
||||
const semanticLayerIdentity = availableSemanticLayers
|
||||
.map((layer, index) => layer.id ?? `${layer.resultId}:${index}`)
|
||||
.join("|");
|
||||
const [selectedSemanticLayerId, setSelectedSemanticLayerId] = useState(
|
||||
initialSemanticLayerId ?? "",
|
||||
);
|
||||
useEffect(() => {
|
||||
if (!availableSemanticLayers.length) {
|
||||
setSelectedSemanticLayerId("");
|
||||
return;
|
||||
}
|
||||
const selectedStillExists = availableSemanticLayers.some(
|
||||
(layer, index) => (layer.id ?? `${layer.resultId}:${index}`) === selectedSemanticLayerId,
|
||||
);
|
||||
if (selectedStillExists) return;
|
||||
const preferred = initialSemanticLayerId
|
||||
? availableSemanticLayers.find((layer) => layer.id === initialSemanticLayerId)
|
||||
: null;
|
||||
const next = preferred ?? availableSemanticLayers[0]!;
|
||||
const nextIndex = availableSemanticLayers.indexOf(next);
|
||||
setSelectedSemanticLayerId(next.id ?? `${next.resultId}:${nextIndex}`);
|
||||
}, [availableSemanticLayers, initialSemanticLayerId, semanticLayerIdentity, selectedSemanticLayerId]);
|
||||
const activeSemantic = availableSemanticLayers.find(
|
||||
(layer, index) => (layer.id ?? `${layer.resultId}:${index}`) === selectedSemanticLayerId,
|
||||
) ?? availableSemanticLayers[0];
|
||||
const metricSceneRef = useRef<LaboratoryMetricEvidenceSceneHandle | null>(null);
|
||||
const metadata = useM4ThreatTimelineMetadata(resultId, timelineEndpointRoot);
|
||||
const playbackRange = useMemo(() => metadata.timeline ? ({
|
||||
@@ -213,6 +312,9 @@ export function M4ReplayThreatVisual({
|
||||
}, [resultId]);
|
||||
if (timelineFrame.activeFrame) lastFrameRef.current = timelineFrame.activeFrame;
|
||||
const frame = timelineFrame.activeFrame ?? lastFrameRef.current;
|
||||
useEffect(() => {
|
||||
onActiveSequenceChange?.(timelineFrame.activeSequence);
|
||||
}, [onActiveSequenceChange, timelineFrame.activeSequence]);
|
||||
const lastSpatialFrameRef = useRef<{
|
||||
resultId: string;
|
||||
frame: M4ThreatTimelineFrame;
|
||||
@@ -226,16 +328,32 @@ export function M4ReplayThreatVisual({
|
||||
? lastSpatialFrameRef.current.frame
|
||||
: null;
|
||||
const cameraPointOverlay = useM4ThreatCameraPointOverlay({
|
||||
enabled: showMediaPoints,
|
||||
enabled: showReferenceMediaLayers && showMediaPoints,
|
||||
resultId,
|
||||
sequence: frame?.sequence ?? null,
|
||||
endpointRoot: timelineEndpointRoot,
|
||||
});
|
||||
const semanticSpatialResultId = activeSemantic
|
||||
? activeSemantic.spatialResultId === undefined
|
||||
? activeSemantic.resultId
|
||||
: activeSemantic.spatialResultId
|
||||
: null;
|
||||
const spatialSemanticTaxonomy = useMemo<readonly E47SemanticClass[]>(
|
||||
() => semanticSpatialResultId && activeSemantic
|
||||
? activeSemantic.taxonomy.map((item) => ({
|
||||
classId: item.classId,
|
||||
label: item.label,
|
||||
disposition: item.disposition === "ambiguous" ? "ambiguous" : "labeled",
|
||||
colorRgb: item.colorRgb,
|
||||
}))
|
||||
: [],
|
||||
[activeSemantic, semanticSpatialResultId],
|
||||
);
|
||||
const semanticTimeline = useE47SemanticTimelineFrame({
|
||||
resultId: semantic?.resultId ?? null,
|
||||
resultId: semanticSpatialResultId,
|
||||
activeSequence: frame?.sequence ?? timelineFrame.activeSequence,
|
||||
frameCount: metadata.timeline?.frameCount ?? 0,
|
||||
taxonomy: semantic?.taxonomy ?? [],
|
||||
taxonomy: spatialSemanticTaxonomy,
|
||||
});
|
||||
const displayingBufferedFrame = Boolean(
|
||||
frame
|
||||
@@ -262,7 +380,7 @@ export function M4ReplayThreatVisual({
|
||||
}, [metadata.timeline, resultId, reviewAnchorIdentity, reviewAnchors, seekPlayback, setPlaybackPlaying]);
|
||||
const reviewAnchorBoxes = useMemo<readonly RecordedEvidenceBox[]>(() => {
|
||||
const timeline = metadata.timeline;
|
||||
if (!frame || !timeline) return [];
|
||||
if (!frame || !timeline || !showReviewAnchorBoxes) return [];
|
||||
return reviewAnchors
|
||||
.filter((anchor) => anchor.sourceSequence === frame.sequence)
|
||||
.map((anchor) => {
|
||||
@@ -281,27 +399,49 @@ export function M4ReplayThreatVisual({
|
||||
dashed: true,
|
||||
};
|
||||
});
|
||||
}, [frame, metadata.timeline, reviewAnchors]);
|
||||
}, [frame, metadata.timeline, reviewAnchors, showReviewAnchorBoxes]);
|
||||
const staticObstacleBoxes = useMemo<readonly RecordedEvidenceBox[]>(() => {
|
||||
const timeline = metadata.timeline;
|
||||
if (
|
||||
!showReferenceMediaLayers
|
||||
|| !frame
|
||||
|| !timeline?.cameraObstacleProjectionDelivery
|
||||
|| !showStaticObstacles
|
||||
) return [];
|
||||
return buildM4StaticObstacleBoxes(
|
||||
frame.metricObstacles,
|
||||
timeline.imageWidth,
|
||||
timeline.imageHeight,
|
||||
);
|
||||
}, [frame, metadata.timeline, showReferenceMediaLayers, showStaticObstacles]);
|
||||
const activeBoxes = useMemo(
|
||||
() => [...boxes(frame?.cameraProposals ?? []), ...reviewAnchorBoxes],
|
||||
[frame, reviewAnchorBoxes],
|
||||
() => !showReferenceMediaLayers ? [] : [
|
||||
...boxes(frame?.cameraProposals ?? []),
|
||||
...staticObstacleBoxes,
|
||||
...reviewAnchorBoxes,
|
||||
],
|
||||
[frame, reviewAnchorBoxes, showReferenceMediaLayers, staticObstacleBoxes],
|
||||
);
|
||||
const semanticClasses = useMemo<readonly RecordedEvidenceSemanticClass[]>(
|
||||
() => semantic?.taxonomy.map((item) => ({
|
||||
() => activeSemantic?.taxonomy.map((item) => ({
|
||||
id: item.classId,
|
||||
label: `semantic: ${item.label}`,
|
||||
})) ?? [],
|
||||
[semantic?.taxonomy],
|
||||
[activeSemantic?.taxonomy],
|
||||
);
|
||||
const semanticPalette = useMemo<readonly RecordedEvidenceSemanticPaletteEntry[]>(
|
||||
() => semantic?.taxonomy.map((item) => ({
|
||||
() => activeSemantic?.taxonomy.map((item) => ({
|
||||
classId: item.classId,
|
||||
color: item.disposition === "ambiguous"
|
||||
color: item.disposition === "undefined"
|
||||
? { kind: "transparent" as const }
|
||||
: item.disposition === "ambiguous"
|
||||
? { kind: "token" as const, token: "--nodedc-warning-rgb" as const }
|
||||
: { kind: "diagnostic" as const, rgb: item.colorRgb },
|
||||
opacity: item.disposition === "ambiguous" ? 0.52 : 0.92,
|
||||
opacity: item.disposition === "undefined"
|
||||
? 0
|
||||
: item.disposition === "ambiguous" ? 0.52 : 0.92,
|
||||
})) ?? [],
|
||||
[semantic?.taxonomy],
|
||||
[activeSemantic?.taxonomy],
|
||||
);
|
||||
const semanticFrame = semanticTimeline.activeFrame?.sequence === frame?.sequence
|
||||
? semanticTimeline.activeFrame
|
||||
@@ -319,7 +459,7 @@ export function M4ReplayThreatVisual({
|
||||
&& lastSpatialSemanticFrameRef.current.frame.sequence === spatialFrame?.sequence
|
||||
? lastSpatialSemanticFrameRef.current.frame
|
||||
: null;
|
||||
const semanticIntegrityError = semantic && spatialFrame && spatialSemanticFrame && (
|
||||
const semanticIntegrityError = activeSemantic && spatialFrame && spatialSemanticFrame && (
|
||||
spatialSemanticFrame.sourcePointCount !== spatialFrame.pointCloudSourceCount
|
||||
|| spatialFrame.pointCloudSampleCount !== spatialFrame.pointCloudSourceCount
|
||||
|| spatialFrame.pointCloudBodyXyzM.length !== spatialFrame.pointCloudSourceCount
|
||||
@@ -328,7 +468,7 @@ export function M4ReplayThreatVisual({
|
||||
: null;
|
||||
const alignedSemanticPointIds = useMemo<readonly (number | null)[] | undefined>(() => {
|
||||
if (
|
||||
!semantic
|
||||
!activeSemantic
|
||||
|| !showSpatialSemantic
|
||||
|| !spatialFrame
|
||||
|| !spatialSemanticFrame
|
||||
@@ -338,13 +478,149 @@ export function M4ReplayThreatVisual({
|
||||
const status = spatialSemanticFrame.statusCodes[index];
|
||||
return status === 2 || status === 3 ? classId : null;
|
||||
});
|
||||
}, [semantic, semanticIntegrityError, showSpatialSemantic, spatialFrame, spatialSemanticFrame]);
|
||||
}, [activeSemantic, semanticIntegrityError, showSpatialSemantic, spatialFrame, spatialSemanticFrame]);
|
||||
const activeSpatialFrame = spatialFrame?.sequence === timelineFrame.activeSequence
|
||||
? spatialFrame
|
||||
: null;
|
||||
const classifiedSpatialFrame = classifiedSpatialLayer?.frame?.sourceSequence === timelineFrame.activeSequence
|
||||
? classifiedSpatialLayer?.frame ?? null
|
||||
: null;
|
||||
const lastClassifiedSpatialFrameRef = useRef<{
|
||||
resultId: string;
|
||||
frame: M4ReplayClassifiedSpatialFrame;
|
||||
} | null>(null);
|
||||
const incomingClassifiedSpatialFrame = classifiedSpatialLayer?.frame ?? null;
|
||||
if (incomingClassifiedSpatialFrame && incomingClassifiedSpatialFrame.sampleAvailable !== false) {
|
||||
lastClassifiedSpatialFrameRef.current = { resultId, frame: incomingClassifiedSpatialFrame };
|
||||
}
|
||||
const lastAvailableClassifiedSpatialFrame = lastClassifiedSpatialFrameRef.current?.resultId === resultId
|
||||
? lastClassifiedSpatialFrameRef.current.frame
|
||||
: null;
|
||||
// `undefined !== false` is true, so the optional-chain form here used to
|
||||
// select `null` during every short chunk miss. That unmounted the WebGL
|
||||
// scene, flashed the alert state and recreated OrbitControls at the default
|
||||
// view on the next frame. Keep the last complete volume until the exact
|
||||
// classified frame is resident again.
|
||||
const displayedClassifiedSpatialFrame = classifiedSpatialFrame
|
||||
&& classifiedSpatialFrame.sampleAvailable !== false
|
||||
? classifiedSpatialFrame
|
||||
: lastAvailableClassifiedSpatialFrame ?? classifiedSpatialFrame;
|
||||
const displayedClassifiedFrameHeld = Boolean(
|
||||
classifiedSpatialFrame
|
||||
&& displayedClassifiedSpatialFrame
|
||||
&& classifiedSpatialFrame.sourceSequence !== displayedClassifiedSpatialFrame.sourceSequence,
|
||||
);
|
||||
const classifiedContextSpatialFrame = displayedClassifiedSpatialFrame
|
||||
? timelineFrame.availableFrames.find(
|
||||
(candidate) => candidate.spatialAvailable
|
||||
&& candidate.sequence === displayedClassifiedSpatialFrame.sourceSequence,
|
||||
) ?? (spatialFrame?.sequence === displayedClassifiedSpatialFrame.sourceSequence
|
||||
? spatialFrame
|
||||
: null)
|
||||
: null;
|
||||
const replaceClassifiedPointCloud = classifiedSpatialLayer?.replacePointCloud ?? true;
|
||||
const nominalSensorHeightM = metadata.timeline?.rig.nominalSensorHeightM ?? 0;
|
||||
const mapGravityLocalSensorToBodyGround = useCallback((
|
||||
point: readonly [number, number, number],
|
||||
): readonly [number, number, number] => {
|
||||
const basis = classifiedContextSpatialFrame?.bodyFrame?.basisMapFromBody;
|
||||
const rotated: readonly [number, number, number] = basis ? [
|
||||
basis[0][0] * point[0] + basis[1][0] * point[1] + basis[2][0] * point[2],
|
||||
basis[0][1] * point[0] + basis[1][1] * point[1] + basis[2][1] * point[2],
|
||||
basis[0][2] * point[0] + basis[1][2] * point[1] + basis[2][2] * point[2],
|
||||
] : point;
|
||||
// TGS evidence is translation-only map-gravity-local with the current LiDAR
|
||||
// as its origin. The metric scene uses the body ground projection as z=0.
|
||||
return [rotated[0], rotated[1], rotated[2] + nominalSensorHeightM];
|
||||
}, [classifiedContextSpatialFrame?.bodyFrame?.basisMapFromBody, nominalSensorHeightM]);
|
||||
const classifiedPointsBody = useMemo(
|
||||
() => displayedClassifiedSpatialFrame?.pointsMapGravityLocalXyzM.map(
|
||||
mapGravityLocalSensorToBodyGround,
|
||||
) ?? [],
|
||||
[displayedClassifiedSpatialFrame, mapGravityLocalSensorToBodyGround],
|
||||
);
|
||||
const classifiedCellsBody = useMemo<readonly LaboratoryMetricCellEvidence[]>(
|
||||
() => displayedClassifiedSpatialFrame?.cellsMapGravityLocal.map((cell) => {
|
||||
const body = mapGravityLocalSensorToBodyGround([
|
||||
cell.centerXyM[0],
|
||||
cell.centerXyM[1],
|
||||
0,
|
||||
]);
|
||||
const [minimumSensorRelativeZ, maximumSensorRelativeZ] = cell.zBoundsM;
|
||||
return {
|
||||
centerBodyXyM: [body[0], body[1]],
|
||||
zBoundsM: [
|
||||
minimumSensorRelativeZ === null
|
||||
? null
|
||||
: minimumSensorRelativeZ + nominalSensorHeightM,
|
||||
maximumSensorRelativeZ === null
|
||||
? null
|
||||
: maximumSensorRelativeZ + nominalSensorHeightM,
|
||||
],
|
||||
state: cell.state,
|
||||
};
|
||||
}) ?? [],
|
||||
[displayedClassifiedSpatialFrame, mapGravityLocalSensorToBodyGround, nominalSensorHeightM],
|
||||
);
|
||||
const classifiedPackedCellsBody = useMemo<LaboratoryMetricPackedCellEvidence | undefined>(() => {
|
||||
const packed = displayedClassifiedSpatialFrame?.packedCellsMapGravityLocal;
|
||||
if (!packed) return undefined;
|
||||
const cellCount = packed.stateCodes.length;
|
||||
if (packed.centersXyM.length !== cellCount * 2 || packed.zBoundsM.length !== cellCount * 2) {
|
||||
return undefined;
|
||||
}
|
||||
const centersBodyXyM = new Float32Array(cellCount * 2);
|
||||
const zBoundsM = new Float32Array(cellCount * 2);
|
||||
for (let index = 0; index < cellCount; index += 1) {
|
||||
const body = mapGravityLocalSensorToBodyGround([
|
||||
packed.centersXyM[index * 2]!,
|
||||
packed.centersXyM[index * 2 + 1]!,
|
||||
0,
|
||||
]);
|
||||
centersBodyXyM[index * 2] = body[0];
|
||||
centersBodyXyM[index * 2 + 1] = body[1];
|
||||
const minimum = packed.zBoundsM[index * 2]!;
|
||||
const maximum = packed.zBoundsM[index * 2 + 1]!;
|
||||
zBoundsM[index * 2] = Number.isFinite(minimum)
|
||||
? minimum + nominalSensorHeightM
|
||||
: Number.NaN;
|
||||
zBoundsM[index * 2 + 1] = Number.isFinite(maximum)
|
||||
? maximum + nominalSensorHeightM
|
||||
: Number.NaN;
|
||||
}
|
||||
return { centersBodyXyM, zBoundsM, stateCodes: packed.stateCodes };
|
||||
}, [displayedClassifiedSpatialFrame, mapGravityLocalSensorToBodyGround, nominalSensorHeightM]);
|
||||
const classifiedCellCounts = useMemo(() => {
|
||||
const counts = { ground: 0, occupied: 0, rejected: 0, unobserved: 0 };
|
||||
const packed = classifiedSpatialFrame?.packedCellsMapGravityLocal;
|
||||
if (packed) {
|
||||
for (const code of packed.stateCodes) {
|
||||
if (code === 1) counts.ground += 1;
|
||||
else if (code === 2) counts.occupied += 1;
|
||||
else if (code === 3) counts.rejected += 1;
|
||||
else if (code === 0) counts.unobserved += 1;
|
||||
else counts.rejected += 1;
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
for (const cell of classifiedSpatialFrame?.cellsMapGravityLocal ?? []) {
|
||||
if (cell.state === "ground-support") counts.ground += 1;
|
||||
else if (cell.state === "nonground-occupied") counts.occupied += 1;
|
||||
else if (cell.state === "unknown-rejected") counts.rejected += 1;
|
||||
else counts.unobserved += 1;
|
||||
}
|
||||
return counts;
|
||||
}, [classifiedSpatialFrame]);
|
||||
const classifiedCellCount = classifiedSpatialFrame?.packedCellsMapGravityLocal?.stateCodes.length
|
||||
?? classifiedSpatialFrame?.cellsMapGravityLocal.length
|
||||
?? 0;
|
||||
const sceneObstacles = useMemo(() => spatialFrame?.metricObstacles.map((obstacle) => ({
|
||||
id: obstacle.componentId,
|
||||
decision: obstacle.assessment.decision,
|
||||
state: obstacle.state,
|
||||
centroidBodyXyzM: obstacle.centroidBodyXyzM,
|
||||
cellCentersBodyXyzM: obstacle.cellCentersBodyXyzM,
|
||||
occupancySource: obstacle.occupancySource,
|
||||
})) ?? [], [spatialFrame]);
|
||||
const currentIncrementObstacles = spatialFrame?.metricObstacles.filter(
|
||||
(item) => item.state === "current",
|
||||
@@ -352,6 +628,10 @@ export function M4ReplayThreatVisual({
|
||||
const rollingMapObstacles = spatialFrame?.metricObstacles.filter(
|
||||
(item) => item.state === "retained",
|
||||
) ?? [];
|
||||
const lowStepObstacles = spatialFrame?.metricObstacles.filter(
|
||||
(item) => item.occupancySource !== "baseline"
|
||||
&& (item.state === "current" || item.state === "retained"),
|
||||
) ?? [];
|
||||
const nearest = spatialFrame?.metricObstacles
|
||||
.map((item) => item.assessment.closestApproachM)
|
||||
.filter((value): value is number => value !== null)
|
||||
@@ -367,17 +647,19 @@ export function M4ReplayThreatVisual({
|
||||
},
|
||||
), [metadata.timeline, spatialFrame, timelineFrame.availableFrames]);
|
||||
const semanticOverlay: RecordedEvidenceSemanticOverlay | undefined =
|
||||
semantic && showMediaSemantic && frame
|
||||
activeSemantic && showMediaSemantic && frame
|
||||
? {
|
||||
src: e47SemanticMaskUrl(semantic.resultId, frame.sequence),
|
||||
src: activeSemantic.maskUrl?.(frame.sequence)
|
||||
?? e47SemanticMaskUrl(activeSemantic.resultId, frame.sequence),
|
||||
prefetchSrcs: Array.from({ length: 12 }, (_, index) => index + 1)
|
||||
.map((offset) => frame.sequence + offset)
|
||||
.filter((sequence) => sequence < (metadata.timeline?.frameCount ?? 0))
|
||||
.map((sequence) => e47SemanticMaskUrl(semantic.resultId, sequence)),
|
||||
.map((sequence) => activeSemantic.maskUrl?.(sequence)
|
||||
?? e47SemanticMaskUrl(activeSemantic.resultId, sequence)),
|
||||
classes: semanticClasses,
|
||||
palette: semanticPalette,
|
||||
opacity: 0.9,
|
||||
ariaLabel: `E47 semantic mask frame ${frame.sequence + 1}`,
|
||||
ariaLabel: `${activeSemantic.maskAriaLabel ?? "Semantic prediction"} frame ${frame.sequence + 1}`,
|
||||
}
|
||||
: undefined;
|
||||
const accumulatedCameraPoints = cameraPointOverlay.overlay?.sequence === frame?.sequence
|
||||
@@ -447,13 +729,15 @@ export function M4ReplayThreatVisual({
|
||||
</div>
|
||||
);
|
||||
|
||||
const mediaLayerControls = semantic || metadata.timeline?.cameraPointDelivery ? (
|
||||
const mediaLayerControls = activeSemantic
|
||||
|| (showReferenceMediaLayers && metadata.timeline?.cameraPointDelivery)
|
||||
|| (showReferenceMediaLayers && metadata.timeline?.cameraObstacleProjectionDelivery) ? (
|
||||
<div
|
||||
className="m4-replay-threat-visual__pane-layer-controls"
|
||||
role="group"
|
||||
aria-label="Слои камеры и видео"
|
||||
>
|
||||
{semantic ? (
|
||||
{activeSemantic ? (
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
@@ -464,7 +748,21 @@ export function M4ReplayThreatVisual({
|
||||
SEMANTICS
|
||||
</Button>
|
||||
) : null}
|
||||
{metadata.timeline?.cameraPointDelivery ? (
|
||||
{availableSemanticLayers.length > 1 ? (
|
||||
<SegmentedControl
|
||||
value={selectedSemanticLayerId}
|
||||
items={availableSemanticLayers.map((layer, index) => ({
|
||||
value: layer.id ?? `${layer.resultId}:${index}`,
|
||||
label: layer.controlLabel ?? layer.label ?? `SEMANTIC ${index + 1}`,
|
||||
}))}
|
||||
label="Источник семантики"
|
||||
onChange={(value) => {
|
||||
setSelectedSemanticLayerId(value);
|
||||
setShowMediaSemantic(true);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{showReferenceMediaLayers && metadata.timeline?.cameraPointDelivery ? (
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
@@ -476,10 +774,68 @@ export function M4ReplayThreatVisual({
|
||||
POINTS
|
||||
</Button>
|
||||
) : null}
|
||||
{showReferenceMediaLayers && metadata.timeline?.cameraObstacleProjectionDelivery ? (
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
variant={showStaticObstacles ? "primary" : "secondary"}
|
||||
aria-pressed={showStaticObstacles}
|
||||
title="Только LOW-STEP LiDAR-препятствия с решением threat · без ручной разметки"
|
||||
onClick={() => setShowStaticObstacles((visible) => !visible)}
|
||||
>
|
||||
OBSTACLES
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
const spatialLayerControls = (
|
||||
const spatialLayerControls = classifiedSpatialLayer ? (
|
||||
<div
|
||||
className="m4-replay-threat-visual__pane-layer-controls"
|
||||
role="group"
|
||||
aria-label={`Слои ${classifiedSpatialLayer.label}`}
|
||||
>
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
variant={showCurrentIncrement ? "primary" : "secondary"}
|
||||
aria-pressed={showCurrentIncrement}
|
||||
onClick={() => setShowCurrentIncrement((visible) => !visible)}
|
||||
>
|
||||
{classifiedSpatialLayer.pointLayerLabel}
|
||||
</Button>
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
variant={showLocalSurface ? "primary" : "secondary"}
|
||||
aria-pressed={showLocalSurface}
|
||||
title="Bounded local SLAM surface · visual-derived"
|
||||
onClick={() => setShowLocalSurface((visible) => !visible)}
|
||||
>
|
||||
LOCAL SLAM
|
||||
</Button>
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
variant={showRollingMap ? "primary" : "secondary"}
|
||||
aria-pressed={showRollingMap}
|
||||
onClick={() => setShowRollingMap((visible) => !visible)}
|
||||
>
|
||||
{classifiedSpatialLayer.cellLayerLabel}
|
||||
</Button>
|
||||
{semanticSpatialResultId ? (
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
variant={showSpatialSemantic ? "primary" : "secondary"}
|
||||
aria-pressed={showSpatialSemantic}
|
||||
onClick={() => setShowSpatialSemantic((visible) => !visible)}
|
||||
>
|
||||
SEMANTICS
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className="m4-replay-threat-visual__pane-layer-controls"
|
||||
role="group"
|
||||
@@ -513,7 +869,19 @@ export function M4ReplayThreatVisual({
|
||||
>
|
||||
ROLLING
|
||||
</Button>
|
||||
{semantic ? (
|
||||
{metadata.timeline?.occupancyProvenanceDelivery ? (
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
variant={showLowStep ? "primary" : "secondary"}
|
||||
aria-pressed={showLowStep}
|
||||
title="Добавочные occupied-only компоненты low-step; без ручных рамок"
|
||||
onClick={() => setShowLowStep((visible) => !visible)}
|
||||
>
|
||||
LOW-STEP
|
||||
</Button>
|
||||
) : null}
|
||||
{semanticSpatialResultId ? (
|
||||
<Button
|
||||
size="compact"
|
||||
shape="pill"
|
||||
@@ -567,11 +935,11 @@ export function M4ReplayThreatVisual({
|
||||
<Icon name="chevron-right" size={16} />
|
||||
</IconButton>
|
||||
<Select
|
||||
label="Контрольные примеры M4.8R1"
|
||||
label={reviewLabel}
|
||||
value={String(selectedReviewAnchorIndex)}
|
||||
options={reviewAnchors.map((anchor, index) => ({
|
||||
value: String(index),
|
||||
label: `${index + 1}/${reviewAnchors.length} · кадр ${anchor.sourceSequence + 1} · ${anchor.matchedAtThreshold ? "покрыт" : "пропуск"}`,
|
||||
label: `${index + 1}/${reviewAnchors.length} · кадр ${anchor.sourceSequence + 1} · ${anchor.statusLabel ?? (anchor.matchedAtThreshold ? "покрыт" : "пропуск")}`,
|
||||
}))}
|
||||
variant="split"
|
||||
menuWidth="anchor"
|
||||
@@ -597,7 +965,11 @@ export function M4ReplayThreatVisual({
|
||||
? splitPrimarySize
|
||||
: 100;
|
||||
|
||||
const overlay = metadata.timeline && frame ? (
|
||||
const overlaySequence = timelineFrame.activeSequence ?? frame?.sequence ?? null;
|
||||
const overlaySessionSeconds = overlaySequence === null
|
||||
? null
|
||||
: (metadata.timeline?.frameTimesNs[overlaySequence] ?? 0) / 1_000_000_000;
|
||||
const overlay = metadata.timeline && overlaySequence !== null ? (
|
||||
<div
|
||||
className="l3-visual-audit__overlay m4-replay-threat-visual__overlay"
|
||||
style={{
|
||||
@@ -606,47 +978,75 @@ export function M4ReplayThreatVisual({
|
||||
>
|
||||
<div>
|
||||
<span>RAVNOVES00 · recorded realtime</span>
|
||||
<strong>frame {frame.sequence + 1}/{metadata.timeline.frameCount}</strong>
|
||||
<strong>frame {overlaySequence + 1}/{metadata.timeline.frameCount}</strong>
|
||||
<small>
|
||||
+{(frame.sessionSeconds - metadata.timeline.timelineStartSeconds).toFixed(3)} с
|
||||
+{((overlaySessionSeconds ?? metadata.timeline.timelineStartSeconds) - metadata.timeline.timelineStartSeconds).toFixed(3)} с
|
||||
· {displayingBufferedFrame
|
||||
? "держим последний кадр, следующий в буфере"
|
||||
: playbackController.playback.playing ? "воспроизведение" : "пауза / seek"}
|
||||
</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>Spatial evidence</span>
|
||||
<strong>
|
||||
{currentIncrementObstacles.length} current · {rollingMapObstacles.length} rolling
|
||||
</strong>
|
||||
<small>
|
||||
{spatialFrame
|
||||
? `${spatialFrame.pointCloudSampleCount}/${spatialFrame.pointCloudSourceCount} exact · ${localSurface.pointsBodyXyzM.length} local SLAM / ${localSurface.sourceFrameCount} frames`
|
||||
: "квалифицированный spatial frame ещё не получен"}
|
||||
{frame.worldStateAvailable
|
||||
? " · world-state delivered"
|
||||
: ` · world-state gap (${frame.terminalOutcome})`}
|
||||
{accumulatedCameraPoints
|
||||
? ` · camera points ${accumulatedCameraPoints.sampleCount}/${accumulatedCameraPoints.projectedPointCount} · causal ${accumulatedCameraPoints.windowSeconds.toFixed(1)} с / ${accumulatedCameraPoints.sourceFrameCount} frames`
|
||||
: pointCloudOverlay
|
||||
? ` · camera points ${frame.cameraProjectedSampleCount}/${frame.cameraProjectedPointCount} exact-current · накопление загружается`
|
||||
: showMediaPoints && cameraPointOverlay.error
|
||||
? " · накопленное camera cloud недоступно"
|
||||
: ""}
|
||||
{semantic && spatialSemanticFrame
|
||||
? ` · semantic L ${spatialSemanticFrame.counts.labeled} · A ${spatialSemanticFrame.counts.ambiguous} · U ${spatialSemanticFrame.counts.unprojected} · Ø ${spatialSemanticFrame.counts.absent}`
|
||||
: semantic ? " · semantic buffer" : ""}
|
||||
</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>Virtual corridor</span>
|
||||
<strong>
|
||||
{spatialFrame?.decisionCounts.threat ?? 0} threat · nearest {nearest === null ? "—" : `${nearest.toFixed(2)} м`}
|
||||
</strong>
|
||||
<small>
|
||||
{metadata.timeline.corridor.forwardLengthM} м · body {metadata.timeline.rig.lengthM}×{metadata.timeline.rig.widthM} м · REPLAY-SIMULATED
|
||||
</small>
|
||||
</div>
|
||||
{showSpatialOverlaySummary ? (
|
||||
<>
|
||||
<div>
|
||||
<span>Spatial evidence</span>
|
||||
<strong>{classifiedSpatialLayer
|
||||
? classifiedSpatialFrame
|
||||
? replaceClassifiedPointCloud
|
||||
? `${classifiedSpatialFrame.pointsMapGravityLocalXyzM.length.toLocaleString("ru-RU")} TGS points · ${classifiedCellCount.toLocaleString("ru-RU")} cells`
|
||||
: `${(activeSpatialFrame?.pointCloudSourceCount ?? classifiedSpatialFrame.sourcePointCount ?? 0).toLocaleString("ru-RU")} source points · ${classifiedCellCount.toLocaleString("ru-RU")} TGS cells`
|
||||
: "TGS spatial buffer"
|
||||
: `${currentIncrementObstacles.length} current · ${rollingMapObstacles.length} rolling${metadata.timeline.occupancyProvenanceDelivery ? ` · ${lowStepObstacles.length} low-step` : ""}`}</strong>
|
||||
<small>{classifiedSpatialLayer
|
||||
? classifiedSpatialFrame
|
||||
? classifiedSpatialFrame.sampleAvailable === false
|
||||
? displayedClassifiedFrameHeld && displayedClassifiedSpatialFrame
|
||||
? `LiDAR отсутствует · current UNOBSERVED · объёмный контекст удержан с frame ${displayedClassifiedSpatialFrame.sourceSequence + 1}`
|
||||
: "LiDAR отсутствует · все ячейки принудительно UNOBSERVED · causal rolling 1 s"
|
||||
: activeSpatialFrame
|
||||
? "map-gravity-local · all eligible points accounted · causal rolling 1 s"
|
||||
: "TGS рассчитан · linked source cloud недоступен для этого кадра"
|
||||
: classifiedSpatialLayer.error
|
||||
?? classifiedSpatialLayer.loadingLabel
|
||||
?? `Открываем ${classifiedSpatialLayer.label}`
|
||||
: (
|
||||
<>
|
||||
{spatialFrame
|
||||
? `${spatialFrame.pointCloudSampleCount}/${spatialFrame.pointCloudSourceCount} exact · ${localSurface.pointsBodyXyzM.length} local SLAM / ${localSurface.sourceFrameCount} frames`
|
||||
: "квалифицированный spatial frame ещё не получен"}
|
||||
{frame
|
||||
? frame.worldStateAvailable
|
||||
? " · world-state delivered"
|
||||
: ` · world-state gap (${frame.terminalOutcome})`
|
||||
: " · world-state frame unavailable"}
|
||||
{accumulatedCameraPoints
|
||||
? ` · camera points ${accumulatedCameraPoints.sampleCount}/${accumulatedCameraPoints.projectedPointCount} · causal ${accumulatedCameraPoints.windowSeconds.toFixed(1)} с / ${accumulatedCameraPoints.sourceFrameCount} frames`
|
||||
: pointCloudOverlay && frame
|
||||
? ` · camera points ${frame.cameraProjectedSampleCount}/${frame.cameraProjectedPointCount} exact-current · накопление загружается`
|
||||
: showMediaPoints && cameraPointOverlay.error
|
||||
? " · накопленное camera cloud недоступно"
|
||||
: ""}
|
||||
{semanticSpatialResultId && spatialSemanticFrame
|
||||
? ` · semantic L ${spatialSemanticFrame.counts.labeled} · A ${spatialSemanticFrame.counts.ambiguous} · U ${spatialSemanticFrame.counts.unprojected} · Ø ${spatialSemanticFrame.counts.absent}`
|
||||
: semanticSpatialResultId ? " · semantic buffer" : ""}
|
||||
</>
|
||||
)}</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>{classifiedSpatialLayer ? "TGS fail-closed" : "Virtual corridor"}</span>
|
||||
<strong>{classifiedSpatialLayer
|
||||
? classifiedSpatialFrame
|
||||
? `${classifiedCellCounts.occupied} occupied · ${classifiedCellCounts.rejected} rejected · ${classifiedCellCounts.unobserved} unobserved`
|
||||
: classifiedSpatialLayer.loading || displayingBufferedFrame ? "loading" : "unavailable"
|
||||
: `${spatialFrame?.decisionCounts.threat ?? 0} threat · nearest ${nearest === null ? "—" : `${nearest.toFixed(2)} м`}`}</strong>
|
||||
<small>{classifiedSpatialLayer
|
||||
? classifiedSpatialFrame
|
||||
? `${classifiedCellCounts.ground} ground-support · visual review only · navigation authority OFF`
|
||||
: "visual review only · navigation authority OFF"
|
||||
: `${metadata.timeline.corridor.forwardLengthM} м · body ${metadata.timeline.rig.lengthM}×${metadata.timeline.rig.widthM} м · REPLAY-SIMULATED`}</small>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
) : undefined;
|
||||
|
||||
@@ -673,6 +1073,7 @@ export function M4ReplayThreatVisual({
|
||||
<div
|
||||
className="m4-replay-threat-visual__pane-toolbar"
|
||||
data-pane-toolbar="media"
|
||||
data-multi-semantic={availableSemanticLayers.length > 1 ? "true" : undefined}
|
||||
>
|
||||
{mediaLayerControls}
|
||||
{mediaModeControls}
|
||||
@@ -744,26 +1145,61 @@ export function M4ReplayThreatVisual({
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{spatialFrame ? (
|
||||
<LaboratoryMetricEvidenceScene
|
||||
ref={metricSceneRef}
|
||||
pointCloudBodyXyzM={spatialFrame.pointCloudBodyXyzM}
|
||||
localSurfaceBodyXyzM={localSurface.pointsBodyXyzM}
|
||||
obstacles={sceneObstacles}
|
||||
rig={timeline.rig}
|
||||
corridor={timeline.corridor}
|
||||
occupiedVoxelSizeM={timeline.occupiedVoxelSizeM}
|
||||
mode={spatialMode}
|
||||
label={`${evidenceLabel} exact current increment, bounded local SLAM surface and rolling occupancy`}
|
||||
showCurrentIncrement={showCurrentIncrement}
|
||||
showLocalSurface={showLocalSurface}
|
||||
showRollingMap={showRollingMap}
|
||||
pointSemanticClassIds={alignedSemanticPointIds}
|
||||
semanticClasses={semanticClasses}
|
||||
semanticPalette={semanticPalette}
|
||||
/>
|
||||
<LaboratoryMetricEvidenceScene
|
||||
ref={metricSceneRef}
|
||||
pointCloudBodyXyzM={displayedClassifiedSpatialFrame && replaceClassifiedPointCloud
|
||||
? classifiedPointsBody
|
||||
: classifiedContextSpatialFrame?.pointCloudBodyXyzM ?? []}
|
||||
localSurfaceBodyXyzM={localSurface.pointsBodyXyzM}
|
||||
obstacles={classifiedSpatialLayer ? [] : sceneObstacles}
|
||||
rig={timeline.rig}
|
||||
corridor={timeline.corridor}
|
||||
occupiedVoxelSizeM={displayedClassifiedSpatialFrame?.cellSizeM ?? timeline.occupiedVoxelSizeM}
|
||||
mode={spatialMode}
|
||||
label={`${evidenceLabel} exact current increment, bounded local SLAM surface and rolling occupancy`}
|
||||
showCurrentIncrement={showCurrentIncrement}
|
||||
showLocalSurface={showLocalSurface}
|
||||
showRollingMap={showRollingMap}
|
||||
showLowStep={classifiedSpatialLayer ? false : showLowStep}
|
||||
pointSemanticClassIds={displayedClassifiedSpatialFrame && replaceClassifiedPointCloud
|
||||
? displayedClassifiedSpatialFrame.pointClassIds
|
||||
: alignedSemanticPointIds}
|
||||
semanticClasses={displayedClassifiedSpatialFrame && replaceClassifiedPointCloud
|
||||
? displayedClassifiedSpatialFrame.classes
|
||||
: semanticClasses}
|
||||
semanticPalette={displayedClassifiedSpatialFrame && replaceClassifiedPointCloud
|
||||
? displayedClassifiedSpatialFrame.palette
|
||||
: semanticPalette}
|
||||
classifiedCells={classifiedCellsBody}
|
||||
classifiedPackedCells={classifiedPackedCellsBody}
|
||||
classifiedCellSizeM={displayedClassifiedSpatialFrame?.cellSizeM}
|
||||
showClassifiedCells={showRollingMap}
|
||||
/>
|
||||
{classifiedSpatialLayer && !displayedClassifiedSpatialFrame ? (
|
||||
<div className="l3-visual-audit__state" role={classifiedSpatialLayer.error ? "alert" : "status"}>
|
||||
{classifiedSpatialLayer.loading || displayingBufferedFrame
|
||||
? <span className="busy-indicator" aria-hidden="true" />
|
||||
: <Icon name="alert" size={18} />}
|
||||
<span>{classifiedSpatialLayer.error
|
||||
?? (classifiedSpatialLayer.loading || displayingBufferedFrame
|
||||
? classifiedSpatialLayer.loadingLabel ?? `Открываем ${classifiedSpatialLayer.label}`
|
||||
: classifiedSpatialLayer.expectedAtSequence
|
||||
? `Открываем ${classifiedSpatialLayer.label}`
|
||||
: `${classifiedSpatialLayer.label} рассчитан только на 10 контрольных кадров.`)}</span>
|
||||
</div>
|
||||
) : null}
|
||||
{frame && !frame.spatialAvailable ? (
|
||||
{classifiedSpatialFrame?.sampleAvailable === false ? (
|
||||
<div className="m4-replay-threat-visual__pane-status" role="status">
|
||||
Кадр {classifiedSpatialFrame.sourceSequence + 1}: LiDAR отсутствует; current safety — все {classifiedCellCount.toLocaleString("ru-RU")} TGS-ячейки UNOBSERVED
|
||||
{displayedClassifiedFrameHeld && displayedClassifiedSpatialFrame
|
||||
? `; для ориентации удержан последний объёмный контекст кадра ${displayedClassifiedSpatialFrame.sourceSequence + 1}.`
|
||||
: "."}
|
||||
</div>
|
||||
) : classifiedSpatialFrame && !activeSpatialFrame ? (
|
||||
<div className="m4-replay-threat-visual__pane-status" role="status">
|
||||
Кадр {classifiedSpatialFrame.sourceSequence + 1}: TGS costmap показан cell-only; linked source cloud для отрисовки отсутствует.
|
||||
</div>
|
||||
) : frame && !frame.spatialAvailable ? (
|
||||
<div className="m4-replay-threat-visual__pane-status" role="status">
|
||||
{spatialFrame
|
||||
? `На кадре ${frame.sequence + 1} нет body frame; держим spatial evidence кадра ${spatialFrame.sequence + 1}.`
|
||||
@@ -798,7 +1234,7 @@ export function M4ReplayThreatVisual({
|
||||
{timelineFrame.loading || displayingBufferedFrame ? (
|
||||
<div className="m4-replay-threat-visual__buffering" role="status">
|
||||
<span className="busy-indicator" aria-hidden="true" />
|
||||
<span>Догружаем следующий spatial-буфер без сброса сцены</span>
|
||||
<span>{timelineFrame.loadingLabel ?? "Догружаем следующий spatial-буфер без сброса сцены"}</span>
|
||||
</div>
|
||||
) : null}
|
||||
{timelineFrame.error ? (
|
||||
@@ -807,13 +1243,13 @@ export function M4ReplayThreatVisual({
|
||||
<span>{timelineFrame.error}</span>
|
||||
</div>
|
||||
) : null}
|
||||
{semantic && semanticTimeline.loading ? (
|
||||
{semanticSpatialResultId && semanticTimeline.loading ? (
|
||||
<div className="m4-replay-threat-visual__buffering" role="status">
|
||||
<span className="busy-indicator" aria-hidden="true" />
|
||||
<span>Догружаем semantic-point evidence E47</span>
|
||||
</div>
|
||||
) : null}
|
||||
{semanticTimeline.error ? (
|
||||
{semanticSpatialResultId && semanticTimeline.error ? (
|
||||
<div className="m4-replay-threat-visual__buffering" role="alert">
|
||||
<Icon name="alert" size={16} />
|
||||
<span>{semanticTimeline.error}</span>
|
||||
@@ -854,8 +1290,8 @@ export function M4ReplayThreatVisual({
|
||||
return (
|
||||
<div className="l3-visual-audit m4-replay-threat-visual">
|
||||
<LaboratoryEvidenceViewer
|
||||
label={semantic
|
||||
? "E47 semantic + SLAM diagnostic replay"
|
||||
label={activeSemantic
|
||||
? activeSemantic.label ?? "Semantic diagnostic replay"
|
||||
: `${evidenceLabel} recorded-realtime replay`}
|
||||
className="m4-replay-threat-evidence-viewer"
|
||||
mode={mediaMode ?? "none"}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import type { VegetationShadowResult } from "../../core/laboratory/vegetationShadow";
|
||||
import {
|
||||
M48MaskComparisonVisual,
|
||||
type M48MaskComparisonCase,
|
||||
} from "./M48FailureAtlasVisual";
|
||||
|
||||
function decimal(value: number, digits = 1): string {
|
||||
return value.toLocaleString("ru-RU", { maximumFractionDigits: digits });
|
||||
}
|
||||
|
||||
const VEGETATION_LABELS: Readonly<Record<string, string>> = {
|
||||
high_grass: "Высокая трава",
|
||||
low_grass: "Низкая трава",
|
||||
bush: "Куст",
|
||||
tree_trunk: "Ствол дерева",
|
||||
tree_crown: "Крона дерева",
|
||||
hedge: "Живая изгородь",
|
||||
forest: "Лесная растительность",
|
||||
crops: "Посевы",
|
||||
};
|
||||
|
||||
function comparisonCases(result: VegetationShadowResult): readonly M48MaskComparisonCase[] {
|
||||
return result.validationCases.map((item) => {
|
||||
const focus = item.focus!;
|
||||
return {
|
||||
caseId: item.caseId,
|
||||
title: `${VEGETATION_LABELS[focus.className] ?? focus.className} · truth ${decimal(focus.truthFraction * 100, 1)}% кадра`,
|
||||
sourceUrl: item.assets.source,
|
||||
truthUrl: item.assets.truth,
|
||||
predictions: {
|
||||
ddrnet: item.assets.ddrnet,
|
||||
ppliteseg: item.assets.ppliteseg,
|
||||
},
|
||||
errors: {
|
||||
ddrnet: item.assets.ddrnet_error,
|
||||
ppliteseg: item.assets.ppliteseg_error,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function VegetationBenchmarkResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: VegetationShadowResult;
|
||||
}) {
|
||||
const selected = result.candidates.find(
|
||||
(candidate) => candidate.candidate === result.selectedCandidate,
|
||||
)!;
|
||||
const alternative = result.candidates.find(
|
||||
(candidate) => candidate.candidate !== result.selectedCandidate,
|
||||
)!;
|
||||
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.8 · архивный benchmark растительности"
|
||||
description="Отдельный truth-backed контур GOOSE для сравнения готовых fine-64 весов. Он не является частью RAVNOVES00 realtime LAB и открывается автономно без Worker 006."
|
||||
status="ARCHIVE ANALYSIS · model qualification only · commands OFF"
|
||||
statusTone="warning"
|
||||
facts={[
|
||||
{ label: "Источник", value: "GOOSE validation · 962 размеченных кадра · 12 hard cases" },
|
||||
{ label: "Сравнение", value: "DDRNet-39 vs PPLiteSeg · official fine-64 weights" },
|
||||
{ label: "Кейсы", value: "трава · куст · ствол · крона · изгородь · лес · посевы" },
|
||||
{ label: "Authority", value: `${rigLabel} · MODEL QUALIFICATION ONLY · commands OFF` },
|
||||
]}
|
||||
brief={{
|
||||
question: "Какие готовые веса лучше различают проезжаемую траву, кусты и стволы на размеченных off-road кадрах?",
|
||||
approach: "Обе модели прогнаны на 962 кадрах, а 12 визуальных кейсов выбраны детерминированно по truth-поддержке восьми растительных классов. Viewer показывает source, ручной truth, prediction и error.",
|
||||
principalResult: `${selected.loadedModelName} лидирует по vegetation IoU: ${decimal(selected.vegetationMeanIouPercent, 2)}% против ${decimal(alternative.vegetationMeanIouPercent, 2)}%.`,
|
||||
limitation: "GOOSE — внешний размеченный домен. Результат выбирает стартовые веса, но не доказывает качество на fisheye RAVNOVES00 и не даёт navigation authority.",
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "ai-inference",
|
||||
pipelineId: "goose-fine64-ready-weights-benchmark-archive/v1",
|
||||
components: result.candidates.map((candidate) => ({
|
||||
kind: "model" as const,
|
||||
name: candidate.loadedModelName,
|
||||
version: candidate.candidate,
|
||||
role: candidate.candidate === result.selectedCandidate
|
||||
? "selected vegetation candidate"
|
||||
: "comparison candidate",
|
||||
identitySha256: candidate.checkpointSha256,
|
||||
})),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.8 · GOOSE VEGETATION HARD CASES"
|
||||
title="TRUTH — ручная разметка · PREDICTION — ответ модели · ERROR — расхождение"
|
||||
kind="diagnostic-model"
|
||||
resizable
|
||||
>
|
||||
<M48MaskComparisonVisual
|
||||
cases={comparisonCases(result)}
|
||||
initialCandidate={result.selectedCandidate}
|
||||
/>
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="DDRNet выбран как стартовый vegetation candidate"
|
||||
status={`${selected.loadedModelName} · перенос на ровер не доказан`}
|
||||
statusTone="warning"
|
||||
metrics={[
|
||||
{
|
||||
label: "GOOSE mIoU",
|
||||
value: `${decimal(selected.meanIouPercent, 2)}% / ${decimal(alternative.meanIouPercent, 2)}%`,
|
||||
hint: `${selected.candidate} / ${alternative.candidate} · полный validation split`,
|
||||
},
|
||||
{
|
||||
label: "Vegetation IoU",
|
||||
value: `${decimal(selected.vegetationMeanIouPercent, 2)}% / ${decimal(alternative.vegetationMeanIouPercent, 2)}%`,
|
||||
hint: "grass/vegetation/bush/tree и родственные fine-64 labels",
|
||||
},
|
||||
{
|
||||
label: "Worker shadow p95",
|
||||
value: `${decimal(selected.shadowLatencyP95Ms, 2)} / ${decimal(alternative.shadowLatencyP95Ms, 2)} ms`,
|
||||
hint: "чистый inference · одна тяжёлая модель за раз",
|
||||
},
|
||||
{
|
||||
label: "Peak VRAM",
|
||||
value: `${decimal(selected.peakReservedVramBytes / 1024 ** 3, 2)} / ${decimal(alternative.peakReservedVramBytes / 1024 ** 3, 2)} GiB`,
|
||||
hint: `${selected.candidate} / ${alternative.candidate} · RTX 4090`,
|
||||
},
|
||||
]}
|
||||
conclusion={{
|
||||
proved: "Обе готовые fine-64 модели воспроизводимо запускаются; DDRNet лучше по aggregate vegetation IoU.",
|
||||
notProved: "Не доказаны accuracy на нашем fisheye, temporal stability, collision safety и физическое поведение ровера.",
|
||||
decision: "Хранить как архив квалификации весов. Проверку на RAVNOVES00 вести только в основной многослойной LAB.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,580 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Icon, IconButton, StatusBadge } from "@nodedc/ui-react";
|
||||
|
||||
import { LaboratoryEvidenceViewer } from "../../components/laboratory/LaboratoryEvidenceViewer";
|
||||
import { LaboratoryRecordedClipPlayer } from "../../components/laboratory/LaboratoryRecordedClipPlayer";
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import {
|
||||
RecordedEvidenceSemanticMaskOverlay,
|
||||
type RecordedEvidenceSemanticClass,
|
||||
type RecordedEvidenceSemanticPaletteEntry,
|
||||
} from "../../components/laboratory/RecordedEvidenceSemanticMaskOverlay";
|
||||
import {
|
||||
vegetationFullRouteMaskUrl,
|
||||
vegetationVideoMaskUrl,
|
||||
type VegetationFullRouteLayer,
|
||||
type VegetationFullRouteReview,
|
||||
type VegetationMixedRouteReview,
|
||||
type VegetationShadowResult,
|
||||
} from "../../core/laboratory/vegetationShadow";
|
||||
import { recordedObservationSources } from "../../core/observation/recordedObservationSources";
|
||||
import { resolveObservationSessionReplay } from "../../core/observation/useObservationSessions";
|
||||
import type { ObservationSourceDescriptor } from "../../core/runtime/contracts";
|
||||
import {
|
||||
fetchM49TgsFullShadowResult,
|
||||
type M49TgsFullShadowResult,
|
||||
} from "../../core/laboratory/m49TgsFullShadow";
|
||||
import { M4ReplayThreatVisual } from "./M4ReplayThreatVisual";
|
||||
import { M49TgsFullShadowEvidence } from "./M49TgsFullShadowEvidence";
|
||||
|
||||
function decimal(value: number, digits = 1): string {
|
||||
return value.toLocaleString("ru-RU", { maximumFractionDigits: digits });
|
||||
}
|
||||
|
||||
const MIXED_ROUTE_MODES = [
|
||||
{ value: "source", label: "SOURCE" },
|
||||
{ value: "city", label: "ГОРОД · EoMT" },
|
||||
{ value: "vegetation", label: "ПРИРОДА · DDRNet" },
|
||||
{ value: "tgs", label: "TGS" },
|
||||
] as const;
|
||||
|
||||
const FULL_ROUTE_MODES = [
|
||||
{ value: "source", label: "SOURCE" },
|
||||
{ value: "city", label: "ГОРОД · EoMT" },
|
||||
{ value: "vegetation", label: "ПРИРОДА · DDRNet" },
|
||||
] as const;
|
||||
|
||||
function semanticPresentation(layer: VegetationFullRouteLayer): {
|
||||
classes: readonly RecordedEvidenceSemanticClass[];
|
||||
palette: readonly RecordedEvidenceSemanticPaletteEntry[];
|
||||
} {
|
||||
return {
|
||||
classes: layer.taxonomy.map((item) => ({ id: item.classId, label: item.label })),
|
||||
palette: layer.taxonomy.map((item) => ({
|
||||
classId: item.classId,
|
||||
color: item.classId === 0
|
||||
? { kind: "transparent" as const }
|
||||
: { kind: "diagnostic" as const, rgb: item.colorRgb },
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
function FullRouteReviewEvidence({
|
||||
resultId,
|
||||
review,
|
||||
}: {
|
||||
resultId: string;
|
||||
review: VegetationFullRouteReview;
|
||||
}) {
|
||||
const [sequence, setSequence] = useState(1);
|
||||
const [playing, setPlaying] = useState(false);
|
||||
const [playbackRate, setPlaybackRate] = useState(1);
|
||||
const [mode, setMode] = useState<typeof FULL_ROUTE_MODES[number]["value"]>("vegetation");
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [videoSource, setVideoSource] = useState<ObservationSourceDescriptor | null>(null);
|
||||
const [videoError, setVideoError] = useState<string | null>(null);
|
||||
const frames = useMemo(
|
||||
() => review.frameSourceTimesNs.map((sourceTimeNs, index) => ({
|
||||
sequence: index + 1,
|
||||
sourceTimeNs,
|
||||
})),
|
||||
[review.frameSourceTimesNs],
|
||||
);
|
||||
const layer = mode === "source" ? null : review[mode];
|
||||
const semantic = useMemo(() => layer ? semanticPresentation(layer) : null, [layer]);
|
||||
const maskSequence = sequence - 1;
|
||||
const prefetchSrcs = useMemo(() => layer
|
||||
? Array.from({ length: 8 }, (_, offset) => maskSequence + offset + 1)
|
||||
.filter((candidate) => candidate < review.frameCount)
|
||||
.map((candidate) => vegetationFullRouteMaskUrl(resultId, mode as "city" | "vegetation", candidate))
|
||||
: [], [layer, maskSequence, mode, resultId, review.frameCount]);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
setVideoSource(null);
|
||||
setVideoError(null);
|
||||
void resolveObservationSessionReplay(review.sessionId, { signal: controller.signal })
|
||||
.then((launch) => {
|
||||
const source = recordedObservationSources(launch).find((candidate) => (
|
||||
candidate.id === review.recordedMediaSourceId
|
||||
&& candidate.modality === "video"
|
||||
&& candidate.semanticChannelId === "camera.video.recorded"
|
||||
&& candidate.delivery?.kind === "recorded-fmp4-manifest"
|
||||
&& candidate.delivery.manifestGenerationSha256 === review.recordedMediaGenerationSha256
|
||||
&& candidate.delivery.timelineStartSeconds === review.timelineStartSeconds
|
||||
&& candidate.delivery.timelineEndSeconds >= review.timelineEndSeconds
|
||||
));
|
||||
if (!source) {
|
||||
throw new Error("RIGHT-видео не совпало с sealed RAVNOVES004TREE timeline.");
|
||||
}
|
||||
if (!controller.signal.aborted) setVideoSource(source);
|
||||
})
|
||||
.catch((caught: unknown) => {
|
||||
if (!controller.signal.aborted) {
|
||||
setVideoError(caught instanceof Error ? caught.message : "Записанное видео недоступно.");
|
||||
}
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [
|
||||
review.recordedMediaGenerationSha256,
|
||||
review.recordedMediaSourceId,
|
||||
review.sessionId,
|
||||
review.timelineEndSeconds,
|
||||
review.timelineStartSeconds,
|
||||
]);
|
||||
|
||||
return (
|
||||
<LaboratoryEvidenceViewer
|
||||
label="RAVNOVES004TREE full recorded review"
|
||||
className="m48-atlas-visual"
|
||||
mode={mode}
|
||||
modes={FULL_ROUTE_MODES}
|
||||
expanded={expanded}
|
||||
onModeChange={setMode}
|
||||
onExpandedChange={setExpanded}
|
||||
chromeLayout="stacked"
|
||||
>
|
||||
{videoSource ? (
|
||||
<LaboratoryRecordedClipPlayer
|
||||
source={videoSource}
|
||||
segmentCount={review.frameCount}
|
||||
frames={frames}
|
||||
sequence={sequence}
|
||||
playing={playing}
|
||||
playbackRate={playbackRate}
|
||||
cameraPresentation="primary"
|
||||
continuousPlayback
|
||||
sourceCount={1}
|
||||
onSequenceChange={setSequence}
|
||||
onPlayingChange={setPlaying}
|
||||
onPlaybackRateChange={setPlaybackRate}
|
||||
cameraOverlay={(
|
||||
<>
|
||||
<div className="m48-clip-player__pane-label" data-pane="camera">
|
||||
{mode === "source" ? "SOURCE" : `${mode === "city" ? "EoMT CITY" : "DDRNet NATURE"} · КАДР ${sequence}/${review.frameCount}`}
|
||||
</div>
|
||||
{layer && semantic ? (
|
||||
<div className="m48-clip-player__overlay">
|
||||
<RecordedEvidenceSemanticMaskOverlay
|
||||
src={vegetationFullRouteMaskUrl(resultId, mode as "city" | "vegetation", maskSequence)}
|
||||
prefetchSrcs={prefetchSrcs}
|
||||
imageWidth={review.width}
|
||||
imageHeight={review.height}
|
||||
classes={semantic.classes}
|
||||
palette={semantic.palette}
|
||||
opacity={0.76}
|
||||
ariaLabel={`${layer.name} semantic prediction`}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<div className="m4-replay-threat-visual__pane-status" role={videoError ? "alert" : "status"}>
|
||||
{videoError ?? "Открываем автономный recorded source…"}
|
||||
</div>
|
||||
)}
|
||||
</LaboratoryEvidenceViewer>
|
||||
);
|
||||
}
|
||||
|
||||
function FullRouteReviewResult({
|
||||
rigLabel,
|
||||
resultId,
|
||||
review,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
resultId: string;
|
||||
review: VegetationFullRouteReview;
|
||||
}) {
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="LAB V1 · RAVNOVES004TREE · полный маршрут"
|
||||
description="Существующий M4.7-шаблон воспроизводит всю запись и переключает два независимых sealed semantic-слоя: городской EoMT и природный DDRNet. Worker для открытия результата не нужен."
|
||||
status="FULL RECORDED REVIEW · truth отсутствует · commands OFF"
|
||||
statusTone="warning"
|
||||
facts={[
|
||||
{ label: "Источник", value: `${review.sourceId} · ${review.frameCount}/${review.frameCount} frames` },
|
||||
{ label: "Город", value: `${review.city.name} · ${decimal(review.city.inferenceFps, 2)} fps` },
|
||||
{ label: "Природа", value: `${review.vegetation.name} · ${decimal(review.vegetation.inferenceFps, 2)} fps` },
|
||||
{ label: "Authority", value: `${rigLabel} · VISUAL REVIEW ONLY · commands OFF` },
|
||||
]}
|
||||
brief={{
|
||||
question: "Как оба semantic-кандидата ведут себя на полном переходе от сельской среды к городской?",
|
||||
approach: "Все 6830 позиции одной recorded timeline последовательно прогнаны на Worker 006 и сохранены двумя независимыми архивами масок. В M4.7 переключается только видимый слой.",
|
||||
principalResult: "Полная временная шкала доступна локально в SOURCE / EoMT CITY / DDRNet NATURE без обращения к Worker.",
|
||||
limitation: "Ручной truth отсутствует. Один повреждённый H.264-пакет на позиции 6092 представлен предыдущим декодированным кадром и явно зафиксирован в proof. Полный TGS и кюветы этим прогоном не проверялись.",
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "ai-inference",
|
||||
pipelineId: "ravnoves004tree-full-eomt-ddrnet-recorded-review/v1",
|
||||
components: [
|
||||
{ kind: "model", name: review.city.name, version: "sealed Worker 006 run", role: "urban semantic review", identitySha256: null },
|
||||
{ kind: "model", name: review.vegetation.name, version: "GOOSE DDRNet-39", role: "vegetation semantic review", identitySha256: null },
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.7 TEMPLATE · RAVNOVES004TREE FULL VIDEO"
|
||||
title="SOURCE / EoMT CITY / DDRNet NATURE · 6830/6830 · TRUTH отсутствует"
|
||||
kind="diagnostic-model"
|
||||
resizable
|
||||
>
|
||||
<FullRouteReviewEvidence resultId={resultId} review={review} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Полный двухслойный visual review собран; управление не авторизовано"
|
||||
status="Recorded evidence ready · navigation/actuation OFF"
|
||||
statusTone="warning"
|
||||
metrics={[
|
||||
{ label: "Route masks", value: "6830/6830 × 2", hint: "sealed local archives · Worker не требуется" },
|
||||
{ label: "EoMT p95", value: `${decimal(review.city.latencyP95Ms, 2)} ms`, hint: "последовательный изолированный прогон" },
|
||||
{ label: "DDRNet p95", value: `${decimal(review.vegetation.latencyP95Ms, 2)} ms`, hint: "последовательный изолированный прогон" },
|
||||
{ label: "Decode repair", value: "1/6830", hint: "sequence 6092 · previous frame · sealed proof" },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: "Городской EoMT и природный DDRNet воспроизводимо обработали полную запись и доступны в одном существующем M4.7 viewer.",
|
||||
notProved: "Не доказаны truth accuracy, одновременный realtime-load, полный TGS, отрицательные препятствия и безопасное управление ровером.",
|
||||
decision: "Использовать результат только как визуальную диагностику. Navigation/actuation оставить OFF; следующий gate — оценка временной стабильности и независимый person/vehicle STOP.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function MixedRouteReviewEvidence({ review }: { review: VegetationMixedRouteReview }) {
|
||||
const [index, setIndex] = useState(0);
|
||||
const [mode, setMode] = useState<typeof MIXED_ROUTE_MODES[number]["value"]>("vegetation");
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const item = review.cases[index]!;
|
||||
return (
|
||||
<LaboratoryEvidenceViewer
|
||||
label="RAVNOVES004TREE mixed route review"
|
||||
className="m48-atlas-visual"
|
||||
mode={mode}
|
||||
modes={MIXED_ROUTE_MODES}
|
||||
expanded={expanded}
|
||||
onModeChange={setMode}
|
||||
onExpandedChange={setExpanded}
|
||||
chromeLayout="stacked"
|
||||
actions={(
|
||||
<>
|
||||
<IconButton label="Предыдущая сцена" onClick={() => setIndex((index - 1 + review.cases.length) % review.cases.length)}>
|
||||
<Icon name="chevron-left" size={16} />
|
||||
</IconButton>
|
||||
<IconButton label="Следующая сцена" onClick={() => setIndex((index + 1) % review.cases.length)}>
|
||||
<Icon name="chevron-right" size={16} />
|
||||
</IconButton>
|
||||
</>
|
||||
)}
|
||||
overlay={(
|
||||
<div className="m48-atlas-visual__case">
|
||||
<StatusBadge tone={item.phase === "urban" ? "accent" : item.phase === "transition" ? "warning" : "neutral"}>
|
||||
{item.phase.toUpperCase()} · {index + 1}/{review.cases.length}
|
||||
</StatusBadge>
|
||||
<strong>sequence {item.sourceSequence} · +{decimal(item.sessionSeconds, 2)} s</strong>
|
||||
<small>
|
||||
TGS: {item.tgs.groundCells} ground · {item.tgs.occupiedCells} occupied · {item.tgs.unobservedCells} unobserved
|
||||
</small>
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className="recorded-evidence-image-scene">
|
||||
<img src={item.assets[mode]} alt="" draggable={false} />
|
||||
</div>
|
||||
</LaboratoryEvidenceViewer>
|
||||
);
|
||||
}
|
||||
|
||||
function MixedRouteReviewResult({
|
||||
rigLabel,
|
||||
review,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
review: VegetationMixedRouteReview;
|
||||
}) {
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="LAB V1 · RAVNOVES004TREE · село → город"
|
||||
description="Существующий LAB-шаблон показывает 10 синхронных camera/LiDAR сцен одной записи. EoMT и DDRNet остаются независимыми слоями; TGS показывает отдельную геометрию и не может быть очищен семантической маской."
|
||||
status="BOUNDED RECORDED REVIEW · truth отсутствует · commands OFF"
|
||||
statusTone="warning"
|
||||
facts={[
|
||||
{ label: "Источник", value: `${review.sourceId} · ${review.frameCount} camera/LiDAR islands` },
|
||||
{ label: "Переход", value: "5 rural · 1 transition · 4 urban" },
|
||||
{ label: "Слои", value: "SOURCE · EoMT CITY · DDRNet VEGETATION · causal TGS" },
|
||||
{ label: "Authority", value: `${rigLabel} · VISUAL REVIEW ONLY · commands OFF` },
|
||||
]}
|
||||
brief={{
|
||||
question: "Сохраняются ли городская семантика, растительность и геометрия при переходе из сельской среды в город?",
|
||||
approach: "Выбраны десять соседних с исходными сцен camera-кадров, каждый синхронизирован с LiDAR в пределах 100 мс. Все три вычислительных слоя прогнаны на Worker 006 и запечатаны локально.",
|
||||
principalResult: "Все 10 сцен обработаны EoMT, DDRNet и causal TGS. Слои можно переключать без наложения цветов и без зависимости LAB от воркера.",
|
||||
limitation: "Это bounded islands без ручной truth. DDRNet шумит по подтипам растительности; TGS не доказывает обнаружение кювета или отрицательного препятствия.",
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "ai-inference",
|
||||
pipelineId: "ravnoves004tree-eomt-ddrnet-causal-tgs-review/v1",
|
||||
components: [
|
||||
{ kind: "model", name: review.models.city.name, version: "sealed Worker run", role: "urban semantic review", identitySha256: null },
|
||||
{ kind: "model", name: review.models.vegetation.name, version: "GOOSE DDRNet-39", role: "vegetation semantic review", identitySha256: null },
|
||||
{ kind: "algorithm", name: review.models.tgs.name, version: "TRAVEL compatibility runner", role: "independent local geometry", identitySha256: null },
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.7 TEMPLATE · RAVNOVES004TREE"
|
||||
title="SOURCE / ГОРОД / ПРИРОДА / TGS · 10/10 · TRUTH отсутствует"
|
||||
kind="diagnostic-model"
|
||||
resizable
|
||||
>
|
||||
<MixedRouteReviewEvidence review={review} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Переход село → город воспроизведён; safety gate не закрыт"
|
||||
status="Review ready · navigation/actuation OFF"
|
||||
statusTone="warning"
|
||||
metrics={[
|
||||
{ label: "Aligned scenes", value: "10/10", hint: "camera + LiDAR + pose · автономный archive" },
|
||||
{ label: "EoMT end-to-end p95", value: `${decimal(review.models.city.endToEndP95Ms, 2)} ms`, hint: `${decimal(review.models.city.inferenceFps, 2)} fps в изолированном прогоне` },
|
||||
{ label: "DDRNet inference p95", value: `${decimal(review.models.vegetation.latencyP95Ms, 2)} ms`, hint: "candidate review · не совместный realtime stack" },
|
||||
{ label: "TGS p95", value: `${decimal(review.models.tgs.latencyP95Ms, 2)} ms`, hint: `${review.models.tgs.cellSizeM} m cells · ${review.models.tgs.radiusM} m radius` },
|
||||
]}
|
||||
conclusion={{
|
||||
proved: "Оба semantic слоя и causal TGS воспроизводимо работают на сельской, переходной и городской части новой записи.",
|
||||
notProved: "Не доказаны accuracy без truth, временная стабильность по всему видео, детект кюветов и безопасное совместное realtime-управление ровером.",
|
||||
decision: "Оставить navigation/actuation OFF. Следующий короткий gate — непрерывный realtime-load двух моделей плюс независимый person/vehicle STOP; кюветы проверять отдельной записью.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function VegetationRouteEvidence({ result }: { result: VegetationShadowResult }) {
|
||||
const route = result.routeVideo!;
|
||||
const [tgs, setTgs] = useState<M49TgsFullShadowResult | null>(null);
|
||||
const [tgsError, setTgsError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
setTgs(null);
|
||||
setTgsError(null);
|
||||
if (!route.linkedTgsResultId) return () => controller.abort();
|
||||
void fetchM49TgsFullShadowResult(route.linkedTgsResultId, {
|
||||
signal: controller.signal,
|
||||
}).then((next) => {
|
||||
if (controller.signal.aborted) return;
|
||||
if (next.source.linkedVisualResultId !== route.baseM4ResultId) {
|
||||
throw new Error("TGS и camera timeline имеют разные source identities.");
|
||||
}
|
||||
setTgs(next);
|
||||
}).catch((caught: unknown) => {
|
||||
if (!controller.signal.aborted) {
|
||||
setTgsError(caught instanceof Error ? caught.message : "Sealed TGS недоступен.");
|
||||
}
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [route.baseM4ResultId, route.linkedTgsResultId]);
|
||||
|
||||
const semantic = {
|
||||
id: "vegetation",
|
||||
controlLabel: "ПРИРОДА · DDRNet",
|
||||
resultId: route.workerResultId,
|
||||
spatialResultId: null,
|
||||
taxonomy: route.taxonomy,
|
||||
maskUrl: (sequence: number) => vegetationVideoMaskUrl(result.resultId, sequence),
|
||||
label: "DDRNet coarse vegetation material · recorded video",
|
||||
maskAriaLabel: "DDRNet vegetation material prediction",
|
||||
} as const;
|
||||
|
||||
if (route.linkedTgsResultId && tgs) {
|
||||
return (
|
||||
<M49TgsFullShadowEvidence
|
||||
result={tgs}
|
||||
semanticOverride={semantic}
|
||||
evidenceLabel="LAB V1 · EoMT + DDRNet + YOLOX + TGS"
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (route.linkedTgsResultId && !tgsError) {
|
||||
return (
|
||||
<div className="m4-replay-threat-visual__pane-status" role="status">
|
||||
Открываем sealed EoMT, TGS и coarse vegetation timeline…
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<M4ReplayThreatVisual
|
||||
resultId={route.baseM4ResultId}
|
||||
evidenceLabel="LAB V1 · DDRNet"
|
||||
showReferenceMediaLayers
|
||||
showSpatialOverlaySummary={false}
|
||||
semantic={semantic}
|
||||
/>
|
||||
{tgsError ? (
|
||||
<div className="m4-replay-threat-visual__pane-status" role="alert">
|
||||
TGS слой недоступен: {tgsError}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function VegetationShadowResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: VegetationShadowResult;
|
||||
}) {
|
||||
if (result.routeFullReview) {
|
||||
return (
|
||||
<FullRouteReviewResult
|
||||
rigLabel={rigLabel}
|
||||
resultId={result.resultId}
|
||||
review={result.routeFullReview}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (result.routeReview) {
|
||||
return <MixedRouteReviewResult rigLabel={rigLabel} review={result.routeReview} />;
|
||||
}
|
||||
const route = result.routeVideo;
|
||||
const selected = result.candidates.find(
|
||||
(candidate) => candidate.candidate === result.selectedCandidate,
|
||||
)!;
|
||||
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="LAB V1 · карта ровера · город + растительность"
|
||||
description="Один recorded-контур RAVNOVES00 синхронно показывает городской EoMT, природный DDRNet, frozen YOLOX detections и causal TGS. Семантические маски переключаются, чтобы их цвета не скрывали друг друга; геометрическое veto остаётся независимым."
|
||||
status={route
|
||||
? "MULTILAYER RECORDED REVIEW · commands OFF · route truth отсутствует"
|
||||
: "ROUTE EVIDENCE MISSING · commands OFF"}
|
||||
statusTone="warning"
|
||||
facts={[
|
||||
{ label: "Источник", value: "RAVNOVES00 · sensor.camera.right · 4489 recorded frames" },
|
||||
{ label: "Город", value: "EoMT Cityscapes · sealed E47 semantic archive" },
|
||||
{ label: "Растительность", value: "DDRNet-39 fine-64 → coarse mission-neutral materials" },
|
||||
{ label: "Safety", value: "YOLOX object boxes + causal TGS · semantic masks не снимают veto" },
|
||||
{ label: "Authority", value: `${rigLabel} · VISUAL REVIEW ONLY · commands OFF` },
|
||||
]}
|
||||
brief={{
|
||||
question: "Можно ли одновременно видеть городской и природный semantic stack, не теряя независимую геометрическую защиту?",
|
||||
approach: "EoMT и DDRNet сохранены как два независимых sealed слоя на одной M4 timeline. В штатном M4.7 viewer пользователь переключает только отображаемую маску; YOLOX и TGS остаются активными слоями evidence.",
|
||||
principalResult: route
|
||||
? "Оба semantic archive доступны в одном viewer. Это не пиксельный fusion и не единая новая модель: городской и природный ответы остаются раздельными."
|
||||
: "Route archive для этой immutable identity отсутствует.",
|
||||
limitation: "RAVNOVES00 не имеет ручной truth. DDRNet заметно прыгает между HIGH GRASS, WOODY и UNKNOWN; поэтому subtype нельзя подавать напрямую в planner. Отсутствие класса никогда не означает свободный путь.",
|
||||
}}
|
||||
method={{
|
||||
completeness: route ? "complete" : "legacy-partial",
|
||||
executionClass: "ai-inference",
|
||||
pipelineId: "ravnoves-eomt-ddrnet-yolox-causal-tgs-recorded-review/v1",
|
||||
components: [
|
||||
{
|
||||
kind: "model",
|
||||
name: "EoMT Cityscapes semantic",
|
||||
version: "sealed E47 archive",
|
||||
role: "urban semantic review",
|
||||
identitySha256: null,
|
||||
},
|
||||
{
|
||||
kind: "model",
|
||||
name: selected.loadedModelName,
|
||||
version: selected.candidate,
|
||||
role: "vegetation material candidate",
|
||||
identitySha256: selected.checkpointSha256,
|
||||
},
|
||||
{
|
||||
kind: "algorithm",
|
||||
name: "Frozen YOLOX + causal TGS",
|
||||
version: "linked M4/M4.9 archives",
|
||||
role: "independent object and geometry veto",
|
||||
identitySha256: null,
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={route ? (
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.7 · RAVNOVES00 FULL VIDEO"
|
||||
title="EoMT CITY / DDRNet VEGETATION + YOLOX + CAUSAL TGS · 4489/4489 · TRUTH отсутствует"
|
||||
kind="diagnostic-model"
|
||||
resizable
|
||||
>
|
||||
<VegetationRouteEvidence result={result} />
|
||||
</LaboratoryEvidence>
|
||||
) : (
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.7 · RAVNOVES00 FULL VIDEO"
|
||||
title="ROUTE ARCHIVE отсутствует"
|
||||
kind="diagnostic-model"
|
||||
>
|
||||
<div className="m4-replay-threat-visual__pane-status" role="alert">
|
||||
Для этой immutable identity нет полного route video evidence.
|
||||
</div>
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Многослойный visual review собран; управление не авторизовано"
|
||||
status="Semantics advisory · YOLOX/TGS veto cannot be cleared"
|
||||
statusTone="warning"
|
||||
metrics={[
|
||||
{
|
||||
label: "Route masks",
|
||||
value: route ? `${route.frameCount}/${route.frameCount}` : "0/4489",
|
||||
hint: "sealed local playback · Worker для открытия не нужен",
|
||||
},
|
||||
{
|
||||
label: "Semantic sources",
|
||||
value: route ? "2 independent layers" : "0",
|
||||
hint: "EoMT CITY / DDRNet VEGETATION · display switches, evidence does not fuse",
|
||||
},
|
||||
{
|
||||
label: "Vegetation worker p95",
|
||||
value: `${decimal(selected.shadowLatencyP95Ms, 2)} ms`,
|
||||
hint: "изолированный DDRNet inference; не совместный realtime stack",
|
||||
},
|
||||
{
|
||||
label: "Vegetation peak VRAM",
|
||||
value: `${decimal(selected.peakReservedVramBytes / 1024 ** 3, 2)} GiB`,
|
||||
hint: "DDRNet candidate на Worker 006",
|
||||
},
|
||||
]}
|
||||
conclusion={{
|
||||
proved: "На одной recorded timeline доступны городской EoMT, природный DDRNet, YOLOX detections и causal TGS; LAB автономна от Worker.",
|
||||
notProved: "Не доказаны совместный live-runtime EoMT+DDRNet, truth accuracy на fisheye, стабильные vegetation subtypes и безопасное управление ровером.",
|
||||
decision: "Использовать маски только для диагностики. Следующий qualification gate — motion-aware temporal vegetation fusion и отдельный совместный realtime load test; до него planner/actuation остаются OFF.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
+14
-14
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState, type ReactNode } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState, type ReactNode } from "react";
|
||||
|
||||
import type { L34RightYoloxTruthIslandResult } from "../../../core/laboratory/l34RightYoloxTruthIsland";
|
||||
import type { L34DResult } from "../../../core/laboratory/l34dCumulativePostprocessing";
|
||||
@@ -28,19 +28,19 @@ export function useL34AnnotationCapability({
|
||||
}): ReactNode {
|
||||
const [open, setOpen] = useState(false);
|
||||
const openWorkspace = useCallback(() => setOpen(true), []);
|
||||
const available = selectedWorkId === "l34-right-yolox-truth-island-freeze"
|
||||
&& l34Result
|
||||
? { resultId: l34Result.resultId, workflow: "assisted-candidate" as const }
|
||||
: selectedWorkId === "e46-detector-truth-island" && e46Result
|
||||
? { resultId: e46Result.resultId, workflow: "independent-blind" as const }
|
||||
: selectedWorkId === "e46a-ai-engineering-preannotation" && e46aResult
|
||||
? { resultId: e46aResult.resultId, workflow: "engineering-preannotation" as const }
|
||||
: selectedWorkId === "l34d-cumulative-postprocessing-candidate"
|
||||
&& l34dResult
|
||||
? { resultId: l34dResult.resultId, workflow: "prediction-hidden" as const }
|
||||
: selectedWorkId === "l34e-self-review-diagnostic" && l34eResult
|
||||
? { resultId: l34eResult.resultId, workflow: "adjudication" as const }
|
||||
: null;
|
||||
const available = useMemo(() => (
|
||||
selectedWorkId === "l34-right-yolox-truth-island-freeze" && l34Result
|
||||
? { resultId: l34Result.resultId, workflow: "assisted-candidate" as const }
|
||||
: selectedWorkId === "e46-detector-truth-island" && e46Result
|
||||
? { resultId: e46Result.resultId, workflow: "independent-blind" as const }
|
||||
: selectedWorkId === "e46a-ai-engineering-preannotation" && e46aResult
|
||||
? { resultId: e46aResult.resultId, workflow: "engineering-preannotation" as const }
|
||||
: selectedWorkId === "l34d-cumulative-postprocessing-candidate" && l34dResult
|
||||
? { resultId: l34dResult.resultId, workflow: "prediction-hidden" as const }
|
||||
: selectedWorkId === "l34e-self-review-diagnostic" && l34eResult
|
||||
? { resultId: l34eResult.resultId, workflow: "adjudication" as const }
|
||||
: null
|
||||
), [e46Result, e46aResult, l34Result, l34dResult, l34eResult, selectedWorkId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!available) {
|
||||
|
||||
@@ -10,6 +10,7 @@ export type LaboratoryProfileId =
|
||||
| "rig-camera-local-surface-v1"
|
||||
| "rig-track-geometry-temporal-v1"
|
||||
| "rig-ravnoves-perception-gate-v1"
|
||||
| "rig-goose-vegetation-benchmark-v1"
|
||||
| "rig-pointpillars-transfer-v1"
|
||||
| "rig-right-yolox-lidar-range-v1"
|
||||
| "rig-nvidia-ready-stack-v1"
|
||||
@@ -63,6 +64,20 @@ interface KnownWorkDefinition {
|
||||
const rig = (rigLabel: string): string => rigLabel.trim() || "Сенсорный риг";
|
||||
|
||||
const KNOWN_WORKS: Readonly<Record<Exclude<LaboratoryWorkId, `session:${string}`>, KnownWorkDefinition>> = {
|
||||
"lab-v1-vegetation-benchmark": {
|
||||
profileId: "rig-goose-vegetation-benchmark-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} · GOOSE vegetation archive`,
|
||||
experimentId: "lab-v1-vegetation-benchmark-archive",
|
||||
experimentName: "DDRNet vs PPLiteSeg · truth-backed archival comparison",
|
||||
variantName: "M4.8 · GOOSE truth · архивный анализ моделей",
|
||||
},
|
||||
"lab-v1-vegetation-shadow": {
|
||||
profileId: "rig-ravnoves-perception-gate-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} · RAVNOVES00 rover perception gate`,
|
||||
experimentId: "lab-v1-vegetation-mission-policy",
|
||||
experimentName: "RAVNOVES00 · city + vegetation + TGS review",
|
||||
variantName: "LAB V1 · EoMT + DDRNet + YOLOX + TGS · commands OFF",
|
||||
},
|
||||
"m48-object-centric-quality": {
|
||||
profileId: "rig-dual-evidence-virtual-corridor-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Camera + prediction-free spatial evidence`,
|
||||
@@ -77,6 +92,20 @@ const KNOWN_WORKS: Readonly<Record<Exclude<LaboratoryWorkId, `session:${string}`
|
||||
experimentName: "M4.8 · small static passage regression",
|
||||
variantName: "M4.8R1 · Worker 006 small-static assisted baseline",
|
||||
},
|
||||
"m48-static-occupancy-qualification": {
|
||||
profileId: "rig-dual-evidence-virtual-corridor-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Canonical Reference Graph`,
|
||||
experimentId: "m48-static-occupancy-qualification",
|
||||
experimentName: "M4.8 · conservative static occupancy qualification",
|
||||
variantName: "M4.8R2 · current/rolling + low-step occupied-only candidate",
|
||||
},
|
||||
"m48r3-static-occupancy-shadow": {
|
||||
profileId: "rig-dual-evidence-virtual-corridor-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Canonical Reference Graph`,
|
||||
experimentId: "m48r3-static-occupancy-shadow",
|
||||
experimentName: "M4.8R3 · full Worker static occupancy shadow",
|
||||
variantName: "M4.8R3 · 4 489 frames · additive low-step occupied-only",
|
||||
},
|
||||
"m48s-fixed-class-detector": {
|
||||
profileId: "rig-ravnoves-perception-gate-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · RAVNOVES00 perception gate`,
|
||||
@@ -84,6 +113,27 @@ const KNOWN_WORKS: Readonly<Record<Exclude<LaboratoryWorkId, `session:${string}`
|
||||
experimentName: "RAVNOVES00 fixed-class risk detector",
|
||||
variantName: "M4.8S · RF-DETR-L TensorRT/Triton shadow",
|
||||
},
|
||||
"m48t-risk-quality-temporal": {
|
||||
profileId: "rig-ravnoves-perception-gate-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Native raw-fisheye perception gate`,
|
||||
experimentId: "m48t-risk-quality-temporal",
|
||||
experimentName: "RF-DETR native risk review and temporal identity",
|
||||
variantName: "M4.8Q · native raw KB4 review · quality not adjudicated",
|
||||
},
|
||||
"m49-tgs-fail-closed-evidence": {
|
||||
profileId: "rig-dual-evidence-virtual-corridor-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Camera + gravity-aligned LiDAR`,
|
||||
experimentId: "m49-tgs-fail-closed-evidence",
|
||||
experimentName: "TRAVEL TGS fail-closed traversability evidence",
|
||||
variantName: "M4.9T4 · 10 anchors · causal rolling 1 s · AOS OFF",
|
||||
},
|
||||
"m49-tgs-full-shadow": {
|
||||
profileId: "rig-dual-evidence-virtual-corridor-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Camera + gravity-aligned LiDAR`,
|
||||
experimentId: "m49-tgs-full-shadow",
|
||||
experimentName: "TRAVEL TGS complete source-paced shadow",
|
||||
variantName: "M4.9T5 · 4 489 frames · causal rolling 1 s · CPU-only",
|
||||
},
|
||||
"m47-reference-graph-shadow": {
|
||||
profileId: "rig-dual-evidence-virtual-corridor-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Camera + LiDAR dual evidence`,
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
import type { RecordedEvidenceBox } from "../../components/laboratory/RecordedEvidenceVideoScene";
|
||||
import type { M4ThreatMetricVisual } from "../../core/laboratory/m4ReplayThreat";
|
||||
|
||||
const MINIMUM_BOX_SIZE_PX = 12;
|
||||
const RETAINED_CURRENT_OVERLAP_LIMIT = 0.5;
|
||||
|
||||
interface ObstacleBoxCandidate {
|
||||
readonly box: RecordedEvidenceBox;
|
||||
readonly state: M4ThreatMetricVisual["state"];
|
||||
}
|
||||
|
||||
function shortComponentId(componentId: string): string {
|
||||
const finalSegment = componentId.split(/[-_]/).pop();
|
||||
return finalSegment && /^\d+$/.test(finalSegment)
|
||||
? finalSegment
|
||||
: componentId.slice(-6).toUpperCase();
|
||||
}
|
||||
|
||||
function clamp(value: number, minimum: number, maximum: number): number {
|
||||
return Math.min(maximum, Math.max(minimum, value));
|
||||
}
|
||||
|
||||
function visibleBox(
|
||||
box: readonly [number, number, number, number],
|
||||
imageWidth: number,
|
||||
imageHeight: number,
|
||||
): readonly [number, number, number, number] | null {
|
||||
const [sourceLeft, sourceTop, sourceRight, sourceBottom] = box;
|
||||
if (
|
||||
sourceRight < 0
|
||||
|| sourceBottom < 0
|
||||
|| sourceLeft >= imageWidth
|
||||
|| sourceTop >= imageHeight
|
||||
) return null;
|
||||
const centerX = (sourceLeft + sourceRight) / 2;
|
||||
const centerY = (sourceTop + sourceBottom) / 2;
|
||||
const halfWidth = Math.max((sourceRight - sourceLeft) / 2, MINIMUM_BOX_SIZE_PX / 2);
|
||||
const halfHeight = Math.max((sourceBottom - sourceTop) / 2, MINIMUM_BOX_SIZE_PX / 2);
|
||||
const left = clamp(centerX - halfWidth, 0, imageWidth - 1);
|
||||
const top = clamp(centerY - halfHeight, 0, imageHeight - 1);
|
||||
const right = clamp(centerX + halfWidth, left + 1, imageWidth);
|
||||
const bottom = clamp(centerY + halfHeight, top + 1, imageHeight);
|
||||
return [left, top, right, bottom];
|
||||
}
|
||||
|
||||
function overlapFractionOfSmaller(
|
||||
left: readonly [number, number, number, number],
|
||||
right: readonly [number, number, number, number],
|
||||
): number {
|
||||
const intersectionWidth = Math.max(
|
||||
0,
|
||||
Math.min(left[2], right[2]) - Math.max(left[0], right[0]),
|
||||
);
|
||||
const intersectionHeight = Math.max(
|
||||
0,
|
||||
Math.min(left[3], right[3]) - Math.max(left[1], right[1]),
|
||||
);
|
||||
const intersectionArea = intersectionWidth * intersectionHeight;
|
||||
const leftArea = (left[2] - left[0]) * (left[3] - left[1]);
|
||||
const rightArea = (right[2] - right[0]) * (right[3] - right[1]);
|
||||
const smallerArea = Math.min(leftArea, rightArea);
|
||||
return smallerArea > 0 ? intersectionArea / smallerArea : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build actionable camera evidence from the same world-state shown in 3D.
|
||||
* Unknown and clear components remain in world-state, but do not compete with
|
||||
* actual corridor threats for the operator's attention.
|
||||
*/
|
||||
export function buildM4StaticObstacleBoxes(
|
||||
obstacles: readonly M4ThreatMetricVisual[],
|
||||
imageWidth: number,
|
||||
imageHeight: number,
|
||||
): readonly RecordedEvidenceBox[] {
|
||||
const candidates: ObstacleBoxCandidate[] = [];
|
||||
for (const obstacle of obstacles) {
|
||||
if (
|
||||
obstacle.occupancySource === "baseline"
|
||||
|| (obstacle.state !== "current" && obstacle.state !== "retained")
|
||||
|| obstacle.assessment.decision !== "threat"
|
||||
|| obstacle.assessment.corridorIntersection !== "intersects"
|
||||
|| obstacle.cameraProjection === null
|
||||
) continue;
|
||||
const projection = obstacle.cameraProjection;
|
||||
const boxXyxy = visibleBox(projection.bboxXyxy, imageWidth, imageHeight);
|
||||
if (!boxXyxy) continue;
|
||||
const depth = projection.nearestDepthM.toLocaleString("ru-RU", {
|
||||
maximumFractionDigits: 1,
|
||||
});
|
||||
candidates.push({
|
||||
state: obstacle.state,
|
||||
box: {
|
||||
boxXyxy,
|
||||
label: `OBS #${shortComponentId(obstacle.componentId)} · ${depth} м`,
|
||||
tone: "danger",
|
||||
dashed: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
const currentBoxes = candidates
|
||||
.filter((candidate) => candidate.state === "current")
|
||||
.map((candidate) => candidate.box.boxXyxy);
|
||||
return candidates
|
||||
.filter((candidate) => (
|
||||
candidate.state !== "retained"
|
||||
|| !currentBoxes.some((currentBox) => (
|
||||
overlapFractionOfSmaller(candidate.box.boxXyxy, currentBox)
|
||||
>= RETAINED_CURRENT_OVERLAP_LIMIT
|
||||
))
|
||||
))
|
||||
.map((candidate) => candidate.box)
|
||||
.sort((left, right) => {
|
||||
const leftArea = (left.boxXyxy[2] - left.boxXyxy[0])
|
||||
* (left.boxXyxy[3] - left.boxXyxy[1]);
|
||||
const rightArea = (right.boxXyxy[2] - right.boxXyxy[0])
|
||||
* (right.boxXyxy[3] - right.boxXyxy[1]);
|
||||
return rightArea - leftArea;
|
||||
});
|
||||
}
|
||||
@@ -18,10 +18,17 @@ function mergeResults(
|
||||
next: AdvancedLaboratoryResults,
|
||||
): AdvancedLaboratoryResults {
|
||||
return {
|
||||
vegetationBenchmark: next.vegetationBenchmark ?? current.vegetationBenchmark,
|
||||
vegetationShadow: next.vegetationShadow ?? current.vegetationShadow,
|
||||
m47Graph: next.m47Graph ?? current.m47Graph,
|
||||
m48: next.m48 ?? current.m48,
|
||||
m48SmallStatic: next.m48SmallStatic ?? current.m48SmallStatic,
|
||||
m48StaticOccupancy: next.m48StaticOccupancy ?? current.m48StaticOccupancy,
|
||||
m48r3StaticOccupancy: next.m48r3StaticOccupancy ?? current.m48r3StaticOccupancy,
|
||||
m48s: next.m48s ?? current.m48s,
|
||||
m48t: next.m48t ?? current.m48t,
|
||||
m49Tgs: next.m49Tgs ?? current.m49Tgs,
|
||||
m49TgsFull: next.m49TgsFull ?? current.m49TgsFull,
|
||||
m4Threat: next.m4Threat ?? current.m4Threat,
|
||||
l3: next.l3 ?? current.l3,
|
||||
l31: next.l31 ?? current.l31,
|
||||
@@ -116,9 +123,15 @@ export function useAdvancedLaboratoryCatalog({
|
||||
const indexedResultId = index.find((item) => item.workId === selectedWorkId)?.resultId;
|
||||
if (
|
||||
[
|
||||
"lab-v1-vegetation-benchmark",
|
||||
"lab-v1-vegetation-shadow",
|
||||
"m47-reference-graph-shadow",
|
||||
"m48-object-centric-quality",
|
||||
"m48-small-static-passage-regression",
|
||||
"m48-static-occupancy-qualification",
|
||||
"m48r3-static-occupancy-shadow",
|
||||
"m49-tgs-fail-closed-evidence",
|
||||
"m49-tgs-full-shadow",
|
||||
].includes(selectedWorkId)
|
||||
&& !indexedResultId
|
||||
) return;
|
||||
|
||||
@@ -2,10 +2,15 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import {
|
||||
fetchM4ThreatCameraPointOverlay,
|
||||
fetchM4ThreatPlaybackManifest,
|
||||
fetchM4ThreatPlaybackPointChunk,
|
||||
fetchM4ThreatTimeline,
|
||||
fetchM4ThreatTimelineChunk,
|
||||
M4_THREAT_TIMELINE_ENDPOINT_ROOT,
|
||||
selectM4ThreatTimelineSequence,
|
||||
type M4ThreatCameraPointOverlay,
|
||||
type M4ThreatPlaybackManifest,
|
||||
type M4ThreatPlaybackProgress,
|
||||
type M4ThreatTimeline,
|
||||
type M4ThreatTimelineChunk,
|
||||
type M4ThreatTimelineFrame,
|
||||
@@ -82,11 +87,48 @@ export function useM4ThreatTimelineFrame({
|
||||
() => new Map(),
|
||||
);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [playbackManifest, setPlaybackManifest] = useState<M4ThreatPlaybackManifest | null>(null);
|
||||
const [playbackProgress, setPlaybackProgress] = useState<M4ThreatPlaybackProgress>({
|
||||
phase: "manifest",
|
||||
loadedBytes: 0,
|
||||
totalBytes: 0,
|
||||
});
|
||||
const [playbackError, setPlaybackError] = useState<string | null>(null);
|
||||
const binaryPlayback = endpointRoot === undefined
|
||||
|| endpointRoot === M4_THREAT_TIMELINE_ENDPOINT_ROOT;
|
||||
const inFlight = useRef(new Map<number, AbortController>());
|
||||
const chunksRef = useRef(chunks);
|
||||
const activeChunkStartRef = useRef<number | null>(null);
|
||||
chunksRef.current = chunks;
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
setPlaybackManifest(null);
|
||||
setPlaybackError(null);
|
||||
setPlaybackProgress({ phase: "manifest", loadedBytes: 0, totalBytes: 0 });
|
||||
if (!timeline) return () => controller.abort();
|
||||
if (!binaryPlayback) {
|
||||
setPlaybackProgress({ phase: "ready", loadedBytes: 0, totalBytes: 0 });
|
||||
return () => controller.abort();
|
||||
}
|
||||
void fetchM4ThreatPlaybackManifest(resultId, {
|
||||
signal: controller.signal,
|
||||
endpointRoot,
|
||||
})
|
||||
.then((manifest) => {
|
||||
if (!controller.signal.aborted) {
|
||||
setPlaybackManifest(manifest);
|
||||
setPlaybackProgress({ phase: "ready", loadedBytes: 0, totalBytes: 0 });
|
||||
}
|
||||
})
|
||||
.catch((caught: unknown) => {
|
||||
if (!controller.signal.aborted) {
|
||||
setPlaybackError(errorMessage(caught, "Бинарный spatial playback M4.6 недоступен."));
|
||||
}
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [binaryPlayback, endpointRoot, resultId, timeline]);
|
||||
|
||||
useEffect(() => {
|
||||
for (const controller of inFlight.current.values()) controller.abort();
|
||||
inFlight.current.clear();
|
||||
@@ -116,7 +158,7 @@ export function useM4ThreatTimelineFrame({
|
||||
activeChunkStartRef.current = activeChunkStart;
|
||||
|
||||
useEffect(() => {
|
||||
if (!timeline || activeChunkStart === null) return;
|
||||
if (!timeline || activeChunkStart === null || (binaryPlayback && !playbackManifest)) return;
|
||||
const starts = m4ThreatChunkWindowStarts(
|
||||
activeChunkStart,
|
||||
chunkSize,
|
||||
@@ -127,10 +169,28 @@ export function useM4ThreatTimelineFrame({
|
||||
if (chunksRef.current.has(start) || inFlight.current.has(start)) continue;
|
||||
const controller = new AbortController();
|
||||
inFlight.current.set(start, controller);
|
||||
void fetchM4ThreatTimelineChunk(resultId, start, chunkSize, {
|
||||
signal: controller.signal,
|
||||
endpointRoot,
|
||||
})
|
||||
void (async () => {
|
||||
const playbackPointPack = binaryPlayback && playbackManifest
|
||||
? await fetchM4ThreatPlaybackPointChunk(
|
||||
playbackManifest,
|
||||
Math.floor(start / playbackManifest.chunkFrameCount),
|
||||
{
|
||||
signal: controller.signal,
|
||||
onProgress: (progress) => {
|
||||
if (!controller.signal.aborted && start === activeChunkStartRef.current) {
|
||||
setPlaybackProgress(progress);
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
: undefined;
|
||||
return fetchM4ThreatTimelineChunk(resultId, start, chunkSize, {
|
||||
signal: controller.signal,
|
||||
endpointRoot,
|
||||
cameraObstacleProjectionDelivery: timeline.cameraObstacleProjectionDelivery,
|
||||
playbackPointPack,
|
||||
});
|
||||
})()
|
||||
.then((chunk) => {
|
||||
if (controller.signal.aborted) return;
|
||||
setChunks((current) => {
|
||||
@@ -160,7 +220,7 @@ export function useM4ThreatTimelineFrame({
|
||||
// loaded first, then the next chunk is prefetched on the following render.
|
||||
break;
|
||||
}
|
||||
}, [activeChunkStart, chunkSize, chunks, endpointRoot, resultId, timeline]);
|
||||
}, [activeChunkStart, binaryPlayback, chunkSize, chunks, endpointRoot, playbackManifest, resultId, timeline]);
|
||||
|
||||
const activeFrame: M4ThreatTimelineFrame | null = useMemo(() => {
|
||||
if (activeSequence === null || activeChunkStart === null) return null;
|
||||
@@ -180,8 +240,17 @@ export function useM4ThreatTimelineFrame({
|
||||
activeSequence,
|
||||
activeFrame,
|
||||
availableFrames,
|
||||
loading: error === null && Boolean(timeline) && !activeFrame,
|
||||
error,
|
||||
loading: error === null && playbackError === null && Boolean(timeline) && !activeFrame,
|
||||
loadingLabel: !binaryPlayback
|
||||
? "Догружаем следующий spatial-буфер без сброса сцены"
|
||||
: playbackProgress.phase === "manifest"
|
||||
? "Проверяем M4 playback manifest"
|
||||
: playbackProgress.phase === "ready"
|
||||
? "Подготавливаем текущий spatial-кадр"
|
||||
: `${playbackProgress.phase === "verify" ? "Проверяем" : "Буферизуем"} текущий spatial chunk · ${playbackProgress.totalBytes > 0
|
||||
? `${Math.min(100, Math.round(playbackProgress.loadedBytes / playbackProgress.totalBytes * 100))}% · ${(playbackProgress.loadedBytes / 1_048_576).toFixed(1)} МБ`
|
||||
: "0%"}`,
|
||||
error: playbackError ?? error,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,411 @@
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
type DragEvent,
|
||||
} from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Button,
|
||||
ConfirmationModal,
|
||||
GlassSurface,
|
||||
Icon,
|
||||
StatusBadge,
|
||||
} from "@nodedc/ui-react";
|
||||
|
||||
import { SimulationCatalog } from "../../components/simulation/SimulationCatalog";
|
||||
import { SimulationProjectWindow } from "../../components/simulation/SimulationProjectWindow";
|
||||
import { SimulationViewport } from "../../components/simulation/SimulationViewport";
|
||||
import {
|
||||
createSimulationProject,
|
||||
deleteSimulationProject,
|
||||
fetchSimulationProjects,
|
||||
retrySimulationProject,
|
||||
uploadSimulationProjectSource,
|
||||
type SimulationProject,
|
||||
type SimulationProjectStatus,
|
||||
type SimulationUploadProgress,
|
||||
} from "../../core/simulation/projects";
|
||||
import {
|
||||
archiveProjectName,
|
||||
archivesFromDrop,
|
||||
hasDroppedFiles,
|
||||
} from "../../core/simulation/sourceFiles";
|
||||
|
||||
const BUILD_STATUSES = new Set<SimulationProjectStatus>(["queued", "processing", "importing"]);
|
||||
|
||||
interface BrowserUpload {
|
||||
project: SimulationProject;
|
||||
file: File;
|
||||
}
|
||||
|
||||
export function SimulationWorkspace() {
|
||||
const [projects, setProjects] = useState<SimulationProject[]>([]);
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [windowOpen, setWindowOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<SimulationProject | null>(null);
|
||||
const [deleting, setDeleting] = useState<SimulationProject | null>(null);
|
||||
const [retryingId, setRetryingId] = useState<string | null>(null);
|
||||
const [pendingUploads, setPendingUploads] = useState<BrowserUpload[]>([]);
|
||||
const [uploadProgress, setUploadProgress] = useState<Map<string, SimulationUploadProgress>>(
|
||||
() => new Map(),
|
||||
);
|
||||
const [queueError, setQueueError] = useState<string | null>(null);
|
||||
const [dropping, setDropping] = useState(false);
|
||||
const activeUploadRef = useRef<{ projectId: string; controller: AbortController } | null>(null);
|
||||
const intakeChainRef = useRef<Promise<void>>(Promise.resolve());
|
||||
const dragDepthRef = useRef(0);
|
||||
|
||||
const load = useCallback(async (signal?: AbortSignal) => {
|
||||
try {
|
||||
const next = await fetchSimulationProjects(signal);
|
||||
setProjects(next);
|
||||
setError(null);
|
||||
} catch (caught) {
|
||||
if (signal?.aborted) return;
|
||||
setError(caught instanceof Error ? caught.message : "Каталог симуляций недоступен.");
|
||||
} finally {
|
||||
if (!signal?.aborted) setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
void load(controller.signal);
|
||||
return () => controller.abort();
|
||||
}, [load]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!projects.some((project) => BUILD_STATUSES.has(project.status))) return;
|
||||
const timer = window.setInterval(() => void load(), 2_000);
|
||||
return () => window.clearInterval(timer);
|
||||
}, [load, projects]);
|
||||
|
||||
useEffect(() => {
|
||||
const next = pendingUploads[0];
|
||||
if (!next || activeUploadRef.current) return;
|
||||
const controller = new AbortController();
|
||||
activeUploadRef.current = { projectId: next.project.projectId, controller };
|
||||
void uploadSimulationProjectSource(
|
||||
next.project,
|
||||
[{ file: next.file, logicalPath: next.file.name }],
|
||||
(progress) => {
|
||||
setUploadProgress((current) => {
|
||||
const updated = new Map(current);
|
||||
updated.set(next.project.projectId, progress);
|
||||
return updated;
|
||||
});
|
||||
setProjects((current) => current.map((project) => (
|
||||
project.projectId === next.project.projectId
|
||||
? {
|
||||
...project,
|
||||
source: { ...project.source, uploadedByteLength: progress.uploadedBytes },
|
||||
}
|
||||
: project
|
||||
)));
|
||||
},
|
||||
controller.signal,
|
||||
).then((queued) => {
|
||||
setProjects((current) => current.map((project) => (
|
||||
project.projectId === queued.projectId ? queued : project
|
||||
)));
|
||||
setQueueError(null);
|
||||
}).catch((caught) => {
|
||||
if (controller.signal.aborted) return;
|
||||
setQueueError(caught instanceof Error
|
||||
? `${next.file.name}: ${caught.message}`
|
||||
: `${next.file.name}: загрузка остановлена.`);
|
||||
}).finally(() => {
|
||||
setPendingUploads((current) => current.filter(
|
||||
(item) => item.project.projectId !== next.project.projectId,
|
||||
));
|
||||
setUploadProgress((current) => {
|
||||
const updated = new Map(current);
|
||||
updated.delete(next.project.projectId);
|
||||
return updated;
|
||||
});
|
||||
activeUploadRef.current = null;
|
||||
});
|
||||
}, [pendingUploads]);
|
||||
|
||||
useEffect(() => () => activeUploadRef.current?.controller.abort(), []);
|
||||
|
||||
const selected = useMemo(
|
||||
() => projects.find((project) => project.projectId === selectedId) ?? null,
|
||||
[projects, selectedId],
|
||||
);
|
||||
|
||||
const openCreate = () => {
|
||||
setEditing(null);
|
||||
setWindowOpen(true);
|
||||
};
|
||||
|
||||
const openEdit = (project: SimulationProject) => {
|
||||
setEditing(project);
|
||||
setWindowOpen(true);
|
||||
};
|
||||
|
||||
const acceptSaved = (project: SimulationProject) => {
|
||||
const wasEditing = editing !== null;
|
||||
setProjects((current) => [project, ...current.filter((item) => item.projectId !== project.projectId)]);
|
||||
if (!wasEditing) setSelectedId(project.projectId);
|
||||
setWindowOpen(false);
|
||||
setEditing(null);
|
||||
};
|
||||
|
||||
const acceptViewerProject = useCallback((project: SimulationProject) => {
|
||||
setProjects((current) => current.map((item) => (
|
||||
item.projectId === project.projectId ? project : item
|
||||
)));
|
||||
}, []);
|
||||
|
||||
const confirmDelete = async () => {
|
||||
if (!deleting) return;
|
||||
const pending = pendingUploads.find((item) => item.project.projectId === deleting.projectId);
|
||||
if (activeUploadRef.current?.projectId === deleting.projectId) {
|
||||
activeUploadRef.current.controller.abort();
|
||||
}
|
||||
setPendingUploads((current) => current.filter(
|
||||
(item) => item.project.projectId !== deleting.projectId,
|
||||
));
|
||||
try {
|
||||
await deleteSimulationProject(deleting.projectId);
|
||||
setProjects((current) => current.filter((project) => project.projectId !== deleting.projectId));
|
||||
setUploadProgress((current) => {
|
||||
const updated = new Map(current);
|
||||
updated.delete(deleting.projectId);
|
||||
return updated;
|
||||
});
|
||||
if (selectedId === deleting.projectId) setSelectedId(null);
|
||||
setDeleting(null);
|
||||
} catch (caught) {
|
||||
if (pending) setPendingUploads((current) => [pending, ...current]);
|
||||
const message = caught instanceof Error ? caught.message : "Не удалось удалить проект.";
|
||||
setQueueError(message);
|
||||
throw caught;
|
||||
}
|
||||
};
|
||||
|
||||
const enqueueDroppedArchives = useCallback((files: File[]) => {
|
||||
intakeChainRef.current = intakeChainRef.current.then(async () => {
|
||||
for (const file of files) {
|
||||
try {
|
||||
const project = await createSimulationProject(
|
||||
archiveProjectName(file.name),
|
||||
"outdoor",
|
||||
[{ file, logicalPath: file.name }],
|
||||
);
|
||||
setProjects((current) => [
|
||||
project,
|
||||
...current.filter((item) => item.projectId !== project.projectId),
|
||||
]);
|
||||
setPendingUploads((current) => [...current, { project, file }]);
|
||||
} catch (caught) {
|
||||
setQueueError(caught instanceof Error
|
||||
? `${file.name}: ${caught.message}`
|
||||
: `${file.name}: не удалось создать проект.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleDrop = async (transfer: DataTransfer) => {
|
||||
dragDepthRef.current = 0;
|
||||
setDropping(false);
|
||||
setQueueError(null);
|
||||
try {
|
||||
enqueueDroppedArchives(await archivesFromDrop(transfer));
|
||||
} catch (caught) {
|
||||
setQueueError(caught instanceof Error ? caught.message : "Архивы не приняты.");
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragEnter = (event: DragEvent<HTMLDivElement>) => {
|
||||
if (!hasDroppedFiles(event.dataTransfer)) return;
|
||||
event.preventDefault();
|
||||
dragDepthRef.current += 1;
|
||||
setDropping(true);
|
||||
};
|
||||
|
||||
const handleDragLeave = (event: DragEvent<HTMLDivElement>) => {
|
||||
if (!hasDroppedFiles(event.dataTransfer)) return;
|
||||
event.preventDefault();
|
||||
dragDepthRef.current = Math.max(0, dragDepthRef.current - 1);
|
||||
if (dragDepthRef.current === 0) setDropping(false);
|
||||
};
|
||||
|
||||
const retry = async (project: SimulationProject) => {
|
||||
setRetryingId(project.projectId);
|
||||
setError(null);
|
||||
try {
|
||||
const queued = await retrySimulationProject(project.projectId);
|
||||
setProjects((current) => current.map((item) => (
|
||||
item.projectId === queued.projectId ? queued : item
|
||||
)));
|
||||
} catch (caught) {
|
||||
setError(caught instanceof Error ? caught.message : "Не удалось повторить сборку.");
|
||||
} finally {
|
||||
setRetryingId(null);
|
||||
}
|
||||
};
|
||||
|
||||
if (selected) {
|
||||
return (
|
||||
<div className="simulation-workspace simulation-workspace--scene">
|
||||
<header className="simulation-workspace__scene-head">
|
||||
<Button
|
||||
size="compact"
|
||||
variant="ghost"
|
||||
icon={<Icon name="chevron-left" size={16} />}
|
||||
onClick={() => setSelectedId(null)}
|
||||
>
|
||||
Все проекты
|
||||
</Button>
|
||||
<div>
|
||||
<span className="section-eyebrow">LAB / SIMULATION RUNTIME</span>
|
||||
<h2>{selected.name}</h2>
|
||||
</div>
|
||||
<StatusBadge tone={statusPresentation(selected.status).tone}>
|
||||
{statusPresentation(selected.status).label}
|
||||
</StatusBadge>
|
||||
</header>
|
||||
{selected.status === "ready" && selected.worldManifest ? (
|
||||
<SimulationViewport
|
||||
project={selected}
|
||||
onProjectChange={acceptViewerProject}
|
||||
/>
|
||||
) : (
|
||||
<GlassSurface className="simulation-workspace__processing" padding="lg">
|
||||
{selected.status === "failed" ? <Icon name="alert" size={20} /> : <ActivityIndicator label="Сборка мира" />}
|
||||
<div className="simulation-workspace__processing-copy">
|
||||
<strong>{selected.status === "failed" ? "Сборка остановлена" : "Worker 006 собирает мир"}</strong>
|
||||
<p>{error ?? selected.error ?? processingMessage(selected)}</p>
|
||||
</div>
|
||||
<div className="simulation-workspace__processing-actions">
|
||||
<StatusBadge tone={selected.status === "failed" ? "warning" : "accent"}>
|
||||
{providerStateLabel(selected.provider.state, selected.status)}
|
||||
</StatusBadge>
|
||||
{selected.status === "failed" ? (
|
||||
<Button
|
||||
size="compact"
|
||||
variant="secondary"
|
||||
disabled={retryingId === selected.projectId}
|
||||
icon={retryingId === selected.projectId
|
||||
? <ActivityIndicator size="compact" />
|
||||
: <Icon name="refresh" size={14} />}
|
||||
onClick={() => void retry(selected)}
|
||||
>
|
||||
Повторить сборку
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</GlassSurface>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="simulation-workspace"
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragOver={(event) => {
|
||||
if (!hasDroppedFiles(event.dataTransfer)) return;
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
}}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={(event) => {
|
||||
if (!hasDroppedFiles(event.dataTransfer)) return;
|
||||
event.preventDefault();
|
||||
void handleDrop(event.dataTransfer);
|
||||
}}
|
||||
>
|
||||
<header className="simulation-workspace__head">
|
||||
<div>
|
||||
<span className="section-eyebrow">ТЕСТОВЫЙ КОНТУР / СИМУЛЯЦИИ</span>
|
||||
<h2>Gaussian-миры</h2>
|
||||
<p>Каталог исходников, сборок Worker 006 и полнофункциональных интерактивных сцен.</p>
|
||||
</div>
|
||||
<Button variant="primary" icon={<Icon name="plus" size={16} />} onClick={openCreate}>
|
||||
Новый проект
|
||||
</Button>
|
||||
</header>
|
||||
|
||||
<SimulationCatalog
|
||||
projects={projects}
|
||||
uploadProgress={uploadProgress}
|
||||
loading={loading}
|
||||
loadError={error}
|
||||
queueError={queueError}
|
||||
dropping={dropping}
|
||||
onCreate={openCreate}
|
||||
onRetryLoad={() => void load()}
|
||||
onSelect={(project) => setSelectedId(project.projectId)}
|
||||
onEdit={openEdit}
|
||||
onDelete={setDeleting}
|
||||
/>
|
||||
|
||||
<SimulationProjectWindow
|
||||
open={windowOpen}
|
||||
project={editing}
|
||||
onClose={() => { if (!windowOpen) return; setWindowOpen(false); setEditing(null); }}
|
||||
onSaved={acceptSaved}
|
||||
/>
|
||||
<ConfirmationModal
|
||||
open={deleting !== null}
|
||||
title="Удалить проект симуляции?"
|
||||
description={(
|
||||
<p>
|
||||
Проект <strong>{deleting?.name}</strong>, локальные производные артефакты и job на Worker 006 будут удалены.
|
||||
</p>
|
||||
)}
|
||||
confirmLabel="Удалить проект"
|
||||
pendingLabel="Удаляем…"
|
||||
danger
|
||||
onClose={() => setDeleting(null)}
|
||||
onConfirm={confirmDelete}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function statusPresentation(status: SimulationProjectStatus): {
|
||||
label: string;
|
||||
tone: "success" | "accent" | "warning" | "neutral";
|
||||
} {
|
||||
if (status === "ready") return { label: "Визуал готов", tone: "success" };
|
||||
if (status === "failed") return { label: "Ошибка", tone: "warning" };
|
||||
if (status === "uploading") return { label: "Загрузка", tone: "neutral" };
|
||||
if (status === "importing") return { label: "Импорт", tone: "accent" };
|
||||
return { label: "Сборка", tone: "accent" };
|
||||
}
|
||||
|
||||
function processingMessage(project: SimulationProject): string {
|
||||
const progress = project.provider.progress;
|
||||
const completed = progress?.completed_steps;
|
||||
const total = progress?.total_steps;
|
||||
if (typeof completed === "number" && typeof total === "number") {
|
||||
return `Этап ${completed.toLocaleString("ru-RU")} из ${total.toLocaleString("ru-RU")}. Каталог обновляется автоматически.`;
|
||||
}
|
||||
return "Исходник подтверждён; локация и её LOD-уровни собираются в переносимом контейнере.";
|
||||
}
|
||||
|
||||
function providerStateLabel(
|
||||
state: string | null,
|
||||
projectStatus: SimulationProjectStatus,
|
||||
): string {
|
||||
if (state === "queued") return "Ожидание";
|
||||
if (state === "verifying_source") return "Проверка исходника";
|
||||
if (state === "inspecting") return "Анализ локации";
|
||||
if (state === "building_preview") return "Подготовка локации";
|
||||
if (state === "building_streamed_sog") return "Сборка LOD";
|
||||
if (state === "building_collision") return "Сборка коллизий";
|
||||
if (state === "ready") return "Визуал готов";
|
||||
if (state === "failed") return "Ошибка";
|
||||
return statusPresentation(projectStatus).label;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ let server;
|
||||
let fetchAdvancedLaboratoryResults;
|
||||
let fetchAdvancedLaboratoryIndex;
|
||||
let fetchAdvancedLaboratoryResult;
|
||||
let fetchM49TgsAnchorSpatial;
|
||||
let AdvancedLaboratoryContractError;
|
||||
let buildLaboratoryCatalog;
|
||||
let buildLaboratoryProfiles;
|
||||
@@ -836,6 +837,77 @@ function e40() {
|
||||
};
|
||||
}
|
||||
|
||||
function m49View() {
|
||||
const anchors = [171, 306, 368, 402, 450, 509, 525, 744, 1122, 1856];
|
||||
return {
|
||||
schema_version: "missioncore.m49-tgs-fail-closed-view/v1",
|
||||
result_id: `m49-tgs-fail-closed-${"2".repeat(64)}`,
|
||||
created_at_utc: "2026-08-26T17:09:43Z",
|
||||
source: {
|
||||
source_id: "RAVNOVES00",
|
||||
source_session_id: "20260720T065719Z_viewer_live",
|
||||
source_pack_sha256: "3".repeat(64),
|
||||
linked_visual_result_id: `m4-threat-replay-${"4".repeat(64)}`,
|
||||
anchor_frame_indices: anchors,
|
||||
},
|
||||
configuration: {
|
||||
profile_id: "m49-ravnoves00-tgs-fail-closed-evidence/v1",
|
||||
config_sha256: "5".repeat(64),
|
||||
coordinate_frame: "map-gravity-local",
|
||||
primary_profile: "causal_rolling_1s",
|
||||
cell_size_m: 0.45,
|
||||
radius_m: 12,
|
||||
},
|
||||
execution: {
|
||||
worker: "Worker 006",
|
||||
device: "cpu",
|
||||
gpu_used: false,
|
||||
wrapper_elapsed_seconds: 12.1,
|
||||
},
|
||||
metrics: {
|
||||
anchor_count: 10,
|
||||
anchor_profile_count: 20,
|
||||
all_eligible_points_accounted: true,
|
||||
costmap_cell_count: 2244,
|
||||
process_wall_current_p50_ms: 20,
|
||||
process_wall_current_max_ms: 30,
|
||||
process_wall_rolling_p50_ms: 30,
|
||||
process_wall_rolling_max_ms: 40,
|
||||
process_max_rss_kib: 9292,
|
||||
primary: anchors.map((anchor, slot) => ({
|
||||
anchor_frame_index: anchor,
|
||||
slot,
|
||||
profile_id: "causal_rolling_1s",
|
||||
point_count: 3,
|
||||
ground_point_count: 1,
|
||||
nonground_point_count: 1,
|
||||
rejected_point_count: 1,
|
||||
ground_cell_count: 1,
|
||||
nonground_cell_count: 1,
|
||||
rejected_cell_count: 1,
|
||||
unobserved_cell_count: 2241,
|
||||
all_points_accounted: true,
|
||||
})),
|
||||
},
|
||||
acceptance: {
|
||||
representation_complete: true,
|
||||
all_points_accounted: true,
|
||||
aos_absent: true,
|
||||
gpu_absent: true,
|
||||
visual_quality_accepted: false,
|
||||
traversability_accepted: false,
|
||||
},
|
||||
decision: {
|
||||
state: "visual-review-required",
|
||||
candidate_retained: true,
|
||||
next_action: "Review the ten anchors.",
|
||||
},
|
||||
limitations: ["bounded diagnostic evidence"],
|
||||
ground_truth: false,
|
||||
access: "read-only",
|
||||
};
|
||||
}
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
appType: "custom",
|
||||
@@ -850,6 +922,9 @@ before(async () => {
|
||||
fetchAdvancedLaboratoryIndex,
|
||||
fetchAdvancedLaboratoryResult,
|
||||
} = await server.ssrLoadModule("/src/core/laboratory/advancedIndex.ts"));
|
||||
({ fetchM49TgsAnchorSpatial } = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/m49TgsFailClosed.ts",
|
||||
));
|
||||
({
|
||||
buildLaboratoryCatalog,
|
||||
buildLaboratoryProfiles,
|
||||
@@ -1596,6 +1671,62 @@ test("selected advanced LAB fetches only its own strict catalog", async () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test("selected M49 LAB preserves the sealed fail-closed contract", async () => {
|
||||
const payload = m49View();
|
||||
const requests = [];
|
||||
const decoded = await fetchAdvancedLaboratoryResult(
|
||||
"m49-tgs-fail-closed-evidence",
|
||||
{
|
||||
resultId: payload.result_id,
|
||||
fetcher: async (input, init) => {
|
||||
requests.push({ input: String(input), method: init?.method });
|
||||
return new Response(JSON.stringify(payload), { status: 200 });
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(decoded.m49Tgs.metrics.anchorCount, 10);
|
||||
assert.equal(decoded.m49Tgs.metrics.costmapCellCount, 2244);
|
||||
assert.equal(decoded.m49Tgs.acceptance.visualQualityAccepted, false);
|
||||
assert.deepEqual(requests, [{
|
||||
input: `/api/v1/laboratory/m49/tgs-fail-closed/${payload.result_id}`,
|
||||
method: "GET",
|
||||
}]);
|
||||
});
|
||||
|
||||
test("M49 anchor fetch keeps every point and all four costmap states", async () => {
|
||||
const resultId = m49View().result_id;
|
||||
const centers = Array.from({ length: 2244 }, (_, index) => [index * 0.45, 0]);
|
||||
const states = Array.from({ length: 2244 }, (_, index) => index % 4);
|
||||
const zBounds = states.map((state) => state === 0 ? [null, null] : [0, 0.2]);
|
||||
const decoded = await fetchM49TgsAnchorSpatial(resultId, 171, "causal_rolling_1s", {
|
||||
fetcher: async () => new Response(JSON.stringify({
|
||||
schema_version: "missioncore.m49-tgs-anchor-spatial/v1",
|
||||
result_id: resultId,
|
||||
anchor_frame_index: 171,
|
||||
source_sequence: 171,
|
||||
profile: "causal_rolling_1s",
|
||||
coordinate_frame: "map-gravity-local",
|
||||
points_xyz_m: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
|
||||
point_states: [1, 2, 3],
|
||||
costmap: {
|
||||
cell_size_m: 0.45,
|
||||
radius_m: 12,
|
||||
centers_xy_m: centers,
|
||||
states,
|
||||
z_bounds_m: zBounds,
|
||||
},
|
||||
all_points_accounted: true,
|
||||
aos_used: false,
|
||||
access: "read-only",
|
||||
}), { status: 200 }),
|
||||
});
|
||||
|
||||
assert.deepEqual(decoded.pointStates, [1, 2, 3]);
|
||||
assert.equal(decoded.costmap.states.length, 2244);
|
||||
assert.deepEqual(new Set(decoded.costmap.states), new Set([0, 1, 2, 3]));
|
||||
});
|
||||
|
||||
test("keeps valid LAB catalogs available when one transport endpoint fails", async () => {
|
||||
const decoded = await fetchAdvancedLaboratoryResults({
|
||||
fetcher: async (input) => {
|
||||
|
||||
@@ -691,3 +691,18 @@ test("metric evidence keeps one WebGL renderer while frame labels advance", () =
|
||||
/querySelector\("canvas"\)[\s\S]*?setAttribute\("aria-label", label\)[\s\S]*?\}, \[label\]\);/,
|
||||
);
|
||||
});
|
||||
|
||||
test("metric evidence renders on demand while preserving damped camera interaction", () => {
|
||||
const source = readFileSync(
|
||||
new URL("../src/components/laboratory/LaboratoryMetricEvidenceScene.tsx", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
assert.match(source, /const requestRenderRef = useRef/);
|
||||
assert.match(source, /controls\.addEventListener\("change", requestRender\)/);
|
||||
assert.match(source, /requestRenderRef\.current\(\)/);
|
||||
assert.doesNotMatch(
|
||||
source,
|
||||
/const render = \(\) => \{\s*animationFrame = window\.requestAnimationFrame\(render\)/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -45,6 +45,59 @@ function resultPayload() {
|
||||
selected: false,
|
||||
...overrides,
|
||||
});
|
||||
const loadScenario = (id, loadPurpose, rate, delivered, superseded) => ({
|
||||
id,
|
||||
load_purpose: loadPurpose,
|
||||
requested_source_rate_hz: rate,
|
||||
source_frames_admitted: 4489,
|
||||
delivered_world_states: delivered,
|
||||
superseded_frames: superseded,
|
||||
delivery_ratio: delivered / 4489,
|
||||
effective_world_state_fps: rate * 0.975,
|
||||
world_state_completion_age_p95_ms: 75,
|
||||
world_state_completion_age_p99_ms: 100,
|
||||
world_state_completion_age_maximum_ms: 400,
|
||||
hot_loop_decode_p95_ms: 14,
|
||||
hot_loop_decode_maximum_ms: 42,
|
||||
preadmission_decode_maximum_ms: 3633,
|
||||
source_prefetch_preparation_maximum_ms: 4353,
|
||||
source_pacing_lateness_p95_ms: 1.7,
|
||||
source_pacing_lateness_maximum_ms: 11,
|
||||
detector_p95_ms: 40,
|
||||
detector_maximum_ms: 370,
|
||||
gpu_utilization_mean_percent: 35,
|
||||
gpu_utilization_maximum_percent: 85,
|
||||
gpu_memory_maximum_mib: 9584,
|
||||
process_peak_rss_mib: 2327,
|
||||
queue_high_watermarks: { detector: 2, geometry: 2, temporal: 2, rolling: 2, threat: 2 },
|
||||
queue_capacity: 2,
|
||||
additional_inference_passes: 0,
|
||||
repeat_count: 3,
|
||||
all_repetitions_passed: true,
|
||||
integrity_gate_passed: true,
|
||||
operating_target_gate_passed: true,
|
||||
thresholds: {
|
||||
minimum_delivery_ratio: rate === 10 ? 0.999 : rate === 12 ? 0.995 : 0.95,
|
||||
minimum_effective_world_state_fps: rate * 0.95,
|
||||
maximum_world_state_completion_p95_ms: rate === 10 ? 125 : rate === 12 ? 150 : 175,
|
||||
},
|
||||
repetitions: [1, 2, 3].map((repetition) => ({
|
||||
run_id: `m48s-load-prefetch-v1-${id}-a${repetition}`,
|
||||
repetition,
|
||||
delivered_world_states: delivered,
|
||||
superseded_frames: superseded,
|
||||
delivery_ratio: delivered / 4489,
|
||||
effective_world_state_fps: rate * 0.975,
|
||||
world_state_completion_age_p95_ms: 75,
|
||||
hot_loop_decode_p95_ms: 14,
|
||||
hot_loop_decode_maximum_ms: 42,
|
||||
preadmission_decode_maximum_ms: 3633,
|
||||
source_pacing_lateness_maximum_ms: 11,
|
||||
operating_target_gate_passed: true,
|
||||
result_sha256: "7".repeat(64),
|
||||
frame_evidence_sha256: "8".repeat(64),
|
||||
})),
|
||||
});
|
||||
return {
|
||||
schema_version: "missioncore.m48s-fixed-class-detector-result-view/v1",
|
||||
result_id: resultId,
|
||||
@@ -138,6 +191,55 @@ function resultPayload() {
|
||||
additional_inference_passes: 0,
|
||||
failures: 0,
|
||||
},
|
||||
runtime_hardening: {
|
||||
schema_version: "missioncore.m48s-runtime-hardening-comparison/v1",
|
||||
baseline: {
|
||||
source_frames_admitted: 4489,
|
||||
delivered_world_states: 4480,
|
||||
superseded_frames: 9,
|
||||
effective_world_state_fps: 9.750635,
|
||||
world_state_completion_age_p95_ms: 76.886564,
|
||||
world_state_completion_age_p99_ms: 100.661219,
|
||||
world_state_completion_age_maximum_ms: 794.748644,
|
||||
rolling_maximum_ms: 762.638263,
|
||||
geometry_maximum_ms: 350.066302,
|
||||
additional_inference_passes: 0,
|
||||
},
|
||||
hardened: {
|
||||
source_frames_admitted: 4489,
|
||||
delivered_world_states: 4488,
|
||||
superseded_frames: 1,
|
||||
effective_world_state_fps: 9.821942,
|
||||
world_state_completion_age_p95_ms: 75.270655,
|
||||
world_state_completion_age_p99_ms: 94.309605,
|
||||
world_state_completion_age_maximum_ms: 449.893287,
|
||||
rolling_maximum_ms: 28.044958,
|
||||
geometry_maximum_ms: 49.174149,
|
||||
additional_inference_passes: 0,
|
||||
},
|
||||
startup: {
|
||||
baseline: { detector_ms: 397.356888, world_state_ms: 449.893287 },
|
||||
prewarmed: { detector_ms: 27.662887, world_state_ms: 60.516957 },
|
||||
prewarm_duration_ms: 420.721918,
|
||||
prewarm_inference_passes: 1,
|
||||
validation_frames: 1000,
|
||||
},
|
||||
},
|
||||
load_envelope: {
|
||||
schema_version: "missioncore.m48s-load-envelope-comparison/v2",
|
||||
repeat_count_per_rate: 3,
|
||||
production_rate_repeatability_passed: true,
|
||||
reserve_12_fps_passed: true,
|
||||
limit_15_fps_passed: true,
|
||||
load_envelope_accepted: true,
|
||||
compute_capacity_at_least_fps: 15,
|
||||
bottleneck_interpretation: "cold-video-decode-isolated-before-admission-no-steady-gpu-saturation",
|
||||
scenarios: [
|
||||
loadScenario("production-10fps", "production-rate", 10, 4489, 0),
|
||||
loadScenario("reserve-12fps", "reserve-gate", 12, 4488, 1),
|
||||
loadScenario("limit-15fps", "limit-discovery", 15, 4488, 1),
|
||||
],
|
||||
},
|
||||
},
|
||||
decision: {
|
||||
selected_candidate: "rf-detr",
|
||||
@@ -145,6 +247,11 @@ function resultPayload() {
|
||||
integrated_world_state_gate_evaluated: true,
|
||||
integrated_world_state_gate_passed: true,
|
||||
detector_replacement_authorized: false,
|
||||
load_envelope_evaluated: true,
|
||||
production_rate_repeatability_passed: true,
|
||||
reserve_12_fps_passed: true,
|
||||
limit_15_fps_passed: true,
|
||||
load_envelope_accepted: true,
|
||||
production_accepted: false,
|
||||
},
|
||||
limitations: ["No independent semantic ground truth."],
|
||||
@@ -175,11 +282,71 @@ test("M4.8S result exposes complete graph load without production authority", as
|
||||
assert.equal(result.metrics.integratedWorldState.deliveredWorldStates, 4481);
|
||||
assert.equal(result.metrics.integratedWorldState.worldStateCompletionAgeP95Ms, 74.733648);
|
||||
assert.equal(result.metrics.integratedWorldState.additionalInferencePasses, 0);
|
||||
assert.equal(result.metrics.runtimeHardening.baseline.supersededFrames, 9);
|
||||
assert.equal(result.metrics.runtimeHardening.hardened.supersededFrames, 1);
|
||||
assert.equal(result.metrics.runtimeHardening.startup.prewarmed.worldStateMs, 60.516957);
|
||||
assert.equal(result.metrics.loadEnvelope.scenarios[0].operatingTargetGatePassed, true);
|
||||
assert.equal(result.metrics.loadEnvelope.scenarios[1].deliveredWorldStates, 4488);
|
||||
assert.equal(result.metrics.loadEnvelope.scenarios[2].repetitions.length, 3);
|
||||
assert.equal(result.metrics.loadEnvelope.scenarios[0].hotLoopDecodeP95Ms, 14);
|
||||
assert.equal(result.metrics.loadEnvelope.computeCapacityAtLeastFps, 15);
|
||||
assert.equal(result.decision.loadEnvelopeAccepted, true);
|
||||
assert.equal(result.decision.integratedWorldStateGatePassed, true);
|
||||
assert.equal(result.decision.productionAccepted, false);
|
||||
assert.equal(result.authority.navigationOrSafetyAccepted, false);
|
||||
});
|
||||
|
||||
test("M4.8S keeps the immutable v1 load-envelope result readable", async () => {
|
||||
const payload = resultPayload();
|
||||
payload.metrics.load_envelope = {
|
||||
schema_version: "missioncore.m48s-load-envelope-comparison/v1",
|
||||
production_rate_repeatability_passed: false,
|
||||
reserve_12_fps_passed: true,
|
||||
limit_15_fps_passed: true,
|
||||
load_envelope_accepted: false,
|
||||
compute_capacity_at_least_fps: 15,
|
||||
bottleneck_interpretation: "rare-source-decode-or-scheduling-tail-not-steady-gpu-saturation",
|
||||
scenarios: payload.metrics.load_envelope.scenarios.map((scenario, index) => ({
|
||||
id: scenario.id,
|
||||
load_purpose: scenario.load_purpose,
|
||||
requested_source_rate_hz: scenario.requested_source_rate_hz,
|
||||
source_frames_admitted: scenario.source_frames_admitted,
|
||||
delivered_world_states: index === 0 ? 4483 : scenario.delivered_world_states,
|
||||
superseded_frames: index === 0 ? 6 : scenario.superseded_frames,
|
||||
delivery_ratio: index === 0 ? 4483 / 4489 : scenario.delivery_ratio,
|
||||
effective_world_state_fps: scenario.effective_world_state_fps,
|
||||
world_state_completion_age_p95_ms: scenario.world_state_completion_age_p95_ms,
|
||||
world_state_completion_age_p99_ms: scenario.world_state_completion_age_p99_ms,
|
||||
world_state_completion_age_maximum_ms: scenario.world_state_completion_age_maximum_ms,
|
||||
decode_p95_ms: scenario.hot_loop_decode_p95_ms,
|
||||
decode_maximum_ms: 3200,
|
||||
detector_p95_ms: scenario.detector_p95_ms,
|
||||
detector_maximum_ms: scenario.detector_maximum_ms,
|
||||
gpu_utilization_mean_percent: scenario.gpu_utilization_mean_percent,
|
||||
gpu_utilization_maximum_percent: scenario.gpu_utilization_maximum_percent,
|
||||
gpu_memory_maximum_mib: scenario.gpu_memory_maximum_mib,
|
||||
process_peak_rss_mib: scenario.process_peak_rss_mib,
|
||||
queue_high_watermarks: scenario.queue_high_watermarks,
|
||||
queue_capacity: 2,
|
||||
additional_inference_passes: 0,
|
||||
integrity_gate_passed: true,
|
||||
operating_target_gate_passed: index !== 0,
|
||||
thresholds: scenario.thresholds,
|
||||
frame_evidence_sha256: "8".repeat(64),
|
||||
})),
|
||||
};
|
||||
payload.decision.production_rate_repeatability_passed = false;
|
||||
payload.decision.load_envelope_accepted = false;
|
||||
|
||||
const result = await fetchM48SFixedClassDetectorResult(resultId, {
|
||||
fetcher: async () => response(payload),
|
||||
});
|
||||
|
||||
assert.equal(result.metrics.loadEnvelope.repeatCountPerRate, 1);
|
||||
assert.equal(result.metrics.loadEnvelope.loadEnvelopeAccepted, false);
|
||||
assert.equal(result.metrics.loadEnvelope.scenarios[0].operatingTargetGatePassed, false);
|
||||
});
|
||||
|
||||
test("M4.8S frame binds exact camera endpoint and risk-only boxes", async () => {
|
||||
const frame = await fetchM48SFixedClassDetectorFrame(resultId, "000253", {
|
||||
fetcher: async () => response({
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { after, before, test } from "node:test";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let fetchM48TRiskQualityResult;
|
||||
|
||||
const resultId = `m48q-native-risk-quality-lab-${"a".repeat(64)}`;
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
appType: "custom",
|
||||
logLevel: "silent",
|
||||
server: { middlewareMode: true },
|
||||
});
|
||||
({ fetchM48TRiskQualityResult } = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/m48tRiskQuality.ts",
|
||||
));
|
||||
});
|
||||
|
||||
after(async () => server?.close());
|
||||
|
||||
function response(value) {
|
||||
return { ok: true, status: 200, json: async () => value };
|
||||
}
|
||||
|
||||
function payload() {
|
||||
return {
|
||||
schema_version: "missioncore.m48q-native-risk-quality-view/v1",
|
||||
variant: "native-risk-review",
|
||||
result_id: resultId,
|
||||
created_at_utc: "2026-08-26T10:00:00Z",
|
||||
status: "complete-review-ready-quality-not-adjudicated",
|
||||
access: "read-only",
|
||||
ground_truth: false,
|
||||
source: {
|
||||
source_id: "RAVNOVES00",
|
||||
frame_count: 4489,
|
||||
raster_width: 800,
|
||||
raster_height: 600,
|
||||
geometric_resampling: false,
|
||||
rectification: false,
|
||||
warp: false,
|
||||
},
|
||||
configuration: {
|
||||
candidate: {
|
||||
provider_id: "triton-rf-detr-large-coco-native-kb4-risk-fp16-shadow/v0",
|
||||
model_id: "rf_detr_large_native_kb4:1",
|
||||
preprocess_id: "raw-kb4-uint8-fused-mask-rgb-pad8-imagenet-trt/v0",
|
||||
minimum_score: 0.25,
|
||||
},
|
||||
},
|
||||
method: {
|
||||
schema_version: "missioncore.laboratory-method/v1",
|
||||
completeness: "complete",
|
||||
execution_class: "hybrid",
|
||||
pipeline_id: "m48q-native-raw-fisheye-risk-case-review/v1",
|
||||
components: [{
|
||||
kind: "model",
|
||||
name: "RF-DETR-L native KB4 TensorRT",
|
||||
version: "rf_detr_large_native_kb4:1",
|
||||
role: "risk proposals",
|
||||
identity_sha256: "b".repeat(64),
|
||||
}],
|
||||
},
|
||||
execution: {
|
||||
effective_world_state_fps: 11.84338,
|
||||
world_state_completion_p95_ms: 47.940779,
|
||||
detector_total_p95_ms: 21.19895,
|
||||
gpu_utilization_p95_percent: 53,
|
||||
gpu_memory_used_maximum_mib: 9718,
|
||||
additional_inference_passes: 0,
|
||||
},
|
||||
metrics: {
|
||||
selection: {
|
||||
case_count: 24,
|
||||
minimum_sequence_separation: 12,
|
||||
selected_bucket_coverage: { person: 22, animal: 3 },
|
||||
selected_class_counts: { person: 44, dog: 3 },
|
||||
},
|
||||
runtime: {
|
||||
delivery_ratio: 1,
|
||||
integrated_runtime_gate_passed: true,
|
||||
operating_target_gate_passed: true,
|
||||
},
|
||||
native_tensor_parity: {
|
||||
risk_detection_precision: 0.9887,
|
||||
risk_detection_recall: 0.9831,
|
||||
matched_mean_iou: 0.9882,
|
||||
},
|
||||
},
|
||||
acceptance: {
|
||||
review_ready: true,
|
||||
integrated_runtime_gate_passed: true,
|
||||
independent_quality_evaluated: false,
|
||||
semantic_candidate_accepted: false,
|
||||
},
|
||||
review: {
|
||||
source_raster: { width: 800, height: 600 },
|
||||
overlay: { client_rendered: true, toggleable: true },
|
||||
cases: Array.from({ length: 24 }, (_, index) => {
|
||||
const caseId = String(index * 20 + 12).padStart(6, "0");
|
||||
return {
|
||||
case_id: caseId,
|
||||
sequence: Number(caseId),
|
||||
frame_id: `frame-${caseId}`,
|
||||
evidence_time_ns: 35_000_000_000 + index * 1_000_000,
|
||||
image_url: `/review/${caseId}.jpg`,
|
||||
media_type: "image/jpeg",
|
||||
width: 800,
|
||||
height: 600,
|
||||
byte_length: 1000 + index,
|
||||
sha256: String(index.toString(16)).padStart(64, "0"),
|
||||
geometric_resampling: false,
|
||||
selection_buckets: [index % 2 ? "person" : "animal"],
|
||||
comparison: {
|
||||
native_detection_count: 1,
|
||||
legacy_704_detection_count: 1,
|
||||
matched_detection_count_iou_at_least_0_5: 1,
|
||||
},
|
||||
proposals: [{
|
||||
proposal_id: `proposal-${index}-0`,
|
||||
class_name: index % 2 ? "person" : "dog",
|
||||
risk_family: index % 2 ? "person" : "animal",
|
||||
score: 0.75,
|
||||
box_xyxy: [10, 20, 100, 200],
|
||||
}],
|
||||
};
|
||||
}),
|
||||
},
|
||||
limitations: ["No independent route truth."],
|
||||
};
|
||||
}
|
||||
|
||||
test("M4.8Q parser accepts only the native 800x600 no-resampling review contract", async () => {
|
||||
const result = await fetchM48TRiskQualityResult(resultId, {
|
||||
fetcher: async () => response(payload()),
|
||||
});
|
||||
|
||||
assert.equal(result.variant, "native-risk-review");
|
||||
assert.equal(result.review.cases.length, 24);
|
||||
assert.equal(result.review.cases[0].width, 800);
|
||||
assert.equal(result.review.cases[0].proposals[0].className, "dog");
|
||||
assert.equal(result.execution.additionalInferencePasses, 0);
|
||||
assert.equal(result.acceptance.independentQualityEvaluated, false);
|
||||
});
|
||||
|
||||
test("M4.8Q parser fails closed if raw-fisheye geometry is resampled", async () => {
|
||||
const invalid = payload();
|
||||
invalid.source.geometric_resampling = true;
|
||||
|
||||
await assert.rejects(
|
||||
fetchM48TRiskQualityResult(resultId, {
|
||||
fetcher: async () => response(invalid),
|
||||
}),
|
||||
/source resampling/,
|
||||
);
|
||||
});
|
||||
|
||||
test("M4.8Q reuses the canonical image scene and viewer overlay toggle", async () => {
|
||||
const source = await readFile(
|
||||
new URL("../src/workspaces/laboratory/M48TRiskQualityVisual.tsx", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
assert.match(source, /<LaboratoryEvidenceViewer/);
|
||||
assert.match(source, /<RecordedEvidenceImageScene/);
|
||||
assert.match(source, /name=\{boxesVisible \? "eye-off" : "eye"\}/);
|
||||
assert.match(source, /raw KB4 800×600 · resampling NO/);
|
||||
assert.doesNotMatch(source, /<canvas/);
|
||||
});
|
||||
@@ -0,0 +1,234 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createHash } from "node:crypto";
|
||||
import { after, before, test } from "node:test";
|
||||
|
||||
import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let M49PhysicalSafetyPlaybackBuffer;
|
||||
let fetchM49PhysicalSafetyPlaybackIdForSource;
|
||||
|
||||
const resultId = `m49-physical-safety-playback-${"a".repeat(64)}`;
|
||||
const endpoint = `/api/v1/laboratory/m49/physical-safety-playback/${resultId}`;
|
||||
const frameCount = 160;
|
||||
const cellCount = 4;
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
appType: "custom",
|
||||
logLevel: "silent",
|
||||
server: { middlewareMode: true },
|
||||
});
|
||||
({
|
||||
M49PhysicalSafetyPlaybackBuffer,
|
||||
fetchM49PhysicalSafetyPlaybackIdForSource,
|
||||
} = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/m49PhysicalSafetyPlayback.ts",
|
||||
));
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await server?.close();
|
||||
});
|
||||
|
||||
function sha256(buffer) {
|
||||
return createHash("sha256").update(Buffer.from(buffer)).digest("hex");
|
||||
}
|
||||
|
||||
function chunk(index) {
|
||||
const start = index * 32;
|
||||
const count = Math.min(32, frameCount - start);
|
||||
const stateBytes = count * cellCount;
|
||||
const zBytes = count * cellCount * 2 * 4;
|
||||
const headerBytes = 28;
|
||||
const padding = (4 - ((headerBytes + stateBytes) % 4)) % 4;
|
||||
const buffer = new ArrayBuffer(headerBytes + stateBytes + padding + zBytes);
|
||||
const bytes = new Uint8Array(buffer);
|
||||
bytes.set(new TextEncoder().encode("MCPSCH01"));
|
||||
const view = new DataView(buffer);
|
||||
view.setUint32(8, start, true);
|
||||
view.setUint32(12, count, true);
|
||||
view.setUint32(16, cellCount, true);
|
||||
view.setUint32(20, stateBytes, true);
|
||||
view.setUint32(24, zBytes, true);
|
||||
const states = new Uint8Array(buffer, headerBytes, stateBytes);
|
||||
states.fill(1);
|
||||
const z = new Float32Array(buffer, headerBytes + stateBytes + padding, count * cellCount * 2);
|
||||
for (let local = 0; local < count; local += 1) {
|
||||
const sequence = start + local;
|
||||
for (let cell = 0; cell < cellCount; cell += 1) {
|
||||
z[(local * cellCount + cell) * 2] = 0;
|
||||
z[(local * cellCount + cell) * 2 + 1] = 0.12;
|
||||
}
|
||||
if (sequence === 17) {
|
||||
states.fill(0, local * cellCount, (local + 1) * cellCount);
|
||||
z.fill(Number.NaN, local * cellCount * 2, (local + 1) * cellCount * 2);
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function fixture() {
|
||||
const centers = new Float32Array([0, 0, 0.15, 0, 0.3, 0, 0.45, 0]).buffer;
|
||||
const frames = new TextEncoder().encode(Array.from({ length: frameCount }, (_, sequence) => (
|
||||
JSON.stringify({
|
||||
source_frame_index: sequence,
|
||||
session_seconds: sequence / 10,
|
||||
sample_available: sequence !== 17,
|
||||
eligible_point_count: sequence === 17 ? 0 : cellCount,
|
||||
})
|
||||
)).join("\n") + "\n").buffer;
|
||||
const chunks = Array.from({ length: Math.ceil(frameCount / 32) }, (_, index) => chunk(index));
|
||||
const manifest = {
|
||||
schema_version: "missioncore.m49-physical-safety-playback/v1",
|
||||
result_id: resultId,
|
||||
created_at_utc: "2026-08-27T12:00:00Z",
|
||||
access: "read-only-sealed-local",
|
||||
identity: { source_result_id: `m49-tgs-full-shadow-${"b".repeat(64)}` },
|
||||
execution: {
|
||||
execution_class: "local-sequential-offline",
|
||||
worker_role: "realtime-only",
|
||||
worker_runtime_dependency: false,
|
||||
worker_requests_required: 0,
|
||||
},
|
||||
authority: {
|
||||
commands_enabled: false,
|
||||
navigation_or_safety_accepted: false,
|
||||
actuation_accepted: false,
|
||||
},
|
||||
playback: {
|
||||
coordinate_frame: "map-gravity-local",
|
||||
source_pace_hz: 10,
|
||||
frame_count: frameCount,
|
||||
cell_count: cellCount,
|
||||
cell_size_m: 0.15,
|
||||
radius_m: 12,
|
||||
state_codes: {
|
||||
UNOBSERVED: 0,
|
||||
GROUND_SUPPORT: 1,
|
||||
NONGROUND_OCCUPIED: 2,
|
||||
UNKNOWN_REJECTED: 3,
|
||||
},
|
||||
chunk_frame_count: 32,
|
||||
startup_prebuffer_chunk_count: 2,
|
||||
resident_chunk_count_max: 3,
|
||||
forward_prefetch_chunk_count: 1,
|
||||
centers: {
|
||||
url: `${endpoint}/tracks/centers`,
|
||||
media_type: "application/octet-stream",
|
||||
byte_length: centers.byteLength,
|
||||
sha256: sha256(centers),
|
||||
dtype: "<f4",
|
||||
shape: [cellCount, 2],
|
||||
},
|
||||
frames: {
|
||||
url: `${endpoint}/tracks/frames`,
|
||||
media_type: "application/x-ndjson",
|
||||
byte_length: frames.byteLength,
|
||||
sha256: sha256(frames),
|
||||
dtype: "ndjson",
|
||||
shape: [frameCount],
|
||||
},
|
||||
chunks: chunks.map((buffer, index) => ({
|
||||
index,
|
||||
start: index * 32,
|
||||
count: Math.min(32, frameCount - index * 32),
|
||||
url: `${endpoint}/chunks/${index}`,
|
||||
media_type: "application/octet-stream",
|
||||
byte_length: buffer.byteLength,
|
||||
sha256: sha256(buffer),
|
||||
header_bytes: 28,
|
||||
format: "mcpsch01-states-u8-aligned-z-bounds-f32le",
|
||||
})),
|
||||
},
|
||||
};
|
||||
const responses = new Map([
|
||||
[`${endpoint}/tracks/centers`, centers],
|
||||
[`${endpoint}/tracks/frames`, frames],
|
||||
...chunks.map((buffer, index) => [`${endpoint}/chunks/${index}`, buffer]),
|
||||
]);
|
||||
return { manifest, responses };
|
||||
}
|
||||
|
||||
test("physical-safety playback opens and seeks with bounded local chunks only", async () => {
|
||||
const { manifest, responses } = fixture();
|
||||
const requested = [];
|
||||
const progress = [];
|
||||
const fetcher = async (input) => {
|
||||
const url = String(input);
|
||||
requested.push(url);
|
||||
if (url === `${endpoint.replace(`/${resultId}`, "")}/results?limit=2&source_result_id=${manifest.identity.source_result_id}`) {
|
||||
return Response.json({
|
||||
schema_version: "missioncore.m49-physical-safety-playback-catalog/v1",
|
||||
worker_runtime_dependency: false,
|
||||
access: "read-only-sealed-local",
|
||||
items: [{
|
||||
result_id: resultId,
|
||||
source_result_id: manifest.identity.source_result_id,
|
||||
worker_runtime_dependency: false,
|
||||
navigation_or_safety_accepted: false,
|
||||
}],
|
||||
});
|
||||
}
|
||||
if (url === `${endpoint}/manifest`) {
|
||||
return Response.json(manifest);
|
||||
}
|
||||
const payload = responses.get(url);
|
||||
return payload
|
||||
? new Response(payload, { headers: { "Content-Type": "application/octet-stream" } })
|
||||
: new Response(null, { status: 404 });
|
||||
};
|
||||
|
||||
const resolvedResultId = await fetchM49PhysicalSafetyPlaybackIdForSource(
|
||||
manifest.identity.source_result_id,
|
||||
{ fetcher },
|
||||
);
|
||||
assert.equal(resolvedResultId, resultId);
|
||||
const playback = await M49PhysicalSafetyPlaybackBuffer.open(resolvedResultId, {
|
||||
fetcher,
|
||||
onProgress: (value) => progress.push(value),
|
||||
});
|
||||
|
||||
assert.deepEqual(playback.residentChunkIndexes, [0, 1]);
|
||||
assert.equal(progress.at(-1).phase, "ready");
|
||||
assert.equal(requested.some((url) => url.includes("worker")), false);
|
||||
const startupRequestCount = requested.length;
|
||||
await playback.prepare(0);
|
||||
await playback.prepare(0);
|
||||
assert.equal(requested.length, startupRequestCount);
|
||||
const missing = await playback.frame(17);
|
||||
assert.equal(missing.metadata.sampleAvailable, false);
|
||||
assert.deepEqual(new Set(missing.states), new Set([0]));
|
||||
assert.equal([...missing.zBoundsM].every((value) => Number.isNaN(value)), true);
|
||||
|
||||
await playback.prepare(100);
|
||||
assert.equal(playback.residentChunkIndexes.length <= 3, true);
|
||||
assert.equal(playback.residentChunkIndexes.includes(3), true);
|
||||
assert.equal(playback.residentChunkIndexes.includes(4), true);
|
||||
const selected = await playback.frame(100);
|
||||
assert.deepEqual([...selected.states], [1, 1, 1, 1]);
|
||||
const maximumResidentBytes = manifest.playback.centers.byte_length
|
||||
+ manifest.playback.frames.byte_length
|
||||
+ 3 * Math.max(...manifest.playback.chunks.map((value) => value.byte_length));
|
||||
assert.equal(playback.residentByteLength <= maximumResidentBytes, true);
|
||||
|
||||
await playback.prepare(0);
|
||||
assert.equal(playback.residentChunkIndexes.length <= 3, true);
|
||||
assert.equal(playback.residentChunkIndexes.includes(0), true);
|
||||
assert.equal(playback.residentChunkIndexes.includes(1), true);
|
||||
assert.equal(
|
||||
requested.every((url) => url.startsWith("/api/v1/laboratory/m49/physical-safety-playback")),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("physical-safety playback rejects a manifest that points at Worker", async () => {
|
||||
const { manifest } = fixture();
|
||||
manifest.playback.centers.url = "http://worker-006/centers";
|
||||
await assert.rejects(
|
||||
M49PhysicalSafetyPlaybackBuffer.open(resultId, {
|
||||
fetcher: async () => Response.json(manifest),
|
||||
}),
|
||||
/sealed local API/,
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,157 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { after, before, test } from "node:test";
|
||||
|
||||
import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let fetchM49TgsFullShadowSpatialChunk;
|
||||
let parseM49TgsNpyTrack;
|
||||
|
||||
const resultId = `m49-tgs-full-shadow-${"a".repeat(64)}`;
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
appType: "custom",
|
||||
logLevel: "silent",
|
||||
server: { middlewareMode: true },
|
||||
});
|
||||
({ fetchM49TgsFullShadowSpatialChunk, parseM49TgsNpyTrack } = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/m49TgsFullShadow.ts",
|
||||
));
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await server?.close();
|
||||
});
|
||||
|
||||
test("M4.9T5 chunk keeps every missing-LiDAR cell explicitly UNOBSERVED", async () => {
|
||||
let requestedUrl = "";
|
||||
const centers = Array.from({ length: 2244 }, (_, index) => [index * 0.45, 0]);
|
||||
const unobserved = Array.from({ length: 2244 }, () => 0);
|
||||
const zBounds = Array.from({ length: 2244 }, () => [null, null]);
|
||||
const metrics = {
|
||||
eligible_point_count: 0,
|
||||
ground_point_count: 0,
|
||||
nonground_point_count: 0,
|
||||
rejected_point_count: 0,
|
||||
occupied_cell_count: 0,
|
||||
};
|
||||
const chunk = await fetchM49TgsFullShadowSpatialChunk(resultId, 7, 1, {
|
||||
fetcher: async (url) => {
|
||||
requestedUrl = String(url);
|
||||
return new Response(JSON.stringify({
|
||||
schema_version: "missioncore.m49-tgs-full-shadow-spatial-chunk/v1",
|
||||
result_id: resultId,
|
||||
start: 7,
|
||||
count: 1,
|
||||
coordinate_frame: "map-gravity-local",
|
||||
costmap: {
|
||||
cell_size_m: 0.45,
|
||||
radius_m: 12,
|
||||
centers_xy_m: centers,
|
||||
},
|
||||
frames: [{
|
||||
source_sequence: 7,
|
||||
source_frame_index: 7,
|
||||
session_seconds: 36.119857292,
|
||||
sample_available: false,
|
||||
states: unobserved,
|
||||
z_bounds_m: zBounds,
|
||||
metrics,
|
||||
}],
|
||||
}), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
requestedUrl,
|
||||
`/api/v1/laboratory/m49/tgs-full-shadow/${resultId}/spatial/chunk?start=7&count=1`,
|
||||
);
|
||||
assert.equal(chunk.count, 1);
|
||||
assert.equal(chunk.frames[0].sampleAvailable, false);
|
||||
assert.equal(chunk.frames[0].costmap.states.length, 2244);
|
||||
assert.deepEqual(new Set(chunk.frames[0].costmap.states), new Set([0]));
|
||||
});
|
||||
|
||||
test("M4.9T5 viewer prefers autonomous chunks and keeps a sealed legacy fallback", async () => {
|
||||
const [source, visual, scene, contract] = await Promise.all([
|
||||
readFile(
|
||||
new URL("../src/workspaces/laboratory/M49TgsFullShadowEvidence.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
readFile(
|
||||
new URL("../src/workspaces/laboratory/M4ReplayThreatVisual.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
readFile(
|
||||
new URL("../src/components/laboratory/LaboratoryMetricEvidenceScene.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
readFile(
|
||||
new URL("../src/core/laboratory/m49TgsFullShadow.ts", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
]);
|
||||
assert.match(source, /fetchM49PhysicalSafetyPlaybackIdForSource/);
|
||||
assert.match(source, /M49PhysicalSafetyPlaybackBuffer\.open/);
|
||||
assert.match(source, /physicalPlayback\.frameIfResident/);
|
||||
assert.match(source, /physicalPlayback\.prepare/);
|
||||
assert.match(source, /fetchM49TgsFullShadowPlaybackPack/);
|
||||
assert.match(source, /playbackProgress/);
|
||||
assert.doesNotMatch(source, /fetchM49TgsFullShadowSpatialChunk/);
|
||||
assert.match(source, /sampleAvailable: frame\.sampleAvailable/);
|
||||
assert.match(source, /packedCellsMapGravityLocal/);
|
||||
assert.match(source, /playbackPack\.states\.subarray/);
|
||||
assert.match(source, /playbackPack\.zBoundsM\.subarray/);
|
||||
assert.doesNotMatch(source, /Array\.from\(\s*playbackPack\.states/);
|
||||
assert.doesNotMatch(source, /centersXyM\.map\(/);
|
||||
assert.match(source, /fetchE47SemanticSlamResult/);
|
||||
assert.match(source, /next\.baseM4ResultId !== result\.source\.linkedVisualResultId/);
|
||||
assert.match(source, /semanticLayers=\{semanticLayers\}/);
|
||||
assert.match(source, /ГОРОД · EoMT/);
|
||||
assert.match(source, /ПРИРОДА · DDRNet/);
|
||||
assert.match(source, /semanticOverride/);
|
||||
assert.doesNotMatch(source, /if \(semanticOverride\) return/);
|
||||
assert.match(visual, /label="Источник семантики"/);
|
||||
assert.match(visual, /availableSemanticLayers\.length > 1/);
|
||||
assert.doesNotMatch(visual, /classifiedSpatialLayer \|\| !showReferenceMediaLayers \? \[\]/);
|
||||
assert.match(
|
||||
visual,
|
||||
/classifiedSpatialFrame\s*&&\s*classifiedSpatialFrame\.sampleAvailable !== false/,
|
||||
);
|
||||
assert.doesNotMatch(visual, /classifiedSpatialFrame\?\.sampleAvailable !== false/);
|
||||
assert.match(visual, /timelineFrame\.availableFrames\.find/);
|
||||
assert.match(visual, /<LaboratoryMetricEvidenceScene/);
|
||||
assert.doesNotMatch(
|
||||
visual,
|
||||
/\{\(!classifiedSpatialLayer \? spatialFrame : displayedClassifiedSpatialFrame\) \? \(/,
|
||||
);
|
||||
assert.match(scene, /useEffect\(\(\) => resetView\(\), \[mode, resetView\]\)/);
|
||||
assert.match(contract, /linked_semantic_result_id/);
|
||||
assert.match(contract, /missioncore\.m49-tgs-full-shadow-playback\/v1/);
|
||||
});
|
||||
|
||||
function npyFloat32(values, shape) {
|
||||
const shapeText = shape.length === 1 ? `${shape[0]},` : shape.join(", ");
|
||||
const prefixLength = 10;
|
||||
let header = `{'descr': '<f4', 'fortran_order': False, 'shape': (${shapeText}), }`;
|
||||
const padding = (16 - ((prefixLength + header.length + 1) % 16)) % 16;
|
||||
header += " ".repeat(padding) + "\n";
|
||||
const buffer = new ArrayBuffer(prefixLength + header.length + values.length * 4);
|
||||
const bytes = new Uint8Array(buffer);
|
||||
bytes.set([0x93, 0x4e, 0x55, 0x4d, 0x50, 0x59, 1, 0]);
|
||||
new DataView(buffer).setUint16(8, header.length, true);
|
||||
bytes.set(new TextEncoder().encode(header), prefixLength);
|
||||
new Float32Array(buffer, prefixLength + header.length, values.length).set(values);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
test("M4.9T5 parses sealed NPY tracks without JSON point arrays", () => {
|
||||
const parsed = parseM49TgsNpyTrack(
|
||||
npyFloat32([1.25, -2.5, 3.75, 4.5], [2, 2]),
|
||||
"<f4",
|
||||
[2, 2],
|
||||
);
|
||||
assert.deepEqual([...parsed], [1.25, -2.5, 3.75, 4.5]);
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { after, before, test } from "node:test";
|
||||
|
||||
@@ -9,7 +10,10 @@ let fetchM4ThreatReplayResult;
|
||||
let fetchM4ThreatVisual;
|
||||
let fetchM4ThreatTimeline;
|
||||
let fetchM4ThreatTimelineChunk;
|
||||
let fetchM4ThreatPlaybackManifest;
|
||||
let fetchM4ThreatPlaybackPointChunk;
|
||||
let fetchM4ThreatCameraPointOverlay;
|
||||
let hydrateM4ThreatTimelineFrame;
|
||||
let selectM4ThreatTimelineFrame;
|
||||
let selectM4ThreatTimelineSequence;
|
||||
let advanceRecordedEvidencePlayback;
|
||||
@@ -17,6 +21,7 @@ let synchronizeRecordedEvidencePlayback;
|
||||
let m4ThreatChunkWindowStarts;
|
||||
let cancelM4ThreatChunkRequestsOutsideWindow;
|
||||
let buildM4LocalSurface;
|
||||
let buildM4StaticObstacleBoxes;
|
||||
|
||||
const resultId = `m4-threat-replay-${"a".repeat(64)}`;
|
||||
|
||||
@@ -31,7 +36,10 @@ before(async () => {
|
||||
fetchM4ThreatVisual,
|
||||
fetchM4ThreatTimeline,
|
||||
fetchM4ThreatTimelineChunk,
|
||||
fetchM4ThreatPlaybackManifest,
|
||||
fetchM4ThreatPlaybackPointChunk,
|
||||
fetchM4ThreatCameraPointOverlay,
|
||||
hydrateM4ThreatTimelineFrame,
|
||||
selectM4ThreatTimelineFrame,
|
||||
selectM4ThreatTimelineSequence,
|
||||
} = await server.ssrLoadModule("/src/core/laboratory/m4ReplayThreat.ts"));
|
||||
@@ -50,6 +58,9 @@ before(async () => {
|
||||
({ buildM4LocalSurface } = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/m4LocalSurface.ts",
|
||||
));
|
||||
({ buildM4StaticObstacleBoxes } = await server.ssrLoadModule(
|
||||
"/src/workspaces/laboratory/m4StaticObstacleBoxes.ts",
|
||||
));
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
@@ -328,6 +339,115 @@ test("M4.6 timeline keeps only a compact index and decodes bounded spatial chunk
|
||||
assert.equal(selectM4ThreatTimelineFrame(chunk.frames, 35.50).sequence, 1);
|
||||
});
|
||||
|
||||
test("M4.6 hydrates a lightweight timeline frame from one retained binary point track", async () => {
|
||||
const raw = timelineFrame(0, 35.421857292, {
|
||||
body_frame: {
|
||||
origin_map_xyz_m: [10, 20, 30],
|
||||
basis_map_from_body: [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
|
||||
},
|
||||
point_cloud_body_xyz_m: [],
|
||||
point_cloud_source_count: 2,
|
||||
point_cloud_sample_count: 2,
|
||||
});
|
||||
const parsed = await fetchM4ThreatTimelineChunk(resultId, 0, 1, {
|
||||
playbackPointPack: {
|
||||
resultId,
|
||||
frameCount: 4489,
|
||||
pointCount: 2,
|
||||
pointOffsets: new Uint32Array([0, 2, ...Array(4488).fill(2)]),
|
||||
pointsMapXyzM: new Float32Array([11, 20, 30.25, 12, 19.5, 30]),
|
||||
},
|
||||
fetcher: async (input) => {
|
||||
assert.match(String(input), /include_points=false/);
|
||||
return new Response(JSON.stringify({
|
||||
schema_version: "missioncore.recorded-spatial-evidence-chunk/v1",
|
||||
result_id: resultId,
|
||||
start_sequence: 0,
|
||||
frame_count: 1,
|
||||
next_sequence: 1,
|
||||
frames: [raw],
|
||||
authority: "replay-simulated",
|
||||
}), { status: 200 });
|
||||
},
|
||||
});
|
||||
assert.deepEqual(parsed.frames[0].pointCloudBodyXyzM, [
|
||||
[1, 0, 0.25],
|
||||
[2, -0.5, 0],
|
||||
]);
|
||||
assert.equal(parsed.frames[0].pointCloudSampleCount, 2);
|
||||
assert.equal(typeof hydrateM4ThreatTimelineFrame, "function");
|
||||
});
|
||||
|
||||
test("M4.6 source cloud opens from one verified bounded chunk instead of the 105 MiB track", async () => {
|
||||
const pointOffsets = [0, ...Array(4489).fill(2)];
|
||||
const points = new Float32Array([11, 20, 30.25, 12, 19.5, 30]);
|
||||
const pointBytes = points.buffer;
|
||||
const pointSha256 = createHash("sha256").update(Buffer.from(pointBytes)).digest("hex");
|
||||
const endpointRoot = "/api/v1/laboratory/m4-threat/results";
|
||||
const chunks = Array.from({ length: 188 }, (_, index) => {
|
||||
const start = index * 24;
|
||||
const count = Math.min(24, 4489 - start);
|
||||
const pointStart = pointOffsets[start];
|
||||
const pointStop = pointOffsets[start + count];
|
||||
const pointCount = pointStop - pointStart;
|
||||
return {
|
||||
index,
|
||||
start,
|
||||
count,
|
||||
point_start: pointStart,
|
||||
point_count: pointCount,
|
||||
url: `${endpointRoot}/${resultId}/timeline/playback/chunks/${index}`,
|
||||
media_type: "application/octet-stream",
|
||||
dtype: "<f4",
|
||||
shape: [pointCount, 3],
|
||||
bytes: pointCount * 3 * 4,
|
||||
sha256: index === 0 ? pointSha256 : "0".repeat(64),
|
||||
};
|
||||
});
|
||||
const manifestPayload = {
|
||||
schema_version: "missioncore.recorded-spatial-playback/v1",
|
||||
result_id: resultId,
|
||||
frame_count: 4489,
|
||||
point_count: 2,
|
||||
point_offsets: pointOffsets,
|
||||
chunk_frame_count: 24,
|
||||
resident_chunk_count_max: 4,
|
||||
forward_prefetch_chunk_count: 1,
|
||||
chunks,
|
||||
track: {
|
||||
id: "points-map-f32",
|
||||
url: `${endpointRoot}/${resultId}/timeline/playback/tracks/points-map-f32`,
|
||||
media_type: "application/octet-stream",
|
||||
dtype: "<f4",
|
||||
shape: [2, 3],
|
||||
bytes: pointBytes.byteLength,
|
||||
sha256: pointSha256,
|
||||
},
|
||||
coordinate_frame: "map",
|
||||
access: "read-only-sealed-binary-playback",
|
||||
};
|
||||
const requested = [];
|
||||
const fetcher = async (input) => {
|
||||
const url = String(input);
|
||||
requested.push(url);
|
||||
if (url.endsWith("/timeline/playback")) return Response.json(manifestPayload);
|
||||
if (url.endsWith("/timeline/playback/chunks/0")) return new Response(pointBytes.slice(0));
|
||||
return new Response(null, { status: 404 });
|
||||
};
|
||||
const manifest = await fetchM4ThreatPlaybackManifest(resultId, { fetcher });
|
||||
const chunk = await fetchM4ThreatPlaybackPointChunk(manifest, 0, { fetcher });
|
||||
|
||||
assert.deepEqual(requested, [
|
||||
`${endpointRoot}/${resultId}/timeline/playback`,
|
||||
`${endpointRoot}/${resultId}/timeline/playback/chunks/0`,
|
||||
]);
|
||||
assert.equal(chunk.pointCount, 2);
|
||||
assert.equal(chunk.pointStart, 0);
|
||||
assert.equal(chunk.sequenceCount, 24);
|
||||
assert.equal(chunk.pointsMapXyzM.byteLength, 24);
|
||||
assert.equal(requested.some((url) => url.endsWith("points-map-f32")), false);
|
||||
});
|
||||
|
||||
test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint", async () => {
|
||||
const replayResultId = `m48s-fixed-class-detector-lab-${"b".repeat(64)}`;
|
||||
const endpointRoot = "/api/v1/laboratory/m48s/fixed-class-detector";
|
||||
@@ -365,6 +485,8 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
camera_point_window_seconds: 2,
|
||||
camera_point_sample_limit: 20000,
|
||||
world_state_delivery: "source-paced-latest-wins",
|
||||
occupancy_provenance_delivery: "baseline-versus-additive-component-diff",
|
||||
camera_obstacle_projection_delivery: "factory-kb4-actionable-added-corridor-bounds",
|
||||
world_state_frame_count: 4481,
|
||||
superseded_frame_count: 8,
|
||||
local_surface_visualization: {
|
||||
@@ -392,9 +514,14 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
assert.equal(timeline.cameraPointWindowSeconds, 2);
|
||||
assert.equal(timeline.worldStateFrameCount, 4481);
|
||||
assert.equal(timeline.supersededFrameCount, 8);
|
||||
assert.equal(
|
||||
timeline.cameraObstacleProjectionDelivery,
|
||||
"factory-kb4-actionable-added-corridor-bounds",
|
||||
);
|
||||
|
||||
const chunk = await fetchM4ThreatTimelineChunk(replayResultId, 1, 1, {
|
||||
endpointRoot,
|
||||
cameraObstacleProjectionDelivery: timeline.cameraObstacleProjectionDelivery,
|
||||
fetcher: async (input) => {
|
||||
requested = String(input);
|
||||
return new Response(JSON.stringify({
|
||||
@@ -411,6 +538,30 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
camera_projected_point_count: 1,
|
||||
camera_projected_sample_count: 1,
|
||||
camera_projection: "factory-kb4-exact",
|
||||
metric_obstacles: [{
|
||||
component_id: "temporal-1855-7",
|
||||
state: "current",
|
||||
motion: "stationary",
|
||||
centroid_body_xyz_m: [2.4, 0.1, 0.3],
|
||||
cell_centers_body_xyz_m: [[2.4, 0.1, 0.3]],
|
||||
occupancy_source: "additive-low-step",
|
||||
camera_projection: {
|
||||
bbox_xyxy: [390.5, 280.25, 408.75, 318.5],
|
||||
nearest_depth_m: 2.3,
|
||||
projected_cell_count: 1,
|
||||
projection: "factory-kb4-occupied-voxel-bounds",
|
||||
authority: "visual-derived",
|
||||
},
|
||||
assessment: {
|
||||
component_id: "temporal-1855-7",
|
||||
decision: "threat",
|
||||
corridor_intersection: "intersects",
|
||||
relative_speed_mps: null,
|
||||
closest_approach_m: 0.2,
|
||||
ttc_seconds: null,
|
||||
reason_codes: ["current-corridor-intersection"],
|
||||
},
|
||||
}],
|
||||
camera_url: `${endpointRoot}/${replayResultId}/timeline/frames/1/camera`,
|
||||
})],
|
||||
authority: "replay-simulated",
|
||||
@@ -418,10 +569,18 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
},
|
||||
});
|
||||
assert.match(requested, new RegExp(`^${endpointRoot}/${replayResultId}/timeline/chunk`));
|
||||
assert.match(
|
||||
requested,
|
||||
/obstacle_projection=factory-kb4-actionable-added-corridor-bounds/,
|
||||
);
|
||||
assert.equal(chunk.frames[0].worldStateAvailable, false);
|
||||
assert.equal(chunk.frames[0].terminalOutcome, "superseded");
|
||||
assert.deepEqual(chunk.frames[0].cameraProjectedPointsXyd[0], [100.5, 200.25, 3.75]);
|
||||
assert.equal(chunk.frames[0].cameraProjection, "factory-kb4-exact");
|
||||
assert.deepEqual(
|
||||
chunk.frames[0].metricObstacles[0].cameraProjection.bboxXyxy,
|
||||
[390.5, 280.25, 408.75, 318.5],
|
||||
);
|
||||
|
||||
const overlay = await fetchM4ThreatCameraPointOverlay(replayResultId, 1, {
|
||||
endpointRoot,
|
||||
@@ -453,6 +612,114 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
assert.equal(overlay.projection, "factory-kb4-causal-registered-accumulation");
|
||||
});
|
||||
|
||||
test("M4.8R3 turns active low-step components into native fisheye obstacle boxes", () => {
|
||||
const obstacle = {
|
||||
componentId: "temporal-1855-7",
|
||||
state: "current",
|
||||
motion: "stationary",
|
||||
centroidBodyXyzM: [2.4, 0.1, 0.3],
|
||||
cellCentersBodyXyzM: [[2.4, 0.1, 0.3]],
|
||||
occupancySource: "additive-low-step",
|
||||
cameraProjection: {
|
||||
bboxXyxy: [398, 298, 402, 302],
|
||||
nearestDepthM: 2.3,
|
||||
projectedCellCount: 1,
|
||||
projection: "factory-kb4-occupied-voxel-bounds",
|
||||
authority: "visual-derived",
|
||||
},
|
||||
assessment: {
|
||||
componentId: "temporal-1855-7",
|
||||
decision: "threat",
|
||||
corridorIntersection: "intersects",
|
||||
relativeSpeedMps: null,
|
||||
closestApproachM: 0.2,
|
||||
ttcSeconds: null,
|
||||
reasonCodes: ["current-corridor-intersection"],
|
||||
},
|
||||
};
|
||||
const boxes = buildM4StaticObstacleBoxes([
|
||||
obstacle,
|
||||
{ ...obstacle, componentId: "baseline", occupancySource: "baseline" },
|
||||
{ ...obstacle, componentId: "held", state: "held" },
|
||||
{
|
||||
...obstacle,
|
||||
componentId: "unknown",
|
||||
assessment: {
|
||||
...obstacle.assessment,
|
||||
decision: "unknown",
|
||||
corridorIntersection: "unknown",
|
||||
},
|
||||
},
|
||||
{
|
||||
...obstacle,
|
||||
componentId: "clear",
|
||||
assessment: {
|
||||
...obstacle.assessment,
|
||||
decision: "not-threat",
|
||||
corridorIntersection: "clear",
|
||||
},
|
||||
},
|
||||
], 800, 600);
|
||||
assert.equal(boxes.length, 1);
|
||||
assert.deepEqual(boxes[0].boxXyxy, [394, 294, 406, 306]);
|
||||
assert.equal(boxes[0].label, "OBS #7 · 2,3 м");
|
||||
assert.equal(boxes[0].tone, "danger");
|
||||
assert.equal(boxes[0].dashed, false);
|
||||
});
|
||||
|
||||
test("M4.8R3 keeps separate CURRENT threats and suppresses their spanning ROLLING box", () => {
|
||||
const current = {
|
||||
componentId: "temporal-left-1",
|
||||
state: "current",
|
||||
motion: "stationary",
|
||||
centroidBodyXyzM: [3, 0, 0.3],
|
||||
cellCentersBodyXyzM: [[3, 0, 0.3]],
|
||||
occupancySource: "additive-low-step",
|
||||
cameraProjection: {
|
||||
bboxXyxy: [350, 260, 410, 310],
|
||||
nearestDepthM: 3,
|
||||
projectedCellCount: 2,
|
||||
projection: "factory-kb4-occupied-voxel-bounds",
|
||||
authority: "visual-derived",
|
||||
},
|
||||
assessment: {
|
||||
componentId: "temporal-left-1",
|
||||
decision: "threat",
|
||||
corridorIntersection: "intersects",
|
||||
relativeSpeedMps: null,
|
||||
closestApproachM: 2.5,
|
||||
ttcSeconds: null,
|
||||
reasonCodes: ["current-corridor-intersection"],
|
||||
},
|
||||
};
|
||||
const boxes = buildM4StaticObstacleBoxes([
|
||||
current,
|
||||
{
|
||||
...current,
|
||||
componentId: "temporal-right-2",
|
||||
cameraProjection: {
|
||||
...current.cameraProjection,
|
||||
bboxXyxy: [405, 265, 445, 320],
|
||||
},
|
||||
},
|
||||
{
|
||||
...current,
|
||||
componentId: "rolling-spanning",
|
||||
state: "retained",
|
||||
cameraProjection: {
|
||||
...current.cameraProjection,
|
||||
bboxXyxy: [340, 255, 450, 325],
|
||||
},
|
||||
},
|
||||
], 800, 600);
|
||||
|
||||
assert.equal(boxes.length, 2);
|
||||
assert.deepEqual(boxes.map((box) => box.label).sort(), [
|
||||
"OBS #1 · 3 м",
|
||||
"OBS #2 · 3 м",
|
||||
]);
|
||||
});
|
||||
|
||||
test("M4.6 local SLAM surface reprojects registered increments into the active body frame", () => {
|
||||
const frames = [
|
||||
timelineFrame(0, 10, {
|
||||
@@ -603,6 +870,9 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
assert.match(visual, /label: "3D"/);
|
||||
assert.match(visual, /label: "PLAN"/);
|
||||
assert.match(visual, />\s*POINTS\s*</);
|
||||
assert.match(visual, />\s*OBSTACLES\s*</);
|
||||
assert.match(visual, /useState\(true\);[\s\S]*setShowStaticObstacles/);
|
||||
assert.match(visual, /buildM4StaticObstacleBoxes/);
|
||||
assert.match(visual, /pointCloudOverlay=/);
|
||||
assert.match(visual, /mediaMode/);
|
||||
assert.match(visual, /spatialMode/);
|
||||
@@ -623,13 +893,22 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
assert.match(visualCss, /m4-replay-threat-visual__deck > \.nodedc-split-pane/);
|
||||
assert.match(visualCss, /m4-replay-threat-visual__pane-toolbar\[data-pane-toolbar="media"\]/);
|
||||
assert.match(visualCss, /m4-replay-threat-visual__pane-toolbar\[data-pane-toolbar="spatial"\]/);
|
||||
assert.match(
|
||||
visualCss,
|
||||
/data-mode-controls="content"\]:has\([\s\S]*m4-replay-threat-visual__review-controls[\s\S]*data-pane-toolbar="media"\][^{]*\{[^}]*top:\s*3\.8rem/s,
|
||||
);
|
||||
assert.match(visualCss, /width: 33\.333333%/);
|
||||
assert.match(visualCss, /flex-flow: column nowrap/);
|
||||
assert.match(visualCss, /m4-replay-threat-visual__overlay > div/);
|
||||
assert.match(visualCss, /grid-template-columns: minmax\(0, max-content\)/);
|
||||
assert.match(visualCss, /width: max-content/);
|
||||
assert.match(visualCss, /grid-template-columns: minmax\(0, 1fr\)/);
|
||||
assert.match(visualCss, /width: min\(17\.5rem/);
|
||||
assert.match(visualCss, /grid-auto-rows: 3\.8rem/);
|
||||
assert.match(visualCss, /--m4-replay-threat-overlay-pane-width/);
|
||||
assert.match(visualCss, /white-space: nowrap/);
|
||||
assert.match(visualCss, /-webkit-line-clamp: 2/);
|
||||
assert.match(visual, /classifiedCellCount/);
|
||||
assert.match(visual, /lastAvailableClassifiedSpatialFrame/);
|
||||
assert.match(visual, /current UNOBSERVED/);
|
||||
assert.match(visualCss, /laboratory-metric-evidence-scene__legend/);
|
||||
assert.match(visualCss, /bottom: auto/);
|
||||
assert.match(videoScene, /<RecordedFmp4Player/);
|
||||
@@ -641,7 +920,29 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
assert.match(metricScene, /OrbitControls/);
|
||||
assert.match(visual, /LOCAL SLAM/);
|
||||
assert.match(visual, /showLocalSurface/);
|
||||
assert.match(visual, /pointCloudBodyXyzM=\{spatialFrame\.pointCloudBodyXyzM\}/);
|
||||
assert.match(
|
||||
visual,
|
||||
/pointCloudBodyXyzM=\{displayedClassifiedSpatialFrame && replaceClassifiedPointCloud[\s\S]*\? classifiedPointsBody[\s\S]*: classifiedContextSpatialFrame\?\.pointCloudBodyXyzM \?\? \[\]\}/,
|
||||
);
|
||||
assert.match(
|
||||
visual,
|
||||
/const classifiedSpatialFrame = classifiedSpatialLayer\?\.frame\?\.sourceSequence === timelineFrame\.activeSequence[\s\S]*lastClassifiedSpatialFrameRef[\s\S]*const displayedClassifiedSpatialFrame = classifiedSpatialFrame\s*&&\s*classifiedSpatialFrame\.sampleAvailable !== false/,
|
||||
);
|
||||
assert.doesNotMatch(visual, /classifiedSpatialFrame\?\.sampleAvailable !== false/);
|
||||
assert.match(visual, /timelineFrame\.availableFrames\.find/);
|
||||
assert.match(visual, /localSurfaceBodyXyzM=\{localSurface\.pointsBodyXyzM\}/);
|
||||
assert.match(visual, /showLocalSurface=\{showLocalSurface\}/);
|
||||
assert.match(visual, /\{semantic \? \([\s\S]*>\s*SEMANTICS\s*<\/Button>/);
|
||||
assert.match(visual, /current safety — все \{classifiedCellCount\.toLocaleString\("ru-RU"\)\} TGS-ячейки UNOBSERVED/);
|
||||
assert.match(
|
||||
visual,
|
||||
/mapGravityLocalSensorToBodyGround[\s\S]*rotated\[2\] \+ nominalSensorHeightM/,
|
||||
);
|
||||
assert.match(
|
||||
visual,
|
||||
/zBoundsM: \[[\s\S]*minimumSensorRelativeZ \+ nominalSensorHeightM[\s\S]*maximumSensorRelativeZ \+ nominalSensorHeightM/,
|
||||
);
|
||||
assert.match(visual, /classifiedCells=\{classifiedCellsBody\}/);
|
||||
assert.match(metricScene, /Локальная SLAM-поверхность/);
|
||||
assert.match(visual, /showJumpToEnd=\{false\}/);
|
||||
assert.doesNotMatch(visual, /Назад на 5 секунд/);
|
||||
|
||||
@@ -324,7 +324,7 @@ test("Polygon exposes one dataset surface and keeps legacy links compatible", ()
|
||||
assert.equal(workspaceById("datasets").kind, "datasets");
|
||||
assert.deepEqual(
|
||||
workspacesForRoot("polygon").map(({ id }) => id),
|
||||
["lab-archive"],
|
||||
["lab-archive", "simulations"],
|
||||
);
|
||||
assert.equal(
|
||||
workspacesForRoot("system").some(({ id }) => id === "polygon-run"),
|
||||
|
||||
@@ -173,6 +173,9 @@ test("recorded player keeps full-archive range fallback and uses bounded generat
|
||||
assert.match(source, /pumpRecordedSegmentWindow/);
|
||||
assert.match(source, /waitForRecordedVideoTarget/);
|
||||
assert.match(source, /removeRecordedMediaRange/);
|
||||
assert.match(source, /hasPresentedFrame/);
|
||||
assert.match(source, /retainForwardFrame/);
|
||||
assert.match(source, /candidateTarget\.sequence >= previousTarget\.sequence/);
|
||||
|
||||
assert.equal(recordedMediaDecodeStartSequence([1, 1491, 1501], 1500), 1491);
|
||||
assert.deepEqual(
|
||||
|
||||
@@ -28,6 +28,8 @@ test("semantic evidence mask is GPU-colored, bounded, cancelled and object-conta
|
||||
assert.match(source, /Math\.min\(width \/ mask\.width, height \/ mask\.height\)/);
|
||||
assert.match(source, /decoded\.key !== expectedKey/);
|
||||
assert.match(source, /mask\?\.key === expectedKey/);
|
||||
assert.match(source, /lastReadyMaskRef/);
|
||||
assert.match(source, /data-state=\{failure \? "error" : exactMask \? "ready" : renderMask \? "stale" : "loading"\}/);
|
||||
assert.match(source, /recorded-evidence-semantic-mask-overlay__error/);
|
||||
assert.match(source, /role="alert"/);
|
||||
});
|
||||
@@ -53,6 +55,12 @@ test("metric evidence keeps missing semantic assignments as context and exposes
|
||||
assert.match(source, /classId === null \? undefined : colorsByClassId\.get\(classId\)/);
|
||||
assert.match(source, /data-decision="semantic"/);
|
||||
assert.match(source, /recordedEvidenceSemanticCssColor/);
|
||||
assert.match(source, /DynamicDrawUsage/);
|
||||
assert.match(source, /classifiedMeshesRef/);
|
||||
assert.match(source, /classifiedPackedCells/);
|
||||
assert.match(source, /updatePointPositions/);
|
||||
assert.match(source, /renderer\.info\.render\.calls/);
|
||||
assert.match(source, /data-decision="performance"/);
|
||||
});
|
||||
|
||||
test("semantic point alignment follows the last qualified spatial increment", async () => {
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { test } from "node:test";
|
||||
|
||||
const sourceRoot = new URL("../src/", import.meta.url);
|
||||
|
||||
async function read(relativePath) {
|
||||
return readFile(new URL(relativePath, sourceRoot), "utf8");
|
||||
}
|
||||
|
||||
test("simulation is a dedicated Polygon workspace with a bounded feature slice", async () => {
|
||||
const [productModel, workspaceHub, workspace, catalog, styles] = await Promise.all([
|
||||
read("productModel.ts"),
|
||||
read("workspaces/Workspaces.tsx"),
|
||||
read("workspaces/simulation/SimulationWorkspace.tsx"),
|
||||
read("components/simulation/SimulationCatalog.tsx"),
|
||||
read("styles.css"),
|
||||
]);
|
||||
|
||||
assert.match(productModel, /id: "simulations"[\s\S]*root: "polygon"[\s\S]*kind: "simulations"/);
|
||||
assert.match(workspaceHub, /case "simulations":[\s\S]*<SimulationWorkspace \/>/);
|
||||
assert.match(catalog, /simulation-catalog__table/);
|
||||
assert.match(workspace, /archivesFromDrop/);
|
||||
assert.match(workspace, /uploadSimulationProjectSource/);
|
||||
assert.match(catalog, /colSpan=\{3\}/);
|
||||
assert.match(catalog, /Ожидает обработки/);
|
||||
assert.match(catalog, /Прогресс \$\{roundedPercent\}% \|/);
|
||||
assert.match(catalog, /Осталось примерно \$\{minutes\} мин/);
|
||||
assert.match(catalog, /simulation-catalog__progress-track/);
|
||||
assert.doesNotMatch(catalog, /disabled=\{ACTIVE_STATUSES\.has/);
|
||||
assert.match(workspace, /<SimulationViewport[\s\S]*project=\{selected\}/);
|
||||
assert.match(workspace, /<ConfirmationModal/);
|
||||
assert.match(workspace, /if \(state === "building_streamed_sog"\) return "Сборка LOD"/);
|
||||
assert.doesNotMatch(workspace, /\{selected\.provider\.state \?\? selected\.status\}/);
|
||||
assert.match(styles, /styles\/simulation\.css/);
|
||||
});
|
||||
|
||||
test("browser upload remains same-origin, resumable and token-free", async () => {
|
||||
const [core, window, sourceFiles] = await Promise.all([
|
||||
read("core/simulation/projects.ts"),
|
||||
read("components/simulation/SimulationProjectWindow.tsx"),
|
||||
read("core/simulation/sourceFiles.ts"),
|
||||
]);
|
||||
|
||||
assert.match(core, /const API_ROOT = "\/api\/v1\/simulation-worlds\/projects"/);
|
||||
assert.match(core, /method: "HEAD"/);
|
||||
assert.match(core, /method: "PATCH"/);
|
||||
assert.match(core, /"Upload-Offset"/);
|
||||
assert.match(core, /estimatedSecondsRemaining/);
|
||||
assert.match(core, /smoothedBytesPerSecond \* 0\.7 \+ currentBytesPerSecond \* 0\.3/);
|
||||
assert.match(core, /estimateSimulationProcessing/);
|
||||
assert.match(core, /jobCreatedAtUtc/);
|
||||
assert.match(core, /stateStartedAtUtc/);
|
||||
assert.match(core, /REFERENCE_STREAM_SECONDS = 2_317/);
|
||||
assert.doesNotMatch(core, /Authorization|Bearer|18090|Worker 006/);
|
||||
assert.match(window, /accept="\.zip,\.rar,\.7z"/);
|
||||
assert.match(window, /webkitdirectory/);
|
||||
assert.match(sourceFiles, /webkitGetAsEntry/);
|
||||
assert.match(sourceFiles, /entry\?\.isDirectory/);
|
||||
assert.match(sourceFiles, /const file = item\.getAsFile\(\)/);
|
||||
assert.match(sourceFiles, /MAX_SIMULATION_SOURCE_BYTES = 16 \* 1024 \*\* 3/);
|
||||
assert.match(sourceFiles, /item\.kind === "file"/);
|
||||
assert.match(sourceFiles, /ровно одна сцена \.lcc или \.lcc2/);
|
||||
assert.match(sourceFiles, /отдельные архивы ZIP, RAR или 7z/);
|
||||
assert.doesNotMatch(window, /Загружаем источник/);
|
||||
assert.match(window, /считаем время/);
|
||||
});
|
||||
|
||||
test("failed simulation can restart from its retained Mission Core source", async () => {
|
||||
const [core, workspace] = await Promise.all([
|
||||
read("core/simulation/projects.ts"),
|
||||
read("workspaces/simulation/SimulationWorkspace.tsx"),
|
||||
]);
|
||||
|
||||
assert.match(core, /retrySimulationProject/);
|
||||
assert.match(core, /\$\{API_ROOT\}\/\$\{encodeURIComponent\(projectId\)\}\/build/);
|
||||
assert.match(workspace, /Повторить сборку/);
|
||||
});
|
||||
|
||||
test("PlayCanvas owns the realtime scene graph without an iframe or React entity tree", async () => {
|
||||
const [runtime, ugv, viewport, ugvSettings, projects, styles, packageDocument] = await Promise.all([
|
||||
read("components/simulation/PlayCanvasRuntime.ts"),
|
||||
read("components/simulation/SimulationUgvController.ts"),
|
||||
read("components/simulation/SimulationViewport.tsx"),
|
||||
read("components/simulation/SimulationUgvSettingsPanel.tsx"),
|
||||
read("core/simulation/projects.ts"),
|
||||
read("styles/simulation.css"),
|
||||
readFile(new URL("../package.json", import.meta.url), "utf8"),
|
||||
]);
|
||||
|
||||
assert.match(packageDocument, /"playcanvas": "2\.21\.4"/);
|
||||
assert.doesNotMatch(packageDocument, /@playcanvas\/react/);
|
||||
assert.match(runtime, /new Application\(canvas/);
|
||||
assert.match(runtime, /setCanvasFillMode\(FILLMODE_NONE/);
|
||||
assert.match(runtime, /setCanvasResolution\(RESOLUTION_AUTO\)/);
|
||||
assert.match(runtime, /new Asset\([^,]+, "gsplat"/);
|
||||
assert.match(runtime, /camera\.script\?\.create\(CameraControls/);
|
||||
assert.match(runtime, /const HOME_POSITION = new Vec3\(0, 1, 0\)/);
|
||||
assert.match(runtime, /const HOME_FOCUS = new Vec3\(1, 1, 0\)/);
|
||||
assert.match(runtime, /maximum: \{[^}]*lodRangeMin: 0, lodRangeMax: 5, pixelRatio: 2, splatBudget: 4_000_000, targetFps: 60/);
|
||||
assert.match(runtime, /app\.scene\.gsplat\.splatBudget = profile\.splatBudget/);
|
||||
assert.match(runtime, /app\.autoRender = false/);
|
||||
assert.match(runtime, /app\.on\("update", this\.updateFrame\)/);
|
||||
assert.match(runtime, /if \(!cameraChanged && this\.controlMode === "free"\) return/);
|
||||
assert.doesNotMatch(runtime, /app\.on\("frameupdate"/);
|
||||
assert.match(runtime, /WEBGL_lose_context/);
|
||||
assert.match(runtime, /selected\.horizontal[^\n]+frame\.mouse\[0\] \*= -1/);
|
||||
assert.match(runtime, /selected\.vertical[^\n]+frame\.mouse\[1\] \*= -1/);
|
||||
assert.match(runtime, /setCameraInversion/);
|
||||
assert.match(runtime, /async setViewMode\([\s\S]*this\.viewMode = mode/);
|
||||
assert.doesNotMatch(runtime.match(/async setViewMode\([\s\S]*?\n }/)?.[0] ?? "", /resetCameraInteraction/);
|
||||
assert.match(runtime, /controller\.fire\("state"\)/);
|
||||
assert.match(runtime, /state\.mouse\.fill\(0\)/);
|
||||
assert.match(runtime, /new Asset\([\s\S]*"container"/);
|
||||
assert.match(runtime, /instantiateModelEntity/);
|
||||
assert.match(runtime, /applyWorldTransform/);
|
||||
assert.match(runtime, /setLayerWorldTransform/);
|
||||
assert.match(runtime, /playCanvasEulerTransform/);
|
||||
assert.match(runtime, /setFromEulerAngles/);
|
||||
assert.match(runtime, /DracoDecoderModule/);
|
||||
assert.match(runtime, /draco_decoder_gltf\.wasm/);
|
||||
assert.match(runtime, /ensureCollision/);
|
||||
assert.match(runtime, /setControlMode/);
|
||||
assert.match(runtime, /setUgvPreset/);
|
||||
assert.match(runtime, /SimulationUgvController/);
|
||||
assert.match(runtime, /for \(const model of this\.collisionVisuals\) model\.enabled = visible/);
|
||||
assert.match(runtime, /instantiateModelEntity/);
|
||||
assert.match(runtime, /this\.ugvController\?\.disable\(\)/);
|
||||
assert.match(runtime, /this\.collisionMaterial\.blendType = combined \? BLEND_NORMAL : BLEND_NONE/);
|
||||
assert.match(runtime, /private requestRender\(\): void/);
|
||||
assert.match(runtime, /app\.root\.addChild/);
|
||||
assert.match(runtime, /dispose\(\)/);
|
||||
assert.doesNotMatch(`${runtime}\n${viewport}`, /iframe|<GSplat/);
|
||||
assert.match(viewport, /Коллизии недоступны/);
|
||||
assert.match(viewport, /Для этой сборки слой коллизий не создавался/);
|
||||
assert.match(viewport, /<Select[\s\S]*Качество Gaussian-сцены/);
|
||||
assert.match(viewport, /label="Режим управления"/);
|
||||
assert.match(viewport, /label: "Свободно"/);
|
||||
assert.match(viewport, /label: "UGV"/);
|
||||
assert.match(viewport, /WASD\/стрелки · пробел — тормоз · R — домой/);
|
||||
assert.match(viewport, /data-control-mode=\{controlMode\}/);
|
||||
assert.match(viewport, /useState<SimulationQuality>\(project\.viewerSettings\.quality\)/);
|
||||
assert.match(viewport, /runtimeRef\.current\?\.home\(\)/);
|
||||
assert.match(viewport, /Настройки сцены/);
|
||||
assert.match(viewport, /Гауссовый слой/);
|
||||
assert.match(viewport, /Слой коллизий/);
|
||||
assert.match(viewport, /Инверсия управления по горизонтали/);
|
||||
assert.match(viewport, /Инверсия управления по вертикали/);
|
||||
assert.match(viewport, /ROTATION_AXES/);
|
||||
assert.match(viewport, /<GlassMaterialSurface/);
|
||||
assert.match(viewport, /<TextField/);
|
||||
assert.match(viewport, /nextDraft\.trim\(\) !== ""/);
|
||||
assert.match(viewport, /saveSimulationViewerSettings/);
|
||||
assert.match(viewport, /SimulationUgvSettingsPanel/);
|
||||
assert.match(viewport, /runtime\.setUgvPreset\(settings\.ugv\)/);
|
||||
assert.match(viewport, /onProjectChange\?\.\(saved\)/);
|
||||
assert.match(viewport, /const worldManifestRevision = JSON\.stringify\(project\.worldManifest\)/);
|
||||
assert.match(viewport, /\[project\.projectId, worldManifestRevision\]/);
|
||||
assert.doesNotMatch(viewport, /\[project\.projectId, project\.worldManifest\]/);
|
||||
assert.doesNotMatch(viewport, />PlayCanvas|PlayCanvas загружает|Streamed SOG/);
|
||||
assert.match(ugv, /AMMO_MODULE_ROOT = "\/vendor\/playcanvas\/ammo\/2026-08-25"/);
|
||||
assert.match(ugv, /new this\.ammo\.btRaycastVehicle/);
|
||||
assert.match(ugv, /type: "mesh"/);
|
||||
assert.match(ugv, /MeshoptSimplifier\.simplify/);
|
||||
assert.match(ugv, /PHYSICS_PROXY_MAX_TRIANGLES = 240_000/);
|
||||
assert.match(ugv, /createPhysicsProxyMesh/);
|
||||
assert.match(ugv, /findSafeSpawnPosition/);
|
||||
assert.match(ugv, /physics\.raycastFirst/);
|
||||
assert.match(ugv, /runCleanup\("destroy static physics mesh", \(\) => mesh\.destroy\(\)\)/);
|
||||
assert.match(ugv, /type: "static"/);
|
||||
assert.match(ugv, /mass: this\.settings\.massKg/);
|
||||
assert.match(ugv, /suspensionRestLength/);
|
||||
assert.match(ugv, /requestedTurn = Number\(this\.isPressed\("KeyA", "ArrowLeft"\)\) - Number\(this\.isPressed\("KeyD", "ArrowRight"\)\)/);
|
||||
assert.match(ugv, /leftCommand = clamp\(forwardCommand - turnCommand/);
|
||||
assert.match(ugv, /rightCommand = clamp\(forwardCommand \+ turnCommand/);
|
||||
assert.match(ugv, /this\.settings\.invertSteering/);
|
||||
assert.match(ugv, /this\.settings\.maxSpeedMetersPerSecond/);
|
||||
assert.match(ugv, /this\.settings\.maxTurnRateDegrees/);
|
||||
assert.match(ugv, /desiredSpeed = forwardInput \* maxSpeed/);
|
||||
assert.match(ugv, /maximumAcceleration = clamp\(1\.4 \+ maxSpeed \* 0\.35, 1\.8, 4\.2\)/);
|
||||
assert.match(ugv, /SERVICE_BRAKE_DECELERATION_MPS2 = 1\.8/);
|
||||
assert.match(ugv, /horizontalSpeed - deceleration \* Math\.max\(0, deltaSeconds\)/);
|
||||
assert.match(ugv, /this\.vehicle\.setBrake\(0, index\)/);
|
||||
assert.doesNotMatch(ugv, /massKg \* 3/);
|
||||
assert.match(ugv, /pureTurn = !braking && forwardInput === 0 && turnInput !== 0/);
|
||||
assert.match(ugv, /desiredYawRate = -turnInput \* maxTurnRate/);
|
||||
assert.match(ugv, /this\.orbitYaw = \(this\.orbitYaw - deltaX \* 0\.006\)/);
|
||||
assert.match(ugv, /CAMERA_RETURN_DELAY_SECONDS = 1\.2/);
|
||||
assert.match(ugv, /CAMERA_RETURN_DURATION_SECONDS = 2/);
|
||||
assert.match(ugv, /approachAngle\(this\.orbitYaw, rearOrbitYaw/);
|
||||
assert.match(ugv, /this\.canvas\.addEventListener\("pointerdown", this\.onOrbitPointerDown\)/);
|
||||
assert.match(ugv, /this\.canvas\.addEventListener\("wheel", this\.onOrbitWheel/);
|
||||
assert.match(ugv, /vehicleGeometryChanged/);
|
||||
assert.match(ugv, /removeAction\(this\.vehicle as NativeObject\)/);
|
||||
assert.match(ugv, /runCleanup\("destroy static physics proxy", \(\) => entity\.destroy\(\)\)/);
|
||||
assert.match(ugv, /runCleanup\("destroy vehicle entity"/);
|
||||
assert.match(ugvSettings, /Физика UGV/);
|
||||
assert.match(ugvSettings, /Дифференциальный привод/);
|
||||
assert.match(ugvSettings, /Масса конструкции/);
|
||||
assert.match(ugvSettings, /Общая высота/);
|
||||
assert.match(ugvSettings, /Клиренс/);
|
||||
assert.match(ugvSettings, /Скорость движения/);
|
||||
assert.match(ugvSettings, /Скорость разворота/);
|
||||
assert.match(ugvSettings, /exactValueBounds=\{SIMULATION_UGV_EXACT_VALUE_LIMITS\.maxSpeedMetersPerSecond\}/);
|
||||
assert.match(projects, /maxSpeedMetersPerSecond: \{ min: 0, max: 1_000_000_000 \}/);
|
||||
assert.match(ugvSettings, /Инверсия управления A\/D/);
|
||||
assert.match(ugvSettings, /Сохранить пресет/);
|
||||
assert.match(ugvSettings, /<RangeControl/);
|
||||
assert.match(ugvSettings, /<Switch/);
|
||||
assert.match(ugvSettings, /<TextField/);
|
||||
assert.match(projects, /missioncore\.simulation-viewer-settings\/v3/);
|
||||
assert.match(projects, /ugv: SimulationUgvPreset/);
|
||||
assert.match(styles, /\.simulation-viewport__settings \{[\s\S]*grid-template-rows: auto minmax\(0, 1fr\);[\s\S]*overflow: clip;/);
|
||||
assert.match(styles, /\.simulation-viewport__settings-scroll \{[\s\S]*overflow-y: auto;/);
|
||||
assert.match(styles, /\.simulation-viewport__toolbar \{[\s\S]*position: sticky;[\s\S]*top: 0;/);
|
||||
assert.match(styles, /canvas\.is-orbiting[\s\S]*cursor: grabbing/);
|
||||
});
|
||||
@@ -0,0 +1,397 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { access, readFile } from "node:fs/promises";
|
||||
import { after, before, test } from "node:test";
|
||||
|
||||
import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let fetchVegetationBenchmarkResult;
|
||||
let fetchVegetationShadowResult;
|
||||
let vegetationFullRouteMaskUrl;
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
appType: "custom",
|
||||
logLevel: "silent",
|
||||
server: { middlewareMode: true },
|
||||
});
|
||||
({
|
||||
fetchVegetationBenchmarkResult,
|
||||
fetchVegetationShadowResult,
|
||||
vegetationFullRouteMaskUrl,
|
||||
} = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/vegetationShadow.ts",
|
||||
));
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await server?.close();
|
||||
});
|
||||
|
||||
const resultId = `lab-v1-vegetation-shadow-${"a".repeat(64)}`;
|
||||
const benchmarkResultId = `lab-v1-vegetation-benchmark-${"d".repeat(64)}`;
|
||||
|
||||
function candidate(candidateKey, vegetationIou) {
|
||||
return {
|
||||
loaded_model_name: candidateKey === "ddrnet" ? "ddrnet_39" : "pp_lite_t_seg",
|
||||
checkpoint_sha256: (candidateKey === "ddrnet" ? "b" : "c").repeat(64),
|
||||
validation_metrics: {
|
||||
mean_iou_percent: 44.2,
|
||||
published_mean_iou_percent: 46.53,
|
||||
vegetation_mean_iou: vegetationIou,
|
||||
},
|
||||
validation_timing: {
|
||||
latency_ms_p95: 22.4,
|
||||
throughput_fps_from_mean_inference: 48.1,
|
||||
},
|
||||
shadow_timing: {
|
||||
prewarm_latency_ms: 612.4,
|
||||
latency_ms_p95: 21.8,
|
||||
throughput_fps_from_mean_inference: 49.2,
|
||||
},
|
||||
resource: {
|
||||
peak_reserved_vram_bytes: 2_000_000_000,
|
||||
gpu_name: "NVIDIA GeForce RTX 4090",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function visualCase(sourceKind, index) {
|
||||
const caseId = `case-${index}`;
|
||||
const keys = sourceKind === "goose"
|
||||
? ["source", "truth", "ddrnet", "ppliteseg", "ddrnet_error", "ppliteseg_error"]
|
||||
: ["source", "ddrnet", "ppliteseg", "urban", "rural", "offroad"];
|
||||
return {
|
||||
case_id: caseId,
|
||||
source_kind: sourceKind,
|
||||
width: sourceKind === "goose" ? 512 : 800,
|
||||
height: sourceKind === "goose" ? 512 : 600,
|
||||
center_crop_xyxy: sourceKind === "goose" ? [0, 0, 512, 512] : [100, 0, 700, 600],
|
||||
outside_crop_state: sourceKind === "goose" ? "not-applicable" : "undefined",
|
||||
focus: sourceKind === "goose" ? {
|
||||
class_name: "high_grass",
|
||||
label_id: 51,
|
||||
truth_pixels: 16384,
|
||||
truth_fraction: 0.0625,
|
||||
stratum_rank: index + 1,
|
||||
} : null,
|
||||
assets: Object.fromEntries(keys.map((key) => [key, {
|
||||
path: `visual/${sourceKind}/${caseId}/${key}.png`,
|
||||
sha256: "d".repeat(64),
|
||||
}])),
|
||||
};
|
||||
}
|
||||
|
||||
function routeVideo() {
|
||||
return {
|
||||
worker_result_id: `lab-v1-ravnoves-video-ddrnet-${"e".repeat(64)}`,
|
||||
m47_reference_graph_result_id: `m47-reference-graph-lab-${"f".repeat(64)}`,
|
||||
base_m4_result_id: `m4-threat-replay-${"1".repeat(64)}`,
|
||||
frame_count: 4489,
|
||||
width: 800,
|
||||
height: 600,
|
||||
center_crop_xyxy: [100, 0, 700, 600],
|
||||
outside_crop_state: "undefined",
|
||||
sequence_binding: "sequence-0-to-masks/frame-000001.png",
|
||||
taxonomy: {
|
||||
schema_version: "missioncore.lab-v1-vegetation-taxonomy/v1",
|
||||
classes: Array.from({ length: 64 }, (_, classId) => ({
|
||||
class_id: classId,
|
||||
label: classId === 0 ? "undefined" : `class-${classId}`,
|
||||
color_rgb: [classId, classId, classId],
|
||||
disposition: classId === 0 ? "undefined" : "prediction",
|
||||
})),
|
||||
},
|
||||
aggregate_prediction_pixels: Array(64).fill(0),
|
||||
mask_archive: {
|
||||
path: "video/ddrnet-semantic-masks.zip",
|
||||
sha256: "9".repeat(64),
|
||||
byte_length: 1024,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function coarseRouteVideo() {
|
||||
return {
|
||||
...routeVideo(),
|
||||
view_kind: "coarse-material-policy-review",
|
||||
linked_tgs_result_id: `m49-tgs-full-shadow-${"2".repeat(64)}`,
|
||||
taxonomy: {
|
||||
schema_version: "missioncore.lab-v1-terrain-policy-taxonomy/v1",
|
||||
classes: Array.from({ length: 10 }, (_, classId) => ({
|
||||
class_id: classId,
|
||||
label: `policy-${classId}`,
|
||||
color_rgb: [classId, classId, classId],
|
||||
disposition: classId === 0 ? "ambiguous" : classId === 9 ? "undefined" : "prediction",
|
||||
material_class: classId === 0 || classId === 9 ? null : "grass",
|
||||
evidence_state: classId === 0 || classId === 9 ? "UNOBSERVED" : "SUPPORTED_GROUND",
|
||||
})),
|
||||
},
|
||||
aggregate_prediction_pixels: Array(10).fill(0),
|
||||
mask_archive: {
|
||||
path: "video/coarse-material-policy-masks.zip",
|
||||
sha256: "8".repeat(64),
|
||||
byte_length: 2048,
|
||||
},
|
||||
valid_fov: {
|
||||
mask_path: "video/valid-fov-mask.png",
|
||||
mask_sha256: "7".repeat(64),
|
||||
outside_valid_fov_class_id: 9,
|
||||
},
|
||||
policy: {
|
||||
presets: {
|
||||
urban: { grass: "NO_GO" },
|
||||
rural: { grass: "HIGH_COST" },
|
||||
offroad: { grass: "HIGH_COST" },
|
||||
},
|
||||
},
|
||||
fusion: {
|
||||
mode: "synchronised-multilayer-review",
|
||||
pixel_raster_fusion: false,
|
||||
camera_semantic_temporal_filter: "none",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function fullRouteReview() {
|
||||
const layer = (kind) => ({
|
||||
name: kind === "city" ? "EoMT Cityscapes" : "ddrnet_39",
|
||||
result_id: kind === "city"
|
||||
? `result-${"2".repeat(64)}`
|
||||
: `lab-v1-ravnoves-video-ddrnet-${"3".repeat(64)}`,
|
||||
frame_count: 6830,
|
||||
taxonomy: {
|
||||
schema_version: kind === "city"
|
||||
? "missioncore.recorded-eomt-taxonomy/v1"
|
||||
: "missioncore.lab-v1-vegetation-taxonomy/v1",
|
||||
classes: Array.from({ length: kind === "city" ? 16 : 64 }, (_, classId) => ({
|
||||
class_id: classId,
|
||||
label: classId === 0 ? "undefined" : `${kind}-${classId}`,
|
||||
color_rgb: [classId, classId, classId],
|
||||
disposition: classId === 0 ? "undefined" : "prediction",
|
||||
})),
|
||||
},
|
||||
mask_archive: {
|
||||
path: kind === "city"
|
||||
? "video/eomt-semantic-masks.zip"
|
||||
: "video/ddrnet-semantic-masks.zip",
|
||||
sha256: "4".repeat(64),
|
||||
byte_length: 4096,
|
||||
},
|
||||
inference_fps: 9.5,
|
||||
latency_p95_ms: 101.2,
|
||||
peak_reserved_vram_bytes: 3_000_000_000,
|
||||
});
|
||||
return {
|
||||
source_id: "RAVNOVES004TREE",
|
||||
session_id: "20260828T130511Z_viewer_live",
|
||||
source_job_id: "recorded-camera-eb2783c5480d56bda07c8af0",
|
||||
source_job_input_sha256: "eb2783c5480d56bda07c8af008dff5344d19dc550ef70fe2075d6f098f7cc715",
|
||||
source_stream_sha256: "e5eb017e2cc0f546736eda5235ca157b501913093cb64af5e548e335417e1bac",
|
||||
recorded_media_source_id: "recorded.camera.6a3945242828a038",
|
||||
recorded_media_generation_sha256: "b073ea1e7babf1c77a664e1a5b95e3702d0e05b0e34c1e85a7c67a6f8b392ded",
|
||||
frame_count: 6830,
|
||||
width: 800,
|
||||
height: 600,
|
||||
timeline_start_seconds: 39.215263458,
|
||||
timeline_end_seconds: 757.260263458,
|
||||
timeline: {
|
||||
path: "video/frame-source-times-ns.bin",
|
||||
sha256: "5".repeat(64),
|
||||
byte_length: 6830 * 8,
|
||||
encoding: "uint64-le-nanoseconds",
|
||||
frame_count: 6830,
|
||||
},
|
||||
ground_truth: false,
|
||||
decode_repair: {
|
||||
repaired_frame_count: 1,
|
||||
sequence: 6092,
|
||||
method: "duplicate-previous-decoded-frame",
|
||||
proofs: {
|
||||
eomt: { path: "proofs/decode_repair.json", sha256: "7".repeat(64) },
|
||||
ddrnet: { path: "proofs/ddrnet_decode_repair.json", sha256: "8".repeat(64) },
|
||||
},
|
||||
},
|
||||
layers: { city: layer("city"), vegetation: layer("vegetation") },
|
||||
};
|
||||
}
|
||||
|
||||
function labPayload(route = routeVideo()) {
|
||||
return {
|
||||
schema_version: "missioncore.lab-v1-vegetation-shadow/v1",
|
||||
result_id: resultId,
|
||||
created_at_utc: "2026-08-27T20:00:00Z",
|
||||
status: "visual-shadow-ready-policy-not-authorized",
|
||||
ground_truth: false,
|
||||
identity: { selected_candidate: "ddrnet" },
|
||||
metrics: {
|
||||
candidates: {
|
||||
ddrnet: candidate("ddrnet", 0.64),
|
||||
ppliteseg: candidate("ppliteseg", 0.61),
|
||||
},
|
||||
},
|
||||
decision: {
|
||||
selected_candidate: "ddrnet",
|
||||
visual_shadow_ready: true,
|
||||
mission_policy_ready_for_configuration: true,
|
||||
navigation_accepted: false,
|
||||
production_accepted: false,
|
||||
},
|
||||
limitations: ["shadow only"],
|
||||
authority: {
|
||||
commands_enabled: false,
|
||||
navigation_or_safety_accepted: false,
|
||||
actuation_accepted: false,
|
||||
camera_semantics_can_clear_rigid_geometry: false,
|
||||
},
|
||||
catalogs: {
|
||||
goose: Array.from({ length: 12 }, (_, index) => visualCase("goose", index)),
|
||||
ravnoves: [],
|
||||
},
|
||||
route_video: route,
|
||||
access: "read-only",
|
||||
};
|
||||
}
|
||||
|
||||
test("vegetation LAB keeps autonomous assets and fail-closed authority", async () => {
|
||||
let requestedUrl = "";
|
||||
const result = await fetchVegetationShadowResult(resultId, {
|
||||
fetcher: async (url) => {
|
||||
requestedUrl = String(url);
|
||||
return new Response(JSON.stringify(labPayload()), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
},
|
||||
});
|
||||
assert.equal(
|
||||
requestedUrl,
|
||||
`/api/v1/laboratory/vegetation-shadow/${resultId}`,
|
||||
);
|
||||
assert.equal(result.selectedCandidate, "ddrnet");
|
||||
assert.equal(result.candidates[0].vegetationMeanIouPercent, 64);
|
||||
assert.equal(result.routeCases.length, 0);
|
||||
assert.equal(result.validationCases.length, 12);
|
||||
assert.equal(result.routeVideo.frameCount, 4489);
|
||||
assert.equal(result.routeVideo.viewKind, "fine-semantic-prediction");
|
||||
assert.equal(result.routeVideo.linkedTgsResultId, null);
|
||||
assert.equal(result.routeVideo.taxonomy[0].disposition, "undefined");
|
||||
assert.equal(result.validationCases[0].focus.className, "high_grass");
|
||||
assert.match(result.validationCases[0].assets.ddrnet_error, /\/assets\/visual\/goose\//);
|
||||
assert.deepEqual(result.authority, {
|
||||
commandsEnabled: false,
|
||||
navigationOrSafetyAccepted: false,
|
||||
actuationAccepted: false,
|
||||
cameraSemanticsCanClearRigidGeometry: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("vegetation LAB parses coarse material policy and sealed TGS binding", async () => {
|
||||
const result = await fetchVegetationShadowResult(resultId, {
|
||||
fetcher: async () => new Response(JSON.stringify(labPayload(coarseRouteVideo())), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}),
|
||||
});
|
||||
assert.equal(result.routeVideo.viewKind, "coarse-material-policy-review");
|
||||
assert.match(result.routeVideo.linkedTgsResultId, /^m49-tgs-full-shadow-/);
|
||||
assert.equal(result.routeVideo.taxonomy.length, 10);
|
||||
assert.equal(result.routeVideo.taxonomy[0].evidenceState, "UNOBSERVED");
|
||||
assert.equal(result.routeVideo.policyPresets.urban.grass, "NO_GO");
|
||||
assert.equal(result.routeVideo.fusionMode, "synchronised-multilayer-review");
|
||||
});
|
||||
|
||||
test("vegetation LAB parses the full 004 pass inside the existing result contract", async () => {
|
||||
const payload = {
|
||||
...labPayload(null),
|
||||
catalogs: { goose: [], ravnoves: [] },
|
||||
route_full_review: fullRouteReview(),
|
||||
};
|
||||
const timeline = new ArrayBuffer(6830 * 8);
|
||||
const timelineView = new DataView(timeline);
|
||||
for (let index = 0; index < 6830; index += 1) {
|
||||
timelineView.setBigUint64(
|
||||
index * 8,
|
||||
BigInt(39_215_263_458 + index * 100_000_000),
|
||||
true,
|
||||
);
|
||||
}
|
||||
const result = await fetchVegetationShadowResult(resultId, {
|
||||
fetcher: async (url) => String(url).endsWith("/route-timeline")
|
||||
? new Response(timeline, {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
ETag: `"${"5".repeat(64)}"`,
|
||||
},
|
||||
})
|
||||
: new Response(JSON.stringify(payload), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}),
|
||||
});
|
||||
assert.equal(result.routeVideo, null);
|
||||
assert.equal(result.routeFullReview.frameCount, 6830);
|
||||
assert.equal(result.routeFullReview.city.taxonomy.length, 16);
|
||||
assert.equal(result.routeFullReview.vegetation.taxonomy.length, 64);
|
||||
assert.equal(result.routeFullReview.decodeRepair.sequence, 6092);
|
||||
assert.equal(result.routeFullReview.frameSourceTimesNs.length, 6830);
|
||||
assert.equal(
|
||||
vegetationFullRouteMaskUrl(resultId, "vegetation", 6829),
|
||||
`/api/v1/laboratory/vegetation-shadow/${resultId}/route-masks/vegetation/6829`,
|
||||
);
|
||||
});
|
||||
|
||||
test("vegetation GOOSE benchmark opens through its separate archival endpoint", async () => {
|
||||
let requestedUrl = "";
|
||||
const result = await fetchVegetationBenchmarkResult(benchmarkResultId, {
|
||||
fetcher: async (url) => {
|
||||
requestedUrl = String(url);
|
||||
return new Response(JSON.stringify({
|
||||
...labPayload(null),
|
||||
result_id: benchmarkResultId,
|
||||
}), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
},
|
||||
});
|
||||
assert.equal(
|
||||
requestedUrl,
|
||||
`/api/v1/laboratory/vegetation-benchmark/${benchmarkResultId}`,
|
||||
);
|
||||
assert.equal(result.routeVideo, null);
|
||||
assert.equal(result.validationCases.length, 12);
|
||||
});
|
||||
|
||||
test("vegetation realtime LAB and archival benchmark use separate admitted instruments", async () => {
|
||||
const [resultSource, benchmarkSource] = await Promise.all([
|
||||
readFile(
|
||||
new URL("../src/workspaces/laboratory/VegetationShadowResult.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
readFile(
|
||||
new URL("../src/workspaces/laboratory/VegetationBenchmarkResult.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
]);
|
||||
assert.doesNotMatch(resultSource, /M48MaskComparisonVisual/);
|
||||
assert.match(resultSource, /M4ReplayThreatVisual/);
|
||||
assert.match(resultSource, /M49TgsFullShadowEvidence/);
|
||||
assert.match(resultSource, /semanticOverride/);
|
||||
assert.match(resultSource, /EoMT CITY \/ DDRNet VEGETATION/);
|
||||
assert.equal(resultSource.match(/<LaboratoryEvidence\b/g)?.length, 4);
|
||||
assert.match(resultSource, /RAVNOVES004TREE mixed route review/);
|
||||
assert.match(resultSource, /RAVNOVES004TREE full recorded review/);
|
||||
assert.match(resultSource, /LaboratoryRecordedClipPlayer/);
|
||||
assert.match(resultSource, /className="m48-clip-player__overlay"/);
|
||||
assert.match(resultSource, /linkedTgsResultId/);
|
||||
assert.match(benchmarkSource, /M48MaskComparisonVisual/);
|
||||
assert.doesNotMatch(benchmarkSource, /M49TgsFullShadowEvidence/);
|
||||
assert.equal(benchmarkSource.match(/<LaboratoryEvidence\b/g)?.length, 1);
|
||||
assert.doesNotMatch(resultSource, /VegetationRouteVisual|urban\/rural\/off-road presets/);
|
||||
await assert.rejects(
|
||||
access(new URL("../src/workspaces/laboratory/VegetationShadowVisual.tsx", import.meta.url)),
|
||||
{ code: "ENOENT" },
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-evidence-definition/v1",
|
||||
"work_id": "lab-v1-vegetation-benchmark",
|
||||
"evidence": {
|
||||
"runtime_relative_root": "lab-v1-vegetation-benchmark/results",
|
||||
"result_id_prefix": "lab-v1-vegetation-benchmark",
|
||||
"document_name": "result.json",
|
||||
"schema_version": "missioncore.lab-v1-vegetation-shadow/v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-evidence-definition/v1",
|
||||
"work_id": "lab-v1-vegetation-shadow",
|
||||
"evidence": {
|
||||
"runtime_relative_root": "lab-v1-vegetation/results",
|
||||
"result_id_prefix": "lab-v1-vegetation-shadow",
|
||||
"document_name": "result.json",
|
||||
"schema_version": "missioncore.lab-v1-vegetation-shadow/v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-evidence-definition/v1",
|
||||
"work_id": "m48-static-occupancy-qualification",
|
||||
"evidence": {
|
||||
"runtime_relative_root": "m48/static-occupancy-qualification-results",
|
||||
"result_id_prefix": "m48-static-occupancy-qualification",
|
||||
"document_name": "manifest.json",
|
||||
"schema_version": "missioncore.m48-static-occupancy-qualification-result/v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-evidence-definition/v1",
|
||||
"work_id": "m48r3-static-occupancy-shadow",
|
||||
"evidence": {
|
||||
"runtime_relative_root": "m48/static-occupancy-shadow-results",
|
||||
"result_id_prefix": "m48r3-static-occupancy-shadow",
|
||||
"document_name": "manifest.json",
|
||||
"schema_version": "missioncore.m48r3-static-occupancy-shadow-result/v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-evidence-definition/v2",
|
||||
"work_id": "m48t-risk-quality-temporal",
|
||||
"evidence_lifecycle": [
|
||||
{
|
||||
"phase": "legacy-quality",
|
||||
"runtime_relative_root": "m48t-risk-quality/lab-results",
|
||||
"result_id_prefix": "m48t-risk-quality-temporal-lab",
|
||||
"document_name": "manifest.json",
|
||||
"schema_version": "missioncore.m48t-risk-quality-temporal-lab/v1"
|
||||
},
|
||||
{
|
||||
"phase": "result",
|
||||
"runtime_relative_root": "m48t-risk-quality/native-lab-results",
|
||||
"result_id_prefix": "m48q-native-risk-quality-lab",
|
||||
"document_name": "manifest.json",
|
||||
"schema_version": "missioncore.m48q-native-risk-quality-lab/v1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-evidence-definition/v1",
|
||||
"work_id": "m49-tgs-fail-closed-evidence",
|
||||
"evidence": {
|
||||
"runtime_relative_root": "m49/tgs-fail-closed-results",
|
||||
"result_id_prefix": "m49-tgs-fail-closed",
|
||||
"document_name": "manifest.json",
|
||||
"schema_version": "missioncore.m49-tgs-fail-closed-result/v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-evidence-definition/v1",
|
||||
"work_id": "m49-tgs-full-shadow",
|
||||
"evidence": {
|
||||
"runtime_relative_root": "m49/tgs-full-shadow-results",
|
||||
"result_id_prefix": "m49-tgs-full-shadow",
|
||||
"document_name": "manifest.json",
|
||||
"schema_version": "missioncore.m49-tgs-full-shadow-lab/v1"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,26 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-execution-registry/v1",
|
||||
"definitions": [
|
||||
{
|
||||
"work_id": "m48-static-occupancy-qualification",
|
||||
"lifecycle": "canonical",
|
||||
"isolation": "core-adapter",
|
||||
"adapter_id": "canonical.m48-static-occupancy-qualification/v1",
|
||||
"input_roles": [
|
||||
"repository_root",
|
||||
"profile_path",
|
||||
"m47_lab_root",
|
||||
"graph_result_root",
|
||||
"small_static_result_root"
|
||||
],
|
||||
"contracts": {
|
||||
"source": "missioncore.m48-static-occupancy-source-set/v1",
|
||||
"provider": "missioncore.m48-additive-low-step-occupancy/v1",
|
||||
"graph": "missioncore.m48-static-occupancy-case/v1",
|
||||
"run": "missioncore.laboratory-run/v1",
|
||||
"evidence": "missioncore.m48-static-occupancy-qualification-result/v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"work_id": "m48-small-static-passage-regression",
|
||||
"lifecycle": "canonical",
|
||||
@@ -128,9 +148,72 @@
|
||||
"run": "missioncore.laboratory-run/v1",
|
||||
"evidence": "missioncore.m48s-fixed-class-detector-lab/v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"work_id": "m48t-risk-quality-temporal",
|
||||
"lifecycle": "experimental",
|
||||
"isolation": "bounded-adapter",
|
||||
"adapter_id": "experimental.m48t-risk-quality-temporal/v1",
|
||||
"input_roles": ["repository_root"],
|
||||
"contracts": {
|
||||
"source": "missioncore.m48t-sealed-quality-temporal-source-set/v1",
|
||||
"provider": "missioncore.rf-detr-risk-quality-provider/v1",
|
||||
"graph": "missioncore.m48t-risk-quality-temporal-lab-graph/v1",
|
||||
"run": "missioncore.laboratory-run/v1",
|
||||
"evidence": "missioncore.m48t-risk-quality-temporal-lab/v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"work_id": "m49-tgs-fail-closed-evidence",
|
||||
"lifecycle": "experimental",
|
||||
"isolation": "bounded-adapter",
|
||||
"adapter_id": "experimental.m49-tgs-fail-closed-evidence/v1",
|
||||
"input_roles": ["repository_root"],
|
||||
"contracts": {
|
||||
"source": "missioncore.m49-tgs-worker-evidence/v1",
|
||||
"provider": "missioncore.travel-tgs-ground-segmentation/v1",
|
||||
"graph": "missioncore.m49-fail-closed-costmap-evidence/v1",
|
||||
"run": "missioncore.laboratory-run/v1",
|
||||
"evidence": "missioncore.m49-tgs-fail-closed-result/v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"work_id": "m49-tgs-full-shadow",
|
||||
"lifecycle": "experimental",
|
||||
"isolation": "bounded-adapter",
|
||||
"adapter_id": "experimental.m49-tgs-full-shadow/v1",
|
||||
"input_roles": ["repository_root"],
|
||||
"contracts": {
|
||||
"source": "missioncore.m49-tgs-full-shadow-result/v1",
|
||||
"provider": "missioncore.travel-tgs-ground-segmentation/v1",
|
||||
"graph": "missioncore.m49-tgs-full-source-paced-shadow/v1",
|
||||
"run": "missioncore.laboratory-run/v1",
|
||||
"evidence": "missioncore.m49-tgs-full-shadow-lab/v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"work_id": "lab-v1-vegetation-shadow",
|
||||
"lifecycle": "experimental",
|
||||
"isolation": "bounded-adapter",
|
||||
"adapter_id": "experimental.lab-v1-vegetation-shadow/v1",
|
||||
"input_roles": [
|
||||
"ddrnet_goose_root",
|
||||
"ppliteseg_goose_root",
|
||||
"ddrnet_ravnoves_root",
|
||||
"ppliteseg_ravnoves_root"
|
||||
],
|
||||
"contracts": {
|
||||
"source": "missioncore.goose-ravnoves-vegetation-source-set/v1",
|
||||
"provider": "missioncore.goose-fine64-ready-weight-provider/v1",
|
||||
"graph": "missioncore.vegetation-mission-policy-shadow-graph/v1",
|
||||
"run": "missioncore.laboratory-run/v1",
|
||||
"evidence": "missioncore.lab-v1-vegetation-shadow/v1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"legacy_work_ids": [
|
||||
"lab-v1-vegetation-benchmark",
|
||||
"m48r3-static-occupancy-shadow",
|
||||
"m47-reference-graph-shadow",
|
||||
"e31-source-binding",
|
||||
"e32-track-geometry",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "missioncore.laboratory-value-review-registry/v1",
|
||||
"reviewed_at_utc": "2026-08-25T11:06:28Z",
|
||||
"reviewed_at_utc": "2026-08-27T20:59:10Z",
|
||||
"entries": [
|
||||
{
|
||||
"catalog_id": "e28-local-surface",
|
||||
@@ -247,9 +247,51 @@
|
||||
"lifecycle": "current",
|
||||
"visual_evidence": "available"
|
||||
},
|
||||
{
|
||||
"catalog_id": "m48-static-occupancy-qualification",
|
||||
"evidence_id": "m48-static-occupancy-qualification-568024554cff011332ff19ca4739f70555a6232c0607dec2a71be6db408ea69a",
|
||||
"signal": "progress",
|
||||
"lifecycle": "current",
|
||||
"visual_evidence": "available"
|
||||
},
|
||||
{
|
||||
"catalog_id": "m48s-fixed-class-detector",
|
||||
"evidence_id": "m48s-fixed-class-detector-lab-d1bac05a9e43d407b0f931105cc0e84183ef9ff37666911f03c41486beeb7ef9",
|
||||
"evidence_id": "m48s-fixed-class-detector-lab-4a901d811f53734540337f8d1f2c01666539aa0a9b7786f26d4f1f2e08cc858a",
|
||||
"signal": "progress",
|
||||
"lifecycle": "current",
|
||||
"visual_evidence": "available"
|
||||
},
|
||||
{
|
||||
"catalog_id": "m48t-risk-quality-temporal",
|
||||
"evidence_id": "m48q-native-risk-quality-lab-e8961d4db8ffb751503b9646bc8eeebec6c80c948ce2f5b4fa5b89c471e673c1",
|
||||
"signal": "progress",
|
||||
"lifecycle": "current",
|
||||
"visual_evidence": "available"
|
||||
},
|
||||
{
|
||||
"catalog_id": "m49-tgs-fail-closed-evidence",
|
||||
"evidence_id": "m49-tgs-fail-closed-9d5cb089bb5cc23f829acb47eda52eaa886db3b60f8fa7d57e02e27f642e837b",
|
||||
"signal": "progress",
|
||||
"lifecycle": "current",
|
||||
"visual_evidence": "available"
|
||||
},
|
||||
{
|
||||
"catalog_id": "m49-tgs-full-shadow",
|
||||
"evidence_id": "m49-tgs-full-shadow-0faeaaf3aba8dccae974eab51ff9cccf264a13ec285abb1920c1e5a09a7e87bc",
|
||||
"signal": "progress",
|
||||
"lifecycle": "current",
|
||||
"visual_evidence": "available"
|
||||
},
|
||||
{
|
||||
"catalog_id": "lab-v1-vegetation-benchmark",
|
||||
"evidence_id": "lab-v1-vegetation-benchmark-a8944d6c2d1102d81da78bcb4963760c9288db0421d9f2686afcbdd14b610d3d",
|
||||
"signal": "progress",
|
||||
"lifecycle": "current",
|
||||
"visual_evidence": "available"
|
||||
},
|
||||
{
|
||||
"catalog_id": "lab-v1-vegetation-shadow",
|
||||
"evidence_id": "lab-v1-vegetation-shadow-d179462134967ace1c5ebd6fbdbdd8659905d390484b9c01ea7930f083bb74d1",
|
||||
"signal": "progress",
|
||||
"lifecycle": "current",
|
||||
"visual_evidence": "available"
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"schema_version": "missioncore.lab-v1-goose-vegetation-benchmark/v1",
|
||||
"lab_id": "LAB-V1",
|
||||
"worker_id": "worker-006",
|
||||
"runtime": {
|
||||
"super_gradients_version": "3.2.0",
|
||||
"super_gradients_revision": "54d062ecb1081944a672ce447cf3e96a36708ff9",
|
||||
"python_version": "3.9",
|
||||
"numpy_version": "1.23.0",
|
||||
"cmake_version": "3.31.6",
|
||||
"onnxsim_version": "0.4.36",
|
||||
"opencv_python_version": "4.8.1.78",
|
||||
"pytorch_version": "1.13.1",
|
||||
"torchvision_version": "0.14.1",
|
||||
"pytorch_cuda_version": "11.7",
|
||||
"container_base": "nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04@sha256:ad6d59a3bbf3e82c1c849c9ac09cfc2a3e0bbb8655042fd899be6681b3fe2a85",
|
||||
"miniconda_installer": "Miniconda3-py39_24.11.1-0-Linux-x86_64.sh",
|
||||
"miniconda_installer_sha256": "3ea8373098d72140e08aac9217822b047ec094eb457e7f73945af7c6f68bf6f5"
|
||||
},
|
||||
"dataset": {
|
||||
"dataset_id": "goose-2d-validation-visible-rgb",
|
||||
"relative_root": "goose-2d/validation",
|
||||
"mapping_relative_path": "goose_label_mapping.csv",
|
||||
"mapping_sha256": "88ae319ba5a3877dd3ae0773f693a6a5fdc283934140de9dfaff029108aefd7f",
|
||||
"image_glob": "images/val/**/*_windshield_vis.png",
|
||||
"expected_pair_count": 962,
|
||||
"input_size": [512, 512],
|
||||
"preprocessing": [
|
||||
"center-square-crop",
|
||||
"nearest-neighbor-resize",
|
||||
"rgb-to-tensor-0-1"
|
||||
]
|
||||
},
|
||||
"candidates": {
|
||||
"ddrnet": {
|
||||
"candidate_id": "goose-ddrnet-class-512",
|
||||
"model_names": ["ddrnet_39"],
|
||||
"checkpoint_relative_path": "models/goose/ddrnet_class_512.pth",
|
||||
"checkpoint_size_bytes": 259419077,
|
||||
"checkpoint_sha256": "b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6",
|
||||
"published_validation_miou_percent": 46.53
|
||||
},
|
||||
"ppliteseg": {
|
||||
"candidate_id": "goose-ppliteseg-class-512",
|
||||
"model_names": [
|
||||
"pp_lite_t_seg",
|
||||
"pp_lite_t_seg50",
|
||||
"pp_lite_t_seg75",
|
||||
"pp_lite_b_seg",
|
||||
"pp_lite_b_seg50",
|
||||
"pp_lite_b_seg75"
|
||||
],
|
||||
"checkpoint_relative_path": "models/goose/ppliteseg_class_512.pth",
|
||||
"checkpoint_size_bytes": 98208249,
|
||||
"checkpoint_sha256": "6dd412c0c99115e359896c4cab43a8e6bce9e09b843e7fa885fe597b0a6121cd",
|
||||
"published_validation_miou_percent": 45.09
|
||||
}
|
||||
},
|
||||
"ravnoves": {
|
||||
"source_id": "RAVNOVES00/right-cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8",
|
||||
"source_sha256": "cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8",
|
||||
"base_m4_result_id": "m4-threat-replay-2a953c5f27f2a5b1dddc5c658c1de2c323d7796084a099c024987a1da03aa324",
|
||||
"expected_width": 800,
|
||||
"expected_height": 600,
|
||||
"expected_frame_count": 4489,
|
||||
"frame_indices": [0, 253, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 4488],
|
||||
"crop_contract": "center-600-square-to-512; outside-crop-is-undefined"
|
||||
},
|
||||
"vegetation_class_names": [
|
||||
"leaves",
|
||||
"forest",
|
||||
"bush",
|
||||
"moss",
|
||||
"tree_crown",
|
||||
"tree_trunk",
|
||||
"crops",
|
||||
"low_grass",
|
||||
"high_grass",
|
||||
"scenery_vegetation",
|
||||
"hedge",
|
||||
"tree_root"
|
||||
],
|
||||
"visual_case_contract": {
|
||||
"selection_basis": "ground-truth-class-support-only",
|
||||
"case_count": 12,
|
||||
"minimum_focus_pixels": 2048,
|
||||
"strata": [
|
||||
{ "class_name": "high_grass", "count": 2 },
|
||||
{ "class_name": "low_grass", "count": 2 },
|
||||
{ "class_name": "bush", "count": 2 },
|
||||
{ "class_name": "tree_trunk", "count": 2 },
|
||||
{ "class_name": "tree_crown", "count": 1 },
|
||||
{ "class_name": "hedge", "count": 1 },
|
||||
{ "class_name": "forest", "count": 1 },
|
||||
{ "class_name": "crops", "count": 1 }
|
||||
],
|
||||
"error_overlay": {
|
||||
"correct_material_rgba": [34, 197, 94, 72],
|
||||
"missed_vegetation_rgba": [239, 68, 68, 220],
|
||||
"false_vegetation_rgba": [245, 158, 11, 220],
|
||||
"wrong_vegetation_material_rgba": [168, 85, 247, 220]
|
||||
}
|
||||
},
|
||||
"policy_action_colors": {
|
||||
"ALLOW": "#22c55e",
|
||||
"HIGH_COST": "#f59e0b",
|
||||
"NO_GO": "#ef4444"
|
||||
},
|
||||
"invariants": {
|
||||
"one_heavy_candidate_at_a_time": true,
|
||||
"raw_fisheye_is_immutable": true,
|
||||
"outside_center_crop_is_free": false,
|
||||
"missing_or_unknown_is_free": false,
|
||||
"camera_semantics_can_clear_rigid_geometry": false,
|
||||
"navigation_authority": false,
|
||||
"actuation_authority": false,
|
||||
"canonical_triton_mutation_allowed": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"schema_version": "missioncore.lab-v1-ravnoves-source/v1",
|
||||
"profile_id": "ravnoves004tree-full-video-source/v1",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES004TREE/right-e5eb017e2cc0f546736eda5235ca157b501913093cb64af5e548e335417e1bac",
|
||||
"source_sha256": "e5eb017e2cc0f546736eda5235ca157b501913093cb64af5e548e335417e1bac",
|
||||
"source_job_id": "recorded-camera-eb2783c5480d56bda07c8af0",
|
||||
"source_job_input_sha256": "eb2783c5480d56bda07c8af008dff5344d19dc550ef70fe2075d6f098f7cc715",
|
||||
"session_id": "20260828T130511Z_viewer_live",
|
||||
"base_m4_result_id": null,
|
||||
"expected_width": 800,
|
||||
"expected_height": 600,
|
||||
"expected_frame_count": 6830,
|
||||
"timeline_start_seconds": 39.215263458,
|
||||
"timeline_end_seconds": 757.260263458,
|
||||
"frame_indices": [],
|
||||
"crop_contract": "center-600-square-to-512; outside-crop-is-undefined"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"schema_version": "missioncore.vegetation-candidate-manifest/v1",
|
||||
"lab_id": "LAB-V1",
|
||||
"ops_issue_id": "88aff22a-43aa-48fb-b7eb-ac424d987d37",
|
||||
"frozen_utc": "2026-08-27T18:39:00Z",
|
||||
"worker": {
|
||||
"worker_id": "worker-006",
|
||||
"candidate_root": "D:\\NDC_MISSIONCORE\\datasets\\vegetation-v1\\observed-2026-08-27",
|
||||
"canonical_runtime_mutation_allowed": false
|
||||
},
|
||||
"upstream_sources": [
|
||||
{
|
||||
"source_id": "wildscenes",
|
||||
"repository": "https://github.com/csiro-robotics/WildScenes.git",
|
||||
"revision": "9eb4e10b4483a634159e2b371be0437e465fe218",
|
||||
"worker_relative_path": "sources/wildscenes"
|
||||
},
|
||||
{
|
||||
"source_id": "rellis-3d",
|
||||
"repository": "https://github.com/unmannedlab/RELLIS-3D.git",
|
||||
"revision": "c17a118fcaed1559f03cc32cc3a91dedc557f8b8",
|
||||
"worker_relative_path": "sources/rellis-3d"
|
||||
},
|
||||
{
|
||||
"source_id": "orfd-offnet",
|
||||
"repository": "https://github.com/chaytonmin/Off-Road-Freespace-Detection.git",
|
||||
"revision": "50e63d24836198e8fb5af707e521f414104b4876",
|
||||
"worker_relative_path": "sources/orfd"
|
||||
}
|
||||
],
|
||||
"candidate_assets": [
|
||||
{
|
||||
"candidate_id": "goose-ppliteseg-category-512",
|
||||
"modality": "camera-2d",
|
||||
"family": "ppliteseg",
|
||||
"output_contract": "goose-category-12",
|
||||
"input_resolution": [512, 512],
|
||||
"relative_path": "models/goose/ppliteseg_category_512.pth",
|
||||
"size_bytes": 98180357,
|
||||
"sha256": "87bf55a1ae994a4bdf3a4d30c8f0dec2916994b37d433f0b5b694d63157ee0ab",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "super-gradients-compatibility-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "goose-ppliteseg-class-512",
|
||||
"modality": "camera-2d",
|
||||
"family": "ppliteseg",
|
||||
"output_contract": "goose-class-64",
|
||||
"input_resolution": [512, 512],
|
||||
"relative_path": "models/goose/ppliteseg_class_512.pth",
|
||||
"size_bytes": 98208249,
|
||||
"sha256": "6dd412c0c99115e359896c4cab43a8e6bce9e09b843e7fa885fe597b0a6121cd",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "super-gradients-compatibility-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "goose-ddrnet-category-512",
|
||||
"modality": "camera-2d",
|
||||
"family": "ddrnet",
|
||||
"output_contract": "goose-category-12",
|
||||
"input_resolution": [512, 512],
|
||||
"relative_path": "models/goose/ddrnet_category_512.pth",
|
||||
"size_bytes": 259313579,
|
||||
"sha256": "ddab58d3b27309e4e1545ecb0eafbe077f3ebd58fe7120defe44478424c2a20e",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "super-gradients-compatibility-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "goose-ddrnet-class-512",
|
||||
"modality": "camera-2d",
|
||||
"family": "ddrnet",
|
||||
"output_contract": "goose-class-64",
|
||||
"input_resolution": [512, 512],
|
||||
"relative_path": "models/goose/ddrnet_class_512.pth",
|
||||
"size_bytes": 259419077,
|
||||
"sha256": "b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "super-gradients-compatibility-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "rellis-hrnet-ocr",
|
||||
"modality": "camera-2d",
|
||||
"family": "hrnet-ocr",
|
||||
"output_contract": "rellis-20-class",
|
||||
"relative_path": "models/rellis-3d/hrnet_best.zip",
|
||||
"size_bytes": 788183119,
|
||||
"sha256": "2842b7c427d9abb3f34725dea306b72422af5293cd8289da3035edff81deac27",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "upstream-validation-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "rellis-gscnn",
|
||||
"modality": "camera-2d",
|
||||
"family": "gscnn",
|
||||
"output_contract": "rellis-20-class",
|
||||
"relative_path": "models/rellis-3d/gscnn_best.pth",
|
||||
"size_bytes": 1098515419,
|
||||
"sha256": "d77a83032ff9b3dea74bdbdd9bb12c0810ddff0dce6a02d42264c592fbdc0b18",
|
||||
"asset_status": "accepted-size-and-hash-legacy-pickle",
|
||||
"runner_status": "upstream-validation-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "rellis-salsanext",
|
||||
"modality": "lidar-3d",
|
||||
"family": "salsanext",
|
||||
"output_contract": "rellis-20-class",
|
||||
"relative_path": "models/rellis-3d/salsanext_best.zip",
|
||||
"size_bytes": 164312336,
|
||||
"sha256": "6cab4f0c4ac556f9597d338692f2dee1a9e9438941f9d85159685616b948fafb",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "native-scan-compatibility-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "rellis-kpconv",
|
||||
"modality": "lidar-3d",
|
||||
"family": "kpconv",
|
||||
"output_contract": "rellis-20-class",
|
||||
"relative_path": "models/rellis-3d/kpconv_best.zip",
|
||||
"size_bytes": 1522250650,
|
||||
"sha256": "d2a11b7a66290cce3d592e830889c3bcb188c62ced83092a7201765621b8bfc3",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "native-scan-compatibility-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "wildscenes-model-bundle",
|
||||
"modality": "camera-2d-and-lidar-3d",
|
||||
"family": "mmsegmentation-and-mmdetection3d",
|
||||
"output_contract": "wildscenes-natural-environment",
|
||||
"bundle_entries": [
|
||||
"spvcnn_wildscenes.pth",
|
||||
"minkunet_wildscenes.pth",
|
||||
"deeplabv3_wildscenes.pth",
|
||||
"segformer_wildscenes.pth",
|
||||
"cylinder3d_wildscenes.pth",
|
||||
"mask2former_swin_wildscenes.pth",
|
||||
"upernet_convnext_wildscenes.pth",
|
||||
"mask2former_resnet_wildscenes.pth"
|
||||
],
|
||||
"relative_path": "models/wildscenes/WildScenes-Models.zip",
|
||||
"size_bytes": 8637507567,
|
||||
"sha256": "0b5040b157e928263bdbefeaffbd36414c2cb641ebc70713b3be3460c1feaf2b",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "upstream-docker-validation-probe-required"
|
||||
},
|
||||
{
|
||||
"candidate_id": "orfd-offnet-roadseg",
|
||||
"modality": "camera-lidar-fusion",
|
||||
"family": "offnet",
|
||||
"output_contract": "binary-freespace",
|
||||
"relative_path": "models/orfd-offnet/OFF-Net/best_net_RoadSeg.pth",
|
||||
"size_bytes": 100976531,
|
||||
"sha256": "4d82a9ba1c5411a8159e1a262f1741a6a163c8bd9751d52a90fb10deb237650d",
|
||||
"asset_status": "accepted",
|
||||
"runner_status": "upstream-validation-probe-required"
|
||||
}
|
||||
],
|
||||
"execution_sequence": [
|
||||
"upstream-runner-reproduction",
|
||||
"official-validation-sample",
|
||||
"native-fisheye-or-lidar-compatibility",
|
||||
"shared-vegetation-label-mapping",
|
||||
"recorded-shadow-quality-and-resource-tournament",
|
||||
"mission-policy-composition-without-actuation"
|
||||
],
|
||||
"invariants": {
|
||||
"one_heavy_candidate_at_a_time": true,
|
||||
"raw_fisheye_is_immutable": true,
|
||||
"missing_or_unknown_is_free": false,
|
||||
"semantic_label_can_clear_rigid_geometry": false,
|
||||
"preset_can_override_explicit_mission_rule": false,
|
||||
"navigation_authority": false,
|
||||
"actuation_authority": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"schema_version": "missioncore.lab-v1-vegetation-integrated-shadow-profile/v3",
|
||||
"profile_id": "lab-v1-ravnoves00-ddrnet-m49-integrated-multirate-phased-shadow/v3",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"expected_timeline_frames": 4489,
|
||||
"requested_source_rate_hz": 12.0,
|
||||
"shared_start_barrier": true,
|
||||
"ground_truth_available": false
|
||||
},
|
||||
"stages": {
|
||||
"m49_graph_tgs": {
|
||||
"profile": "m49-tgs-integrated-graph-shadow-v1.json",
|
||||
"profile_sha256": "b61e018b2d04eec58802e2d4186ce7a3dd3a15b254db106b57b609e903eeef80",
|
||||
"candidate": "frozen-native-rf-detr-plus-cpu-tgs",
|
||||
"parameters_unchanged": true,
|
||||
"timeline_rate_hz": 12.0
|
||||
},
|
||||
"vegetation": {
|
||||
"candidate_id": "ddrnet_39-goose-fine-64",
|
||||
"candidate_key": "ddrnet",
|
||||
"checkpoint_sha256": "b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6",
|
||||
"config_sha256": "96a427a8baae387b827ec9c0bf7ca42e3fb9114b8fa9a8671bbc9d10877670b9",
|
||||
"policy_sha256": "b75c4ac841d7b4bcc57f7a9c8417ca2317d8ecfa499e72a9af8a8591a2ec0d35",
|
||||
"provider_map_sha256": "f2b69046b6a740fd9532d2d88e7fabae7c20fb662f783c9502adc9026406f352",
|
||||
"container_image": "ndc/mission-core-lab-v1-goose:sg3.2.0-cu117-v1",
|
||||
"container_image_id": "sha256:591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd",
|
||||
"timeline_rate_hz": 12.0,
|
||||
"inference_rate_hz": 6.0,
|
||||
"inference_stride": 2,
|
||||
"inference_phase_offset_ms": 40.0,
|
||||
"held_evidence_fail_closed": true,
|
||||
"semantic_output_persisted": false,
|
||||
"one_heavy_vegetation_candidate_at_a_time": true
|
||||
}
|
||||
},
|
||||
"acceptance": {
|
||||
"minimum_graph_world_state_fps": 11.209069,
|
||||
"minimum_vegetation_timeline_fps": 11.209069,
|
||||
"minimum_vegetation_inference_fps": 5.604534,
|
||||
"maximum_vegetation_inference_completion_p95_ms": 125.0,
|
||||
"maximum_semantic_evidence_source_age_ms": 125.0,
|
||||
"maximum_combined_output_age_p99_ms": 125.0,
|
||||
"capacity_drop_count_max": 0,
|
||||
"unaccounted_frame_count_max": 0
|
||||
},
|
||||
"telemetry": {
|
||||
"sample_interval_seconds": 1.0,
|
||||
"required_roles": [
|
||||
"graph",
|
||||
"triton",
|
||||
"tgs",
|
||||
"vegetation"
|
||||
]
|
||||
},
|
||||
"invariants": {
|
||||
"raw_fisheye_immutable": true,
|
||||
"reference_graph_parameters_unchanged": true,
|
||||
"tgs_parameters_unchanged": true,
|
||||
"ddrnet_parameters_unchanged": true,
|
||||
"safety_layers_remain_12hz": true,
|
||||
"vegetation_gpu_phase_follows_safety_detector": true,
|
||||
"held_semantic_evidence_is_advisory_only": true,
|
||||
"vegetation_source_buffer_bounded": true,
|
||||
"vegetation_full_route_rgb_prefetch_allowed": false,
|
||||
"ppliteseg_concurrent_run_allowed": false,
|
||||
"camera_semantics_can_clear_rigid_geometry": false,
|
||||
"canonical_triton_mutation_allowed": false,
|
||||
"runtime_shared_source_frame_target": true,
|
||||
"gauss_or_playcanvas_in_scope": false
|
||||
},
|
||||
"authority": {
|
||||
"visual_quality_accepted": false,
|
||||
"route_truth_available": false,
|
||||
"traversability_accepted": false,
|
||||
"physical_free_space_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false,
|
||||
"production_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"schema_version": "missioncore.lab-v1-vegetation-integrated-shadow-profile/v2",
|
||||
"profile_id": "lab-v1-ravnoves00-ddrnet-m49-integrated-multirate-shadow/v2",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"expected_timeline_frames": 4489,
|
||||
"requested_source_rate_hz": 12.0,
|
||||
"shared_start_barrier": true,
|
||||
"ground_truth_available": false
|
||||
},
|
||||
"stages": {
|
||||
"m49_graph_tgs": {
|
||||
"profile": "m49-tgs-integrated-graph-shadow-v1.json",
|
||||
"profile_sha256": "b61e018b2d04eec58802e2d4186ce7a3dd3a15b254db106b57b609e903eeef80",
|
||||
"candidate": "frozen-native-rf-detr-plus-cpu-tgs",
|
||||
"parameters_unchanged": true,
|
||||
"timeline_rate_hz": 12.0
|
||||
},
|
||||
"vegetation": {
|
||||
"candidate_id": "ddrnet_39-goose-fine-64",
|
||||
"candidate_key": "ddrnet",
|
||||
"checkpoint_sha256": "b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6",
|
||||
"config_sha256": "96a427a8baae387b827ec9c0bf7ca42e3fb9114b8fa9a8671bbc9d10877670b9",
|
||||
"policy_sha256": "b75c4ac841d7b4bcc57f7a9c8417ca2317d8ecfa499e72a9af8a8591a2ec0d35",
|
||||
"provider_map_sha256": "f2b69046b6a740fd9532d2d88e7fabae7c20fb662f783c9502adc9026406f352",
|
||||
"container_image": "ndc/mission-core-lab-v1-goose:sg3.2.0-cu117-v1",
|
||||
"container_image_id": "sha256:591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd",
|
||||
"timeline_rate_hz": 12.0,
|
||||
"inference_rate_hz": 6.0,
|
||||
"inference_stride": 2,
|
||||
"held_evidence_fail_closed": true,
|
||||
"semantic_output_persisted": false,
|
||||
"one_heavy_vegetation_candidate_at_a_time": true
|
||||
}
|
||||
},
|
||||
"acceptance": {
|
||||
"minimum_graph_world_state_fps": 11.209069,
|
||||
"minimum_vegetation_timeline_fps": 11.209069,
|
||||
"minimum_vegetation_inference_fps": 5.604534,
|
||||
"maximum_vegetation_inference_completion_p95_ms": 125.0,
|
||||
"maximum_semantic_evidence_source_age_ms": 125.0,
|
||||
"maximum_combined_output_age_p99_ms": 125.0,
|
||||
"capacity_drop_count_max": 0,
|
||||
"unaccounted_frame_count_max": 0
|
||||
},
|
||||
"telemetry": {
|
||||
"sample_interval_seconds": 1.0,
|
||||
"required_roles": [
|
||||
"graph",
|
||||
"triton",
|
||||
"tgs",
|
||||
"vegetation"
|
||||
]
|
||||
},
|
||||
"invariants": {
|
||||
"raw_fisheye_immutable": true,
|
||||
"reference_graph_parameters_unchanged": true,
|
||||
"tgs_parameters_unchanged": true,
|
||||
"ddrnet_parameters_unchanged": true,
|
||||
"safety_layers_remain_12hz": true,
|
||||
"held_semantic_evidence_is_advisory_only": true,
|
||||
"vegetation_source_buffer_bounded": true,
|
||||
"vegetation_full_route_rgb_prefetch_allowed": false,
|
||||
"ppliteseg_concurrent_run_allowed": false,
|
||||
"camera_semantics_can_clear_rigid_geometry": false,
|
||||
"canonical_triton_mutation_allowed": false,
|
||||
"runtime_shared_source_frame_target": true,
|
||||
"gauss_or_playcanvas_in_scope": false
|
||||
},
|
||||
"authority": {
|
||||
"visual_quality_accepted": false,
|
||||
"route_truth_available": false,
|
||||
"traversability_accepted": false,
|
||||
"physical_free_space_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false,
|
||||
"production_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"schema_version": "missioncore.lab-v1-vegetation-integrated-shadow-profile/v1",
|
||||
"profile_id": "lab-v1-ravnoves00-ddrnet-m49-integrated-shadow/v1",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"expected_timeline_frames": 4489,
|
||||
"requested_source_rate_hz": 12.0,
|
||||
"shared_start_barrier": true,
|
||||
"ground_truth_available": false
|
||||
},
|
||||
"stages": {
|
||||
"m49_graph_tgs": {
|
||||
"profile": "m49-tgs-integrated-graph-shadow-v1.json",
|
||||
"profile_sha256": "b61e018b2d04eec58802e2d4186ce7a3dd3a15b254db106b57b609e903eeef80",
|
||||
"candidate": "frozen-native-rf-detr-plus-cpu-tgs",
|
||||
"parameters_unchanged": true
|
||||
},
|
||||
"vegetation": {
|
||||
"candidate_id": "ddrnet_39-goose-fine-64",
|
||||
"candidate_key": "ddrnet",
|
||||
"checkpoint_sha256": "b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6",
|
||||
"config_sha256": "96a427a8baae387b827ec9c0bf7ca42e3fb9114b8fa9a8671bbc9d10877670b9",
|
||||
"policy_sha256": "b75c4ac841d7b4bcc57f7a9c8417ca2317d8ecfa499e72a9af8a8591a2ec0d35",
|
||||
"provider_map_sha256": "f2b69046b6a740fd9532d2d88e7fabae7c20fb662f783c9502adc9026406f352",
|
||||
"container_image": "ndc/mission-core-lab-v1-goose:sg3.2.0-cu117-v1",
|
||||
"container_image_id": "sha256:591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd",
|
||||
"semantic_output_persisted": false,
|
||||
"one_heavy_vegetation_candidate_at_a_time": true
|
||||
}
|
||||
},
|
||||
"acceptance": {
|
||||
"minimum_graph_world_state_fps": 11.209069,
|
||||
"minimum_vegetation_fps": 11.209069,
|
||||
"maximum_vegetation_completion_p95_ms": 125.0,
|
||||
"maximum_combined_output_age_p99_ms": 125.0,
|
||||
"capacity_drop_count_max": 0,
|
||||
"unaccounted_frame_count_max": 0
|
||||
},
|
||||
"telemetry": {
|
||||
"sample_interval_seconds": 1.0,
|
||||
"required_roles": [
|
||||
"graph",
|
||||
"triton",
|
||||
"tgs",
|
||||
"vegetation"
|
||||
]
|
||||
},
|
||||
"invariants": {
|
||||
"raw_fisheye_immutable": true,
|
||||
"reference_graph_parameters_unchanged": true,
|
||||
"tgs_parameters_unchanged": true,
|
||||
"ddrnet_parameters_unchanged": true,
|
||||
"vegetation_source_buffer_bounded": true,
|
||||
"vegetation_full_route_rgb_prefetch_allowed": false,
|
||||
"ppliteseg_concurrent_run_allowed": false,
|
||||
"camera_semantics_can_clear_rigid_geometry": false,
|
||||
"canonical_triton_mutation_allowed": false,
|
||||
"runtime_shared_source_frame_target": true,
|
||||
"gauss_or_playcanvas_in_scope": false
|
||||
},
|
||||
"authority": {
|
||||
"visual_quality_accepted": false,
|
||||
"route_truth_available": false,
|
||||
"traversability_accepted": false,
|
||||
"physical_free_space_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false,
|
||||
"production_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"schema_version": "missioncore.vegetation-mission-policy/v1",
|
||||
"profile_id": "lab-v1-vegetation-mission-policy/v1",
|
||||
"status": "planning-shadow-only-unqualified",
|
||||
"vehicle_profile": {
|
||||
"path": "config/perception/m49-physical-safety-shadow-v0.json",
|
||||
"profile_id": "m49-mission-core-rover-physical-safety-shadow/v0"
|
||||
},
|
||||
"actions": [
|
||||
"ALLOW",
|
||||
"HIGH_COST",
|
||||
"NO_GO"
|
||||
],
|
||||
"precedence": [
|
||||
"hard_safety_interlock",
|
||||
"explicit_mission_rule",
|
||||
"selected_preset_default"
|
||||
],
|
||||
"material_classes": [
|
||||
"hard_surface",
|
||||
"bare_soil",
|
||||
"grass",
|
||||
"fern",
|
||||
"herbaceous_vegetation",
|
||||
"cultivated_vegetation",
|
||||
"woody_shrub",
|
||||
"tree_or_trunk",
|
||||
"vegetation_unknown"
|
||||
],
|
||||
"mission_overridable_materials": [
|
||||
"grass",
|
||||
"fern",
|
||||
"herbaceous_vegetation",
|
||||
"cultivated_vegetation"
|
||||
],
|
||||
"presets": {
|
||||
"urban": {
|
||||
"hard_surface": "ALLOW",
|
||||
"bare_soil": "HIGH_COST",
|
||||
"grass": "NO_GO",
|
||||
"fern": "NO_GO",
|
||||
"herbaceous_vegetation": "NO_GO",
|
||||
"cultivated_vegetation": "NO_GO",
|
||||
"woody_shrub": "NO_GO",
|
||||
"tree_or_trunk": "NO_GO",
|
||||
"vegetation_unknown": "NO_GO"
|
||||
},
|
||||
"rural": {
|
||||
"hard_surface": "ALLOW",
|
||||
"bare_soil": "ALLOW",
|
||||
"grass": "HIGH_COST",
|
||||
"fern": "HIGH_COST",
|
||||
"herbaceous_vegetation": "HIGH_COST",
|
||||
"cultivated_vegetation": "NO_GO",
|
||||
"woody_shrub": "NO_GO",
|
||||
"tree_or_trunk": "NO_GO",
|
||||
"vegetation_unknown": "NO_GO"
|
||||
},
|
||||
"offroad": {
|
||||
"hard_surface": "ALLOW",
|
||||
"bare_soil": "ALLOW",
|
||||
"grass": "HIGH_COST",
|
||||
"fern": "HIGH_COST",
|
||||
"herbaceous_vegetation": "HIGH_COST",
|
||||
"cultivated_vegetation": "NO_GO",
|
||||
"woody_shrub": "NO_GO",
|
||||
"tree_or_trunk": "NO_GO",
|
||||
"vegetation_unknown": "NO_GO"
|
||||
}
|
||||
},
|
||||
"evidence_policy": {
|
||||
"policy_eligible_states": [
|
||||
"SUPPORTED_GROUND",
|
||||
"VEGETATION_POTENTIALLY_TRAVERSABLE"
|
||||
],
|
||||
"force_no_go_states": [
|
||||
"UNOBSERVED",
|
||||
"NEGATIVE_OR_UNSUPPORTED",
|
||||
"RIGID_OR_UNKNOWN_OBSTACLE",
|
||||
"VEGETATION_UNKNOWN",
|
||||
"VEGETATION_WITH_RIGID_GEOMETRY"
|
||||
],
|
||||
"force_no_go_materials": [
|
||||
"woody_shrub",
|
||||
"tree_or_trunk",
|
||||
"vegetation_unknown"
|
||||
],
|
||||
"missing_material_is": "vegetation_unknown",
|
||||
"missing_evidence_is": "UNOBSERVED",
|
||||
"camera_semantics_can_clear_rigid_geometry": false,
|
||||
"mission_rule_can_override_hard_safety_interlock": false
|
||||
},
|
||||
"mission_configuration_contract": {
|
||||
"preset_is_required": true,
|
||||
"explicit_rules_are_sparse_overrides": true,
|
||||
"preset_may_be_suggested_automatically": true,
|
||||
"automatic_preset_switch_requires_operator_opt_in": true,
|
||||
"automatic_switch_may_weaken_explicit_mission_rule": false,
|
||||
"operator_must_review_effective_rules_before_start": true
|
||||
},
|
||||
"authority": {
|
||||
"perception_selects_mission_action": false,
|
||||
"preset_grants_actuation": false,
|
||||
"navigation_accepted": false,
|
||||
"safety_accepted": false,
|
||||
"actuation_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"schema_version": "missioncore.vegetation-provider-label-map/v1",
|
||||
"profile_id": "lab-v1-vegetation-provider-label-map/v1",
|
||||
"policy_profile_id": "lab-v1-vegetation-mission-policy/v1",
|
||||
"providers": {
|
||||
"goose-fine-64": {
|
||||
"unmapped_policy": "no-material-claim",
|
||||
"class_granularity": "fine",
|
||||
"can_distinguish_low_and_high_grass": true,
|
||||
"can_distinguish_tree_trunk": true,
|
||||
"labels": {
|
||||
"asphalt": "hard_surface",
|
||||
"bikeway": "hard_surface",
|
||||
"cobble": "hard_surface",
|
||||
"sidewalk": "hard_surface",
|
||||
"gravel": "bare_soil",
|
||||
"soil": "bare_soil",
|
||||
"low_grass": "grass",
|
||||
"high_grass": "herbaceous_vegetation",
|
||||
"moss": "herbaceous_vegetation",
|
||||
"crops": "cultivated_vegetation",
|
||||
"bush": "woody_shrub",
|
||||
"hedge": "woody_shrub",
|
||||
"tree_trunk": "tree_or_trunk",
|
||||
"tree_root": "tree_or_trunk",
|
||||
"forest": "vegetation_unknown",
|
||||
"leaves": "vegetation_unknown",
|
||||
"scenery_vegetation": "vegetation_unknown",
|
||||
"tree_crown": "vegetation_unknown"
|
||||
}
|
||||
},
|
||||
"goose-category-12": {
|
||||
"unmapped_policy": "no-material-claim",
|
||||
"class_granularity": "coarse",
|
||||
"can_distinguish_low_and_high_grass": false,
|
||||
"can_distinguish_tree_trunk": false,
|
||||
"labels": {
|
||||
"artificial_ground": "hard_surface",
|
||||
"vegetation": "vegetation_unknown"
|
||||
}
|
||||
},
|
||||
"wildscenes-19": {
|
||||
"unmapped_policy": "no-material-claim",
|
||||
"class_granularity": "medium",
|
||||
"can_distinguish_low_and_high_grass": false,
|
||||
"can_distinguish_tree_trunk": true,
|
||||
"labels": {
|
||||
"asphalt/concrete": "hard_surface",
|
||||
"dirt": "bare_soil",
|
||||
"gravel": "bare_soil",
|
||||
"grass": "grass",
|
||||
"bush": "woody_shrub",
|
||||
"tree-trunk": "tree_or_trunk",
|
||||
"tree-foliage": "vegetation_unknown"
|
||||
}
|
||||
},
|
||||
"rellis-20": {
|
||||
"unmapped_policy": "no-material-claim",
|
||||
"class_granularity": "medium",
|
||||
"can_distinguish_low_and_high_grass": false,
|
||||
"can_distinguish_tree_trunk": false,
|
||||
"labels": {
|
||||
"asphalt": "hard_surface",
|
||||
"concrete": "hard_surface",
|
||||
"grass": "grass",
|
||||
"bush": "woody_shrub",
|
||||
"tree": "tree_or_trunk"
|
||||
}
|
||||
},
|
||||
"orfd-binary-freespace": {
|
||||
"unmapped_policy": "no-material-claim",
|
||||
"class_granularity": "binary-geometry-only",
|
||||
"can_distinguish_low_and_high_grass": false,
|
||||
"can_distinguish_tree_trunk": false,
|
||||
"labels": {}
|
||||
}
|
||||
},
|
||||
"invariants": {
|
||||
"unmapped_label_means_free": false,
|
||||
"coarse_vegetation_means_grass": false,
|
||||
"binary_freespace_selects_material": false,
|
||||
"provider_label_grants_actuation": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"schema_version": "missioncore.m48-static-occupancy-qualification-profile/v1",
|
||||
"profile_id": "m48-conservative-static-occupancy/v1",
|
||||
"pipeline_id": "m4-current-rolling-plus-step-static-occupancy/v1",
|
||||
"experiment_id": "m48-static-occupancy-qualification/v1",
|
||||
"human_lab_id": "M4.8",
|
||||
"run_label": "M4.8R2",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"source_session_id": "20260720T065719Z_viewer_live",
|
||||
"m47_lab_result_id": "m47-reference-graph-lab-49678f0a7c628c7e991af0964fa57d005baa027d2d1eea19f38bbfe27ed39ce5",
|
||||
"m47_graph_result_id": "m47-reference-graph-5f6a851cd655c7cf07c3025dacadbc188018b0afa97eda3a08802266e12da87d",
|
||||
"m47_graph_frames_sha256": "d2cd53f8cff555410959600a79eb9a101aad4a8009ba87bdd0f3c5f122948071",
|
||||
"small_static_result_id": "m48-small-static-passage-regression-3e3a2001f87fd3adcb736de52a65e42515044d83faa3515f892705b40915c084",
|
||||
"small_static_anchors_sha256": "6a317aa75dde8204d5574a56166bebc9347e8797934dbc82f076a0abfdfaa95a"
|
||||
},
|
||||
"selection": {
|
||||
"motion": "static",
|
||||
"requires_avoidance_or_clearance": true,
|
||||
"canonical_engineering_sequences": [1880, 2584],
|
||||
"independent_truth": false
|
||||
},
|
||||
"distance_bands_m": {
|
||||
"critical_near": [0.0, 8.0],
|
||||
"approach": [8.0, 12.0]
|
||||
},
|
||||
"candidate": {
|
||||
"point_sources": ["local-surface-occupied", "local-surface-step-candidate"],
|
||||
"minimum_points": 2,
|
||||
"minimum_voxels": 1,
|
||||
"voxel_size_m": 0.35,
|
||||
"depth_cluster_minimum_gap_m": 0.65,
|
||||
"depth_cluster_gap_fraction": 0.08,
|
||||
"spatial_cluster_radius_m": 0.75
|
||||
},
|
||||
"acceptance": {
|
||||
"minimum_critical_near_candidate_recall": 1.0,
|
||||
"minimum_approach_candidate_recall": 0.95,
|
||||
"minimum_canonical_engineering_recall": 1.0,
|
||||
"maximum_false_free_count": 0
|
||||
},
|
||||
"policy": {
|
||||
"absence_of_points_means_free": false,
|
||||
"absence_of_camera_detection_means_free": false,
|
||||
"step_candidate_can_only_add_occupied_or_unknown": true,
|
||||
"semantic_class_used": false,
|
||||
"planner_authoritative_free_space_claimed": false
|
||||
},
|
||||
"authority": {
|
||||
"mode": "replay-simulated",
|
||||
"physical_live": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"schema_version": "missioncore.reference-perception-graph-config/v2",
|
||||
"graph_id": "reference-perception-graph/v2",
|
||||
"source_profile_id": "m4-ravnoves00-recorded-realtime/v1",
|
||||
"providers": [
|
||||
{
|
||||
"role": "source",
|
||||
"provider_id": "ravnoves00-recorded-source/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "m4-ravnoves00-recorded-realtime/v1",
|
||||
"sha256": "ea10359339e6cce31b5780a2710299771cab7cc0c1c2a2b56a1621f786b31fa8"
|
||||
},
|
||||
{
|
||||
"role": "detector",
|
||||
"provider_id": "triton-rf-detr-large-coco-native-kb4-risk-fp16-shadow/v0",
|
||||
"version": "0.1.0",
|
||||
"revision": "rf-detr-large-coco-native-kb4-uint8-trt11-fp16-risk-shadow/v0",
|
||||
"sha256": "dbf4da5dbad6c3c22b1280b46ffcad81719bd183c81c263a4859847d829019b6"
|
||||
},
|
||||
{
|
||||
"role": "geometry",
|
||||
"provider_id": "ravnoves00-geometry-association/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "m4-ravnoves00-e29-e32-geometry/v1",
|
||||
"sha256": "cc666c9389a5e221957faddec89584709b66918d14abaf646f1832e001421999"
|
||||
},
|
||||
{
|
||||
"role": "temporal",
|
||||
"provider_id": "bounded-spatial-temporal-layer/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "m4-bounded-temporal-motion/v1",
|
||||
"sha256": "7130eaee24a95c7d888bf7598010e03e129e1c3ac5b34bcd8401015ff4244b39"
|
||||
},
|
||||
{
|
||||
"role": "motion",
|
||||
"provider_id": "class-independent-motion-estimator/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "m4-bounded-temporal-motion/v1",
|
||||
"sha256": "7130eaee24a95c7d888bf7598010e03e129e1c3ac5b34bcd8401015ff4244b39"
|
||||
},
|
||||
{
|
||||
"role": "rolling",
|
||||
"provider_id": "rolling-local-obstacle-map/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "ravnoves00-rolling-local-obstacle-map/v1",
|
||||
"sha256": "f7e3315eaf6ffaf3aee1e04913933812092cf82bbcc9984c1a6fa2d9250e6784"
|
||||
},
|
||||
{
|
||||
"role": "threat",
|
||||
"provider_id": "dual-evidence-replay-threat/v3",
|
||||
"version": "3.0.0",
|
||||
"revision": "m4-ravnoves00-virtual-corridor/v3",
|
||||
"sha256": "8c3a5aa837da1f028f5998fb504a1381f9b2b68de6420a32160410b6dc0887c7"
|
||||
}
|
||||
],
|
||||
"queues": [
|
||||
{
|
||||
"stage_id": "detector",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 1000000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
},
|
||||
{
|
||||
"stage_id": "geometry",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 1500000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
},
|
||||
{
|
||||
"stage_id": "temporal",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 1750000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
},
|
||||
{
|
||||
"stage_id": "rolling",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 2000000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
},
|
||||
{
|
||||
"stage_id": "threat",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 2250000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
}
|
||||
],
|
||||
"authority": {
|
||||
"mode": "replay-simulated",
|
||||
"physical_live": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"schema_version": "missioncore.m48q-native-risk-case-mining-profile/v1",
|
||||
"profile_id": "m48q-ravnoves00-native-raw-kb4-risk-review/v1",
|
||||
"question": "Which real RAVNOVES00 raw-fisheye frames expose the native RF-DETR risk semantics that require operator review before independent route truth exists?",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"frame_count": 4489,
|
||||
"raster_width": 800,
|
||||
"raster_height": 600,
|
||||
"video_sha256": "cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8",
|
||||
"geometric_resampling": false,
|
||||
"rectification": false,
|
||||
"warp": false
|
||||
},
|
||||
"candidate": {
|
||||
"provider_id": "triton-rf-detr-large-coco-native-kb4-risk-fp16-shadow/v0",
|
||||
"model_id": "rf_detr_large_native_kb4:1",
|
||||
"preprocess_id": "raw-kb4-uint8-fused-mask-rgb-pad8-imagenet-trt/v0",
|
||||
"engine_sha256": "b8a40b3580edff001ec9680de68707242294ff590ab296000fae371f1083f695",
|
||||
"minimum_score": 0.25
|
||||
},
|
||||
"risk_families": {
|
||||
"person": ["person"],
|
||||
"animal": ["bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe"],
|
||||
"light-road-user": ["bicycle", "motorcycle", "skateboard"],
|
||||
"vehicle": ["car", "bus", "truck"]
|
||||
},
|
||||
"selection": {
|
||||
"case_count": 24,
|
||||
"minimum_sequence_separation": 12,
|
||||
"low_confidence_maximum_score": 0.4,
|
||||
"fisheye_edge_margin_fraction": 0.12,
|
||||
"bucket_quotas": {
|
||||
"person": 3,
|
||||
"animal": 3,
|
||||
"light-road-user": 3,
|
||||
"vehicle": 3,
|
||||
"low-confidence": 3,
|
||||
"fisheye-edge": 3,
|
||||
"native-fewer-than-legacy": 3,
|
||||
"native-more-than-legacy": 3
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"quality_evaluated": false,
|
||||
"ground_truth": false,
|
||||
"candidate_accepted": false,
|
||||
"production_accepted": false,
|
||||
"purpose": "bounded-native-risk-case-review"
|
||||
},
|
||||
"authority": {
|
||||
"ground_truth": false,
|
||||
"candidate_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"schema_version": "missioncore.m48-additive-low-step-occupancy-profile/v1",
|
||||
"profile_id": "m48r3-ravnoves00-additive-low-step/v1",
|
||||
"provider_id": "ravnoves00-additive-low-step-geometry/v1",
|
||||
"base_geometry": {
|
||||
"profile_id": "m4-ravnoves00-e29-e32-geometry/v1",
|
||||
"sha256": "cc666c9389a5e221957faddec89584709b66918d14abaf646f1832e001421999"
|
||||
},
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"session_id": "20260720T065719Z_viewer_live",
|
||||
"frame_count": 4489,
|
||||
"point_count": 9207270,
|
||||
"local_surface_model_id": "k1-local-surface-23762244c8bdb97de26fb721ac957d7a00bc9a63571ac4cfa4be19c4effc7d55",
|
||||
"local_surface_sha256": "f57eb2485b6cef47f2a97a2d9ff1aa9fd9265fe1eb69cd5852d12f39e13b8bc6",
|
||||
"m48r2_result_id": "m48-static-occupancy-qualification-568024554cff011332ff19ca4739f70555a6232c0607dec2a71be6db408ea69a",
|
||||
"m48r2_cases_sha256": "249f58bf62973bfbcef8cd2f780013830fd4bf61ec342365a541963af96fa2ff"
|
||||
},
|
||||
"componentization": {
|
||||
"voxel_size_m": 0.45,
|
||||
"neighbor_radius_cells": 1,
|
||||
"minimum_points": 5,
|
||||
"sparse_persistence_minimum_points": 2,
|
||||
"sparse_persistence_window_frames": 6,
|
||||
"sparse_persistence_minimum_hits": 6,
|
||||
"sparse_persistence_maximum_range_m": 8.0,
|
||||
"minimum_voxels": 1,
|
||||
"local_radius_m": 10.0,
|
||||
"maximum_candidate_points_per_frame": 768,
|
||||
"maximum_cells_per_component": 256,
|
||||
"maximum_components_per_frame": 128,
|
||||
"exclude_baseline_occupied_points": true,
|
||||
"exclude_claimed_source_points": true
|
||||
},
|
||||
"separation_expectations": [
|
||||
{
|
||||
"anchor_id": "anchor-5e6e2a81e0667bdd9faf2a9e",
|
||||
"sequence": 1856,
|
||||
"expected_minimum_components": 2,
|
||||
"interpretation": "two thin posts remain independent occupied components"
|
||||
},
|
||||
{
|
||||
"anchor_id": "anchor-924a4623077fe5df18816b47",
|
||||
"sequence": 1856,
|
||||
"expected_minimum_components": 2,
|
||||
"interpretation": "two concrete hemispheres remain independent occupied components"
|
||||
}
|
||||
],
|
||||
"acceptance": {
|
||||
"expected_frames": 4489,
|
||||
"requested_source_rate_hz": 12.0,
|
||||
"minimum_effective_world_state_fps": 11.5,
|
||||
"maximum_world_state_completion_p95_ms": 60.0,
|
||||
"maximum_geometry_stage_p95_ms": 9.0,
|
||||
"maximum_geometry_stage_p99_ms": 16.0,
|
||||
"maximum_fps_regression_fraction_vs_native_baseline": 0.05,
|
||||
"maximum_world_state_p95_delta_ms_vs_native_baseline": 15.0,
|
||||
"maximum_additive_component_mean_growth_fraction": 1.0,
|
||||
"maximum_additive_cell_mean_growth_fraction": 1.0,
|
||||
"maximum_capacity_drop_count": 0,
|
||||
"minimum_critical_near_recall": 1.0,
|
||||
"minimum_canonical_engineering_recall": 1.0,
|
||||
"maximum_false_free_count": 0
|
||||
},
|
||||
"policy": {
|
||||
"absence_of_points_means_free": false,
|
||||
"absence_of_camera_detection_means_free": false,
|
||||
"additive_only": true,
|
||||
"semantic_class_used": false,
|
||||
"ray_clearing_used": false,
|
||||
"planner_authoritative_free_space_claimed": false
|
||||
},
|
||||
"authority": {
|
||||
"mode": "replay-simulated",
|
||||
"physical_live": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"schema_version": "missioncore.reference-perception-graph-config/v2",
|
||||
"graph_id": "reference-perception-graph/v2",
|
||||
"source_profile_id": "m4-ravnoves00-recorded-realtime/v1",
|
||||
"providers": [
|
||||
{
|
||||
"role": "source",
|
||||
"provider_id": "ravnoves00-recorded-source/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "m4-ravnoves00-recorded-realtime/v1",
|
||||
"sha256": "ea10359339e6cce31b5780a2710299771cab7cc0c1c2a2b56a1621f786b31fa8"
|
||||
},
|
||||
{
|
||||
"role": "detector",
|
||||
"provider_id": "triton-rf-detr-large-coco-native-kb4-risk-fp16-shadow/v0",
|
||||
"version": "0.1.0",
|
||||
"revision": "rf-detr-large-coco-native-kb4-uint8-trt11-fp16-risk-shadow/v0",
|
||||
"sha256": "dbf4da5dbad6c3c22b1280b46ffcad81719bd183c81c263a4859847d829019b6"
|
||||
},
|
||||
{
|
||||
"role": "geometry",
|
||||
"provider_id": "ravnoves00-additive-low-step-geometry/v1",
|
||||
"version": "0.1.0",
|
||||
"revision": "m48r3-ravnoves00-additive-low-step/v1",
|
||||
"sha256": "00fc197ee7200e2f0447b6bec7cc2f21b3c2970d7dd9414cc41e6787d712fee5"
|
||||
},
|
||||
{
|
||||
"role": "temporal",
|
||||
"provider_id": "bounded-spatial-temporal-layer/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "m4-bounded-temporal-motion/v1",
|
||||
"sha256": "7130eaee24a95c7d888bf7598010e03e129e1c3ac5b34bcd8401015ff4244b39"
|
||||
},
|
||||
{
|
||||
"role": "motion",
|
||||
"provider_id": "class-independent-motion-estimator/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "m4-bounded-temporal-motion/v1",
|
||||
"sha256": "7130eaee24a95c7d888bf7598010e03e129e1c3ac5b34bcd8401015ff4244b39"
|
||||
},
|
||||
{
|
||||
"role": "rolling",
|
||||
"provider_id": "rolling-local-obstacle-map/v1",
|
||||
"version": "1.0.0",
|
||||
"revision": "ravnoves00-rolling-local-obstacle-map/v1",
|
||||
"sha256": "f7e3315eaf6ffaf3aee1e04913933812092cf82bbcc9984c1a6fa2d9250e6784"
|
||||
},
|
||||
{
|
||||
"role": "threat",
|
||||
"provider_id": "dual-evidence-replay-threat/v3",
|
||||
"version": "3.0.0",
|
||||
"revision": "m4-ravnoves00-virtual-corridor/v3",
|
||||
"sha256": "8c3a5aa837da1f028f5998fb504a1381f9b2b68de6420a32160410b6dc0887c7"
|
||||
}
|
||||
],
|
||||
"queues": [
|
||||
{
|
||||
"stage_id": "detector",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 1000000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
},
|
||||
{
|
||||
"stage_id": "geometry",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 1500000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
},
|
||||
{
|
||||
"stage_id": "temporal",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 1750000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
},
|
||||
{
|
||||
"stage_id": "rolling",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 2000000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
},
|
||||
{
|
||||
"stage_id": "threat",
|
||||
"capacity": 2,
|
||||
"deadline_ns": 2250000000,
|
||||
"terminal_timeout_ns": 90000000000
|
||||
}
|
||||
],
|
||||
"authority": {
|
||||
"mode": "replay-simulated",
|
||||
"physical_live": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"schema_version": "missioncore.m48s-load-envelope-profile/v2",
|
||||
"profile_id": "m48s-rf-detr-reference-graph-load-envelope-prefetch/v1",
|
||||
"decision_question": "Does bounded recorded-image prefetch remove decode-startup interference and make the 10, 12 and 15 FPS complete-graph results repeatable on Worker 006?",
|
||||
"hypothesis": "A 64-frame bounded decoder prefetch completed before source admission isolates cold video open and initial decode from the realtime hot loop. Three complete repetitions at each rate will retain exact terminal accounting, satisfy the predeclared targets and attribute any residual tail to hot-loop decode, source pacing or graph completion.",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"source_profile_id": "m4-ravnoves00-recorded-realtime/v1",
|
||||
"frame_count": 4489,
|
||||
"graph_id": "reference-perception-graph/v2",
|
||||
"detector_provider_id": "triton-rf-detr-large-coco-risk-fp16-shadow/v0",
|
||||
"sensor_timestamps_preserved": true
|
||||
},
|
||||
"controlled_change_from_v1": {
|
||||
"change": "bounded 64-frame recorded-image decode prefetch before source admission plus source pacing attribution",
|
||||
"unchanged": [
|
||||
"source frames and source timestamps",
|
||||
"RF-DETR TensorRT engine and threshold",
|
||||
"geometry, temporal, motion, rolling-map and threat providers",
|
||||
"latest-wins queue capacities",
|
||||
"single inference pass per admitted detector frame",
|
||||
"detector prewarm and cyclic-GC hot-loop policy"
|
||||
]
|
||||
},
|
||||
"series_control": {
|
||||
"repeat_count_per_rate": 3,
|
||||
"execution_order": [
|
||||
"production-10fps-a1",
|
||||
"reserve-12fps-a1",
|
||||
"limit-15fps-a1",
|
||||
"production-10fps-a2",
|
||||
"reserve-12fps-a2",
|
||||
"limit-15fps-a2",
|
||||
"production-10fps-a3",
|
||||
"reserve-12fps-a3",
|
||||
"limit-15fps-a3"
|
||||
],
|
||||
"worker": "DESKTOP-OPJ8J04 / Worker 006",
|
||||
"execution": "strictly sequential; one graph container and one candidate Triton container per run"
|
||||
},
|
||||
"scenarios": [
|
||||
{
|
||||
"id": "production-10fps",
|
||||
"run_ids": [
|
||||
"m48s-load-prefetch-v1-production-10fps-a1",
|
||||
"m48s-load-prefetch-v1-production-10fps-a2",
|
||||
"m48s-load-prefetch-v1-production-10fps-a3"
|
||||
],
|
||||
"load_purpose": "production-rate",
|
||||
"source_rate_hz": 10.0,
|
||||
"thresholds": {
|
||||
"minimum_delivery_ratio": 0.999,
|
||||
"minimum_effective_world_state_fps": 9.5,
|
||||
"maximum_world_state_completion_p95_ms": 125.0
|
||||
},
|
||||
"required_for_reserve_decision": true
|
||||
},
|
||||
{
|
||||
"id": "reserve-12fps",
|
||||
"run_ids": [
|
||||
"m48s-load-prefetch-v1-reserve-12fps-a1",
|
||||
"m48s-load-prefetch-v1-reserve-12fps-a2",
|
||||
"m48s-load-prefetch-v1-reserve-12fps-a3"
|
||||
],
|
||||
"load_purpose": "reserve-gate",
|
||||
"source_rate_hz": 12.0,
|
||||
"thresholds": {
|
||||
"minimum_delivery_ratio": 0.995,
|
||||
"minimum_effective_world_state_fps": 11.4,
|
||||
"maximum_world_state_completion_p95_ms": 150.0
|
||||
},
|
||||
"required_for_reserve_decision": true
|
||||
},
|
||||
{
|
||||
"id": "limit-15fps",
|
||||
"run_ids": [
|
||||
"m48s-load-prefetch-v1-limit-15fps-a1",
|
||||
"m48s-load-prefetch-v1-limit-15fps-a2",
|
||||
"m48s-load-prefetch-v1-limit-15fps-a3"
|
||||
],
|
||||
"load_purpose": "limit-discovery",
|
||||
"source_rate_hz": 15.0,
|
||||
"thresholds": {
|
||||
"minimum_delivery_ratio": 0.95,
|
||||
"minimum_effective_world_state_fps": 14.25,
|
||||
"maximum_world_state_completion_p95_ms": 175.0
|
||||
},
|
||||
"required_for_reserve_decision": false
|
||||
}
|
||||
],
|
||||
"common_integrity_gates": [
|
||||
"closed terminal accounting",
|
||||
"zero failed, stale, rejected or unavailable frames",
|
||||
"all queue high-watermarks at or below capacity two",
|
||||
"complete single-pass pipeline timing",
|
||||
"detector prewarm before source admission",
|
||||
"source prefetch ready before source admission",
|
||||
"source pacing attribution for every admitted frame",
|
||||
"cyclic GC disabled only during the hot loop and restored after",
|
||||
"all command, actuation, navigation and safety authority remains false"
|
||||
],
|
||||
"exit_decision": {
|
||||
"repeatability_accepted_when": "All three repetitions at 10 and 12 FPS pass every integrity and operating-target gate; 15 FPS remains limit evidence and must pass integrity.",
|
||||
"optimization_scope_when_rejected": "Optimize only the phase identified by preadmission/hot-loop decode and source-pacing attribution; do not add another detector or inference pass."
|
||||
},
|
||||
"authority": {
|
||||
"candidate_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false,
|
||||
"production_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"schema_version": "missioncore.m48s-load-envelope-profile/v1",
|
||||
"profile_id": "m48s-rf-detr-reference-graph-load-envelope/v1",
|
||||
"decision_question": "Can the unchanged single-pass RF-DETR reference graph sustain the recorded production rate and 20 percent reserve on Worker 006, and where does its bounded latest-wins limit begin?",
|
||||
"hypothesis": "The hardened single-pass graph sustains 10 FPS and 12 FPS without unbounded queues, failed frames, a second inference pass, or more than the predeclared delivery loss; 15 FPS is measured only to locate the limit.",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"source_profile_id": "m4-ravnoves00-recorded-realtime/v1",
|
||||
"frame_count": 4489,
|
||||
"graph_id": "reference-perception-graph/v2",
|
||||
"detector_provider_id": "triton-rf-detr-large-coco-risk-fp16-shadow/v0",
|
||||
"sensor_timestamps_preserved": true
|
||||
},
|
||||
"controlled_change": {
|
||||
"only_variable": "wall_clock_source_rate_hz",
|
||||
"unchanged": [
|
||||
"source frames and source timestamps",
|
||||
"RF-DETR TensorRT engine and threshold",
|
||||
"geometry, temporal, motion, rolling-map and threat providers",
|
||||
"latest-wins queue capacities",
|
||||
"single inference pass per admitted detector frame",
|
||||
"detector prewarm and cyclic-GC hot-loop policy"
|
||||
]
|
||||
},
|
||||
"scenarios": [
|
||||
{
|
||||
"id": "production-10fps",
|
||||
"run_id": "m48s-load-envelope-v1-production-10fps-a1",
|
||||
"load_purpose": "production-rate",
|
||||
"source_rate_hz": 10.0,
|
||||
"thresholds": {
|
||||
"minimum_delivery_ratio": 0.999,
|
||||
"minimum_effective_world_state_fps": 9.5,
|
||||
"maximum_world_state_completion_p95_ms": 125.0
|
||||
},
|
||||
"required_for_reserve_decision": true
|
||||
},
|
||||
{
|
||||
"id": "reserve-12fps",
|
||||
"run_id": "m48s-load-envelope-v1-reserve-12fps-a1",
|
||||
"load_purpose": "reserve-gate",
|
||||
"source_rate_hz": 12.0,
|
||||
"thresholds": {
|
||||
"minimum_delivery_ratio": 0.995,
|
||||
"minimum_effective_world_state_fps": 11.4,
|
||||
"maximum_world_state_completion_p95_ms": 150.0
|
||||
},
|
||||
"required_for_reserve_decision": true
|
||||
},
|
||||
{
|
||||
"id": "limit-15fps",
|
||||
"run_id": "m48s-load-envelope-v1-limit-15fps-a1",
|
||||
"load_purpose": "limit-discovery",
|
||||
"source_rate_hz": 15.0,
|
||||
"thresholds": {
|
||||
"minimum_delivery_ratio": 0.95,
|
||||
"minimum_effective_world_state_fps": 14.25,
|
||||
"maximum_world_state_completion_p95_ms": 175.0
|
||||
},
|
||||
"required_for_reserve_decision": false
|
||||
}
|
||||
],
|
||||
"common_integrity_gates": [
|
||||
"closed terminal accounting",
|
||||
"zero failed, stale, rejected or unavailable frames",
|
||||
"all queue high-watermarks at or below capacity two",
|
||||
"complete single-pass pipeline timing",
|
||||
"detector prewarm before source admission",
|
||||
"cyclic GC disabled only during the hot loop and restored after",
|
||||
"all command, actuation, navigation and safety authority remains false"
|
||||
],
|
||||
"visual_evidence": {
|
||||
"binding": "reuse exact M4.8S full camera plus LiDAR plus 3D/PLAN timeline",
|
||||
"reason": "Only wall-clock pacing changes; source frames, sensor timestamps and graph semantics remain immutable.",
|
||||
"independent_ground_truth": false
|
||||
},
|
||||
"exit_decision": {
|
||||
"reserve_accepted_when": "Both production-10fps and reserve-12fps pass every integrity and operating target gate.",
|
||||
"optimization_scope_when_rejected": "Optimize only the measured bottleneck stage; do not add another detector or inference pass.",
|
||||
"limit_discovery_interpretation": "The 15 FPS result is valid evidence when integrity gates pass even if its operating target gate fails."
|
||||
},
|
||||
"authority": {
|
||||
"candidate_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false,
|
||||
"production_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"schema_version": "missioncore.m48t-risk-quality-temporal-profile/v1",
|
||||
"profile_id": "m48t-coco2017-risk-quality-temporal/v1",
|
||||
"candidate": {
|
||||
"provider_id": "triton-rf-detr-large-coco-risk-fp16-shadow/v0",
|
||||
"model_id": "rf_detr_large:1",
|
||||
"minimum_score": 0.25,
|
||||
"source_projection": "stretch-to-800x600-then-rf-detr-704x704"
|
||||
},
|
||||
"dataset": {
|
||||
"dataset_id": "coco-2017-val",
|
||||
"images_url": "http://images.cocodataset.org/zips/val2017.zip",
|
||||
"annotations_url": "http://images.cocodataset.org/annotations/annotations_trainval2017.zip",
|
||||
"annotation_document": "annotations/instances_val2017.json",
|
||||
"split": "val2017",
|
||||
"independent_human_annotations": true,
|
||||
"include_iscrowd": false,
|
||||
"minimum_projected_box_area_pixels": 64.0,
|
||||
"maximum_projected_box_area_fraction": 0.5
|
||||
},
|
||||
"risk_classes": {
|
||||
"person": ["person"],
|
||||
"animal": ["bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe"],
|
||||
"light-road-user": ["bicycle", "motorcycle", "skateboard"],
|
||||
"vehicle": ["car", "bus", "truck"]
|
||||
},
|
||||
"matching": {
|
||||
"iou_threshold": 0.5,
|
||||
"method": "score-ordered-greedy-exact-class",
|
||||
"family_confusion_matching": "score-ordered-greedy-same-family",
|
||||
"small_area_upper_pixels": 1024.0,
|
||||
"medium_area_upper_pixels": 9216.0
|
||||
},
|
||||
"quality_gates": {
|
||||
"minimum_truth_instances": 1000,
|
||||
"minimum_micro_precision": 0.8,
|
||||
"minimum_micro_recall": 0.75,
|
||||
"minimum_medium_large_recall": 0.85,
|
||||
"minimum_family_recall": {
|
||||
"person": 0.8,
|
||||
"animal": 0.75,
|
||||
"light-road-user": 0.65,
|
||||
"vehicle": 0.85
|
||||
},
|
||||
"minimum_class_truth_instances": 25,
|
||||
"minimum_qualified_class_recall": 0.55,
|
||||
"maximum_empty_prediction_risk_image_fraction": 0.1
|
||||
},
|
||||
"temporal": {
|
||||
"history_size": 5,
|
||||
"initial_confirmation_observations": 2,
|
||||
"switch_confirmation_observations": 3,
|
||||
"semantic_hold_seconds": 0.3,
|
||||
"state_expiry_seconds": 1.0,
|
||||
"maximum_active_components": 512,
|
||||
"cross_family_conflict_fallback": "unknown",
|
||||
"association_uses_semantic_class": false,
|
||||
"occupancy_uses_semantic_class": false
|
||||
},
|
||||
"scope": {
|
||||
"child_adult_distinction_evaluated": false,
|
||||
"unknown_moving_detection_evaluated": false,
|
||||
"object_presence_evaluated": true,
|
||||
"semantic_family_evaluated": true,
|
||||
"temporal_stability_evaluated": true,
|
||||
"risk_policy_evaluated": false
|
||||
},
|
||||
"authority": {
|
||||
"ground_truth_for_ravnoves00": false,
|
||||
"candidate_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"schema_version": "missioncore.m48t-upstream-parity-profile/v1",
|
||||
"profile_id": "m48t-rf-detr-large-upstream-coco-parity/v1",
|
||||
"model": {
|
||||
"package": "rfdetr",
|
||||
"package_version": "1.9.4",
|
||||
"upstream_revision": "9b009fa928d6218320439803d1da01869a85c072",
|
||||
"checkpoint": "rf-detr-large-2026.pth",
|
||||
"checkpoint_sha256": "0f4e20e19a99c0f8a62b5685f57f6c8b5c371c59081feda6752a0561a79ccf38",
|
||||
"resolution": [704, 704],
|
||||
"maximum_query_class_pairs": 300
|
||||
},
|
||||
"dataset": {
|
||||
"dataset_id": "coco-2017-val",
|
||||
"image_count": 5000,
|
||||
"annotations_sha256": "e8c7f7908f1d7278341fae127d0da654f102f11bd7b21d8aeefa635b8c810b6f",
|
||||
"evaluation": "pycocotools.COCOeval/bbox",
|
||||
"all_categories": true,
|
||||
"official_crowd_ignore": true,
|
||||
"custom_area_filtering": false
|
||||
},
|
||||
"providers": {
|
||||
"pytorch": {
|
||||
"preprocessing": "official-rfdetr-predict-direct-original-to-704",
|
||||
"dtype": "float16",
|
||||
"confidence_prefilter": 0.0
|
||||
},
|
||||
"tensorrt": {
|
||||
"provider_id": "triton-rf-detr-large-coco-risk-fp16-shadow/v0",
|
||||
"engine_sha256": "986399ce706b7380472cf5e473232249fed6e628971d8007f6609e83128d46b8",
|
||||
"preprocessing": "official-rfdetr-direct-original-to-704",
|
||||
"confidence_prefilter": 0.0
|
||||
}
|
||||
},
|
||||
"published_reference": {
|
||||
"coco_ap_50_95": 0.565,
|
||||
"coco_ap_50": 0.751,
|
||||
"maximum_absolute_reproduction_delta": 0.01
|
||||
},
|
||||
"parity_gates": {
|
||||
"maximum_absolute_ap_50_95_delta": 0.005,
|
||||
"maximum_absolute_ap_50_delta": 0.005
|
||||
},
|
||||
"authority": {
|
||||
"candidate_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"schema_version": "missioncore.camera-lidar-traversability/v1",
|
||||
"roles": {
|
||||
"camera_semantics": "material-and-risk-meaning-primary",
|
||||
"lidar": "metric-geometry-and-positive-support-primary",
|
||||
"arbitration": "preserve-contradiction-never-unilateral-clear"
|
||||
},
|
||||
"camera_contract": {
|
||||
"raster": "native-800x600-fisheye",
|
||||
"rectification_allowed": false,
|
||||
"new_model_allowed": false,
|
||||
"vegetation_classes": [
|
||||
"grass_low_vegetation",
|
||||
"tree_woody_vegetation"
|
||||
]
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"id": "RIGID_OR_UNKNOWN_OBSTACLE",
|
||||
"required_evidence": "stable-metric-nonground-without-vegetation-support",
|
||||
"cost": "lethal-or-unknown"
|
||||
},
|
||||
{
|
||||
"id": "VEGETATION_UNKNOWN",
|
||||
"required_evidence": "camera-vegetation-without-positive-ground-support",
|
||||
"cost": "unknown-never-free"
|
||||
},
|
||||
{
|
||||
"id": "VEGETATION_POTENTIALLY_TRAVERSABLE",
|
||||
"required_evidence": "camera-low-vegetation-plus-positive-ground-without-concentrated-rigid-return",
|
||||
"cost": "high-cost-terrain"
|
||||
},
|
||||
{
|
||||
"id": "VEGETATION_WITH_RIGID_GEOMETRY",
|
||||
"required_evidence": "camera-vegetation-plus-concentrated-persistent-vertical-geometry",
|
||||
"cost": "lethal"
|
||||
},
|
||||
{
|
||||
"id": "SUPPORTED_GROUND",
|
||||
"required_evidence": "positive-ground-support-without-blocking-geometry",
|
||||
"cost": "candidate-traversable"
|
||||
}
|
||||
],
|
||||
"invariants": {
|
||||
"camera_can_clear_positive_rigid_geometry": false,
|
||||
"lidar_nonground_alone_means_rigid_object": false,
|
||||
"missing_lidar_support_means_free": false,
|
||||
"vegetation_is_binary_free_or_lethal": false,
|
||||
"physical_navigation_authority": false
|
||||
},
|
||||
"deferred_robot_profile": [
|
||||
"footprint",
|
||||
"ground_clearance",
|
||||
"traction",
|
||||
"maximum_slope",
|
||||
"admissible_vegetation_height",
|
||||
"vegetation_contact_allowed"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"schema_version": "missioncore.m49-physical-safety-shadow-profile/v1",
|
||||
"profile_id": "m49-mission-core-rover-physical-safety-shadow/v0",
|
||||
"status": "planning-only-unqualified",
|
||||
"vehicle": {
|
||||
"source": "operator-supplied-2026-08-27-unverified",
|
||||
"body_length_m": 1.0,
|
||||
"body_width_m": 0.8,
|
||||
"body_height_m": 0.4,
|
||||
"ground_clearance_m": 0.15,
|
||||
"nominal_mass_kg": 100.0,
|
||||
"mass_qualification": "estimate-not-weighed",
|
||||
"provisional_centered_footprint_body_xy_m": [
|
||||
[0.5, 0.4],
|
||||
[0.5, -0.4],
|
||||
[-0.5, -0.4],
|
||||
[-0.5, 0.4]
|
||||
],
|
||||
"nominal_speed_mps": 0.2777777778,
|
||||
"maximum_operating_speed_mps": 0.5555555556,
|
||||
"drive": {
|
||||
"motor_count": 2,
|
||||
"rated_power_per_motor_w": 500.0,
|
||||
"motor_per_side": true,
|
||||
"steering_model": "unqualified-likely-differential"
|
||||
}
|
||||
},
|
||||
"unresolved_physical_inputs": [
|
||||
"measured-mass-and-center-of-gravity",
|
||||
"wheel-diameter-and-width",
|
||||
"wheelbase-track-and-overhangs",
|
||||
"qualified-base-link-origin",
|
||||
"controller-braking-and-loss-of-power-behavior",
|
||||
"measured-stopping-envelope",
|
||||
"maximum-step-slope-and-side-slope",
|
||||
"lidar-camera-to-body-extrinsics",
|
||||
"negative-obstacle-sensor-coverage"
|
||||
],
|
||||
"terrain_evidence": {
|
||||
"accepted_baseline_profile": "m49-tgs-full-shadow-v1.json",
|
||||
"accepted_baseline_cell_size_m": 0.45,
|
||||
"baseline_mutation_allowed": false,
|
||||
"challenger_cell_sizes_m": [0.15, 0.1],
|
||||
"challenger_radius_m": 12.0,
|
||||
"missing_support_policy": "stop-never-free",
|
||||
"required_states": [
|
||||
"SUPPORTED",
|
||||
"RIGID_OR_UNKNOWN_OBSTACLE",
|
||||
"NEGATIVE_OR_UNSUPPORTED",
|
||||
"VEGETATION_UNKNOWN",
|
||||
"VEGETATION_POTENTIALLY_TRAVERSABLE",
|
||||
"VEGETATION_WITH_RIGID_GEOMETRY"
|
||||
]
|
||||
},
|
||||
"operator_visual": {
|
||||
"host_profile": "14-inch-2023-macbook-pro-18-gib",
|
||||
"worker_role": "realtime-only",
|
||||
"lab_artifact_generation": "local-sequential-offline-or-imported-sealed",
|
||||
"lab_build_may_take_longer_than_source_duration": true,
|
||||
"source_pace_hz": 10.0,
|
||||
"render_policy": "on-demand-with-interaction-damping",
|
||||
"transport": "sealed-local-binary-chunks-no-per-cell-json",
|
||||
"worker_runtime_dependency": false,
|
||||
"sealed_artifact_required": true,
|
||||
"offline_worker_open_required": true,
|
||||
"full_session_high_resolution_preload_allowed": false,
|
||||
"playback_buffer": {
|
||||
"chunk_frame_count": 32,
|
||||
"startup_prebuffer_chunk_count": 2,
|
||||
"startup_prebuffer_seconds": 6.4,
|
||||
"resident_chunk_count_max": 3,
|
||||
"resident_window_seconds_max": 9.6,
|
||||
"forward_prefetch_chunk_count": 1,
|
||||
"backward_seek_policy": "load-target-and-next-from-sealed-local-artifact"
|
||||
},
|
||||
"lod": {
|
||||
"safety_computation_reduced_by_visual_lod": false,
|
||||
"near_field_radius_m": 4.0,
|
||||
"near_field_cell_size_m": 0.15,
|
||||
"mid_field_radius_m": 8.0,
|
||||
"mid_field_cell_size_m": 0.3,
|
||||
"far_field_radius_m": 12.0,
|
||||
"far_field_cell_size_m": 0.45,
|
||||
"paused_active_frame_full_resolution_available": true
|
||||
},
|
||||
"acceptance_budget": {
|
||||
"main_thread_frame_prepare_p95_ms_max": 10.0,
|
||||
"webgl_render_submit_p95_ms_target": 16.7,
|
||||
"webgl_render_submit_p95_ms_max": 33.3,
|
||||
"evidence_to_visible_p95_ms_max": 100.0,
|
||||
"incremental_resident_memory_mib_max": 256.0,
|
||||
"post_warmup_memory_growth_mib_max": 32.0,
|
||||
"long_task_over_50ms_count_max": 0,
|
||||
"webgl_context_loss_count_max": 0,
|
||||
"worker_unavailable_open_failure_count_max": 0,
|
||||
"worker_request_count_during_lab_open_max": 0,
|
||||
"worker_request_count_during_lab_build_max": 0
|
||||
}
|
||||
},
|
||||
"authority": {
|
||||
"commands_enabled": false,
|
||||
"navigation_accepted": false,
|
||||
"safety_accepted": false,
|
||||
"actuation_accepted": false,
|
||||
"physical_test_accepted": false
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user