/** * Batch Renderer for Hopewell Lidar Tiles * * Usage in dev console with loaded app: * import { batchRenderTiles } from './batch-renderer.js'; * const app = document.querySelector('#app').__vue_app__; * const sandboxRef = app._instance.refs.sandboxRef; * const tileCache = app._instance.data.tileCache; * * await batchRenderTiles(sandboxRef, tileCache, tileNames); */ /** * Download a data URL as a file */ function downloadDataURL(dataURL, filename) { const link = document.createElement('a'); link.href = dataURL; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); } /** * Download text content as a file */ function downloadText(text, filename) { const blob = new Blob([text], { type: 'application/json' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } /** * Batch render tiles using already-loaded app * * @param {Object} sandboxRef - Vue ref to ShadingSandbox component * @param {Object} tileCache - Cache of loaded tile data * @param {string[]} tileNames - Array of tile names to render * @param {Object} options - Options * @param {Object} options.renderSettings - Override render settings * @param {number} options.renderQuality - Render quality (default: 1024) * * @returns {Promise} Array of results */ export async function batchRenderTiles(sandboxRef, tileCache, tileNames, options = {}) { const { renderSettings = null, // Use sandbox defaults if null renderQuality = 1024 } = options; console.log(`[BatchRenderer] Starting batch render of ${tileNames.length} tiles`); console.log(`[BatchRenderer] Quality: ${renderQuality}px`); const results = []; const startTime = Date.now(); for (let i = 0; i < tileNames.length; i++) { const tileName = tileNames[i]; const current = i + 1; const total = tileNames.length; console.log(`[BatchRenderer] [${current}/${total}] Processing ${tileName}...`); try { const tileData = tileCache[tileName]; if (!tileData) { throw new Error(`Tile ${tileName} not found in cache`); } // Render console.log(`[BatchRenderer] Rendering...`); const renderResult = await sandboxRef.renderTileWithSettings( tileData, renderSettings || sandboxRef.getSettings(), renderQuality ); if (!renderResult.success) { throw new Error(renderResult.error || 'Render failed'); } console.log(`[BatchRenderer] Rendered in ${renderResult.renderTime}ms`); // Generate metadata const metadata = { tileName, bounds: tileData.bounds, renderSettings: renderSettings || sandboxRef.getSettings(), renderQuality, pointCount: tileData.pointCount, triangleCount: tileData.triangleCount, renderedAt: new Date().toISOString() }; // Download downloadDataURL(renderResult.dataURL, `${tileName}.png`); downloadText(JSON.stringify(metadata, null, 2), `${tileName}.json`); results.push({ tileName, metadata, renderTime: renderResult.renderTime, success: true }); console.log(`[BatchRenderer] ✓ Complete`); // Small delay await new Promise(resolve => setTimeout(resolve, 100)); } catch (err) { console.error(`[BatchRenderer] ✗ Failed: ${err.message}`); results.push({ tileName, success: false, error: err.message }); } } const totalTime = Date.now() - startTime; const successCount = results.filter(r => r.success).length; const failCount = results.filter(r => !r.success).length; console.log(`[BatchRenderer] Batch complete in ${(totalTime / 1000).toFixed(1)}s`); console.log(`[BatchRenderer] Success: ${successCount}, Failed: ${failCount}`); return results; }