diff --git a/web/app.js b/web/app.js index 7178b94..0117a78 100644 --- a/web/app.js +++ b/web/app.js @@ -30,7 +30,7 @@ const modelInput=$('#model-input'),modelButton=$('#load-model'); modelButton.onclick=()=>{modelInput.value='';modelInput.click()}; function bytesToBase64(bytes){let value='';for(let i=0;i{const file=modelInput.files?.[0],old=modelButton.textContent;if(!file)return;try{if(!file.name.toLowerCase().endsWith('.stl'))throw new Error('Choose an STL mesh');if(file.size>30*1024*1024)throw new Error('The STL is larger than 30 MB; export a lighter mesh');modelButton.disabled=true;modelButton.textContent='Loading…';await new Promise(requestAnimationFrame);const buffer=await file.arrayBuffer(),result=window.rovModel.loadBuffer(buffer,file.name);modelButton.textContent='Replace STL';toast(`Loaded ${result.name} • ${result.triangles.toLocaleString()} triangles`);if(bridgeReady)cacheModel(file).then(()=>toast('STL saved for the next launch')).catch(error=>toast(`Model loaded, but could not be saved: ${error.message}`,true))}catch(error){toast(`STL import failed: ${error.message}`,true)}finally{modelButton.disabled=false;if(modelButton.textContent==='Loading…')modelButton.textContent=old}}; $('#refresh').onclick=async()=>populatePorts(await api('refresh_ports'));$('#connect').onclick=async()=>{try{if(connected)await api('disconnect');else await api('connect',$('#port').value,+$('#baud').value,+$('#rate').value)}catch(e){toast(e.message,true)}}; $('#manual').onclick=()=>api('command','manual').catch(e=>toast(e.message,true));$('#arm').onclick=()=>openModal('arm-dialog');$('#confirm-arm').onclick=()=>{api('command','arm').catch(e=>toast(e.message,true));$('#arm-dialog').close()};$('#disarm').onclick=()=>api('command','disarm').catch(e=>toast(e.message,true));$('#logs').onclick=()=>api('open_logs'); diff --git a/web/model-viewer.js b/web/model-viewer.js index 8636b7e..8477850 100644 --- a/web/model-viewer.js +++ b/web/model-viewer.js @@ -283,7 +283,8 @@ const numTriangles = Math.floor(rawTriangles.length / 9); const posMap = new Map(); const getVertexIndex = (x, y, z) => { - const key = `${Math.round(x * 10000)},${Math.round(y * 10000)},${Math.round(z * 10000)}`; + const ix = (x * 2000) | 0, iy = (y * 2000) | 0, iz = (z * 2000) | 0; + const key = (ix * 73856093 ^ iy * 19349663 ^ iz * 83492791) >>> 0; let idx = posMap.get(key); if (idx === undefined) { idx = posMap.size; diff --git a/web_ui.py b/web_ui.py index 15d0098..5d9d440 100644 --- a/web_ui.py +++ b/web_ui.py @@ -139,8 +139,8 @@ class ControlApi: pass return None - def read_saved_model_chunk(self, offset, size=196608): - offset, size = int(offset), min(int(size), 196608) + def read_saved_model_chunk(self, offset, size=1048576): + offset, size = int(offset), min(int(size), 1048576) if offset < 0 or size < 1 or not self.model_cache.is_file(): raise ValueError("Saved model is unavailable") with self.model_cache.open("rb") as stream: