From 11bdb7009a346ab5188af397c237f31046b77d07 Mon Sep 17 00:00:00 2001 From: Mark Kalsbeek Date: Sun, 25 Jan 2026 15:52:46 +0100 Subject: [PATCH] tweaks and fix of ray feature --- ui/src/App.vue | 75 ++++-- ui/src/components/FeaturePopup.vue | 13 +- ui/src/components/MapControls.vue | 18 -- ui/src/components/ShadingSandbox.vue | 10 +- ui/src/components/TileRequestNotification.vue | 224 ------------------ ui/src/data/historicSites.js | 25 +- ui/src/utils/batch-renderer.js | 104 ++++---- ui/src/utils/coordinates.js | 2 +- ui/src/utils/geometry.js | 25 +- 9 files changed, 147 insertions(+), 349 deletions(-) delete mode 100644 ui/src/components/TileRequestNotification.vue diff --git a/ui/src/App.vue b/ui/src/App.vue index 6a5b928..092998f 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -89,6 +89,7 @@ - - \ No newline at end of file diff --git a/ui/src/data/historicSites.js b/ui/src/data/historicSites.js index 3e7a000..652e3a7 100644 --- a/ui/src/data/historicSites.js +++ b/ui/src/data/historicSites.js @@ -46,15 +46,15 @@ export const KNOWN_SITES = [ "description": "A nearly perfect circle 1,200 feet in diameter, enclosing approximately 30 acres \\cite{squier_davis_1848}. The earthen wall is lined by a deep interior ditch, a design typical of earlier Adena earthworks \\cite{lynott_2015}. Located in Heath, Ohio, this is one of the largest circular earthworks in the Americas. Eagle Mound at the center covers the remains of a large ceremonial structure \\cite{ohc_newark}. The walls vary from 4 to 14 feet in height at the monumental gateway. Unlike the Octagon, no solar alignments have been confirmed at the Great Circle \\cite{hively_horn_1982}. Part of the Hopewell Ceremonial Earthworks UNESCO World Heritage Site \\cite{unesco_2023}.", "type": "earthwork", "tiles": ["BS19870742", 'BS19870743', 'BS19880743'], - "overlay" : [ - { - "type": 'line', - "coordinates": [ - [-82.459197, 40.027871], - [-82.458565, 40.028731] - ] - } - ] + // "overlay" : [ + // { + // "type": 'line', + // "coordinates": [ + // [-82.459197, 40.027871], + // [-82.458565, 40.028731] + // ] + // } + // ] }, { "name": "Van Voorhis Walls", @@ -91,6 +91,13 @@ export const KNOWN_SITES = [ "type": "earthwork", "tiles": ['BS17630452', 'BS17630451', 'BS17650451', 'BS17620451', 'BS17620450'] }, + { + "name": "Southernmost identfied Section", + "description":"Southernmost identfied GHR Section according to \\cite{lepper_2024}", + "coordinates": [[-82.52056,39.95528]], + "type": 'road_confirmed', + "tiles": ['BS19620711',"BS19610711"] + }, // There is something in this area, but I can't confirm it's the 'high banks works' // Google maps and some facebook boomer do claim so, "highbank park earthworks" // A historical map puts it near the Scioto river, but that's on the other side of columbus diff --git a/ui/src/utils/batch-renderer.js b/ui/src/utils/batch-renderer.js index ad9142e..e7efab7 100644 --- a/ui/src/utils/batch-renderer.js +++ b/ui/src/utils/batch-renderer.js @@ -1,13 +1,20 @@ /** * Batch Renderer for Hopewell Lidar Tiles * - * Usage in dev console with loaded app: + * Usage: * 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); + * // Get refs from your app + * const tilesStore = useTilesStore(); + * const sandboxRef = ref(null); // ref to ShadingSandbox component + * + * // Render tiles + * const results = await batchRenderTiles( + * sandboxRef.value, + * tilesStore, + * ['tile-id-1', 'tile-id-2', 'tile-id-3'], + * { renderQuality: 1024 } + * ); */ /** @@ -23,62 +30,53 @@ function downloadDataURL(dataURL, filename) { } /** - * 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 + * Batch render tiles using offscreen ShadingSandbox * - * @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} sandboxComponent - Vue component instance (sandboxRef.value) + * @param {Object} tilesStore - Pinia tiles store instance + * @param {string[]} tileIds - Array of tile IDs to render (must be pre-loaded in store) * @param {Object} options - Options - * @param {Object} options.renderSettings - Override render settings - * @param {number} options.renderQuality - Render quality (default: 1024) + * @param {number} options.renderQuality - Render quality in pixels (default: 1024) * * @returns {Promise} Array of results */ -export async function batchRenderTiles(sandboxRef, tileCache, tileNames, options = {}) { +export async function batchRenderTiles(sandboxComponent, tilesStore, tileIds, 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] Starting batch render of ${tileIds.length} tiles`); console.log(`[BatchRenderer] Quality: ${renderQuality}px`); const results = []; const startTime = Date.now(); + sandboxComponent.offscreen = true; - for (let i = 0; i < tileNames.length; i++) { - const tileName = tileNames[i]; + for (let i = 0; i < tileIds.length; i++) { + const tileId = tileIds[i]; const current = i + 1; - const total = tileNames.length; + const total = tileIds.length; - console.log(`[BatchRenderer] [${current}/${total}] Processing ${tileName}...`); + console.log(`[BatchRenderer] [${current}/${total}] Processing ${tileId}...`); try { - const tileData = tileCache[tileName]; - if (!tileData) { - throw new Error(`Tile ${tileName} not found in cache`); + // Get tile data from store + const metadata = tilesStore.getMetadata(tileId); + const moundData = tilesStore.getMoundData(tileId); + + if (!metadata) { + throw new Error(`Metadata not found in store for ${tileId}`); } - // Render - console.log(`[BatchRenderer] Rendering...`); - const renderResult = await sandboxRef.renderTileWithSettings( - tileData, - renderSettings || sandboxRef.getSettings(), + if (!moundData) { + throw new Error(`Mound data not found in store for ${tileId}`); + } + + // Render with current settings + console.log(`[BatchRenderer] Rendering at ${renderQuality}px...`); + const renderResult = await sandboxComponent.renderTileWithSettings( + moundData, + sandboxComponent.getSettings(), renderQuality ); @@ -88,37 +86,21 @@ export async function batchRenderTiles(sandboxRef, tileCache, tileNames, options 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`); + // Download PNG + downloadDataURL(renderResult.dataURL, `${tileId}.png`); results.push({ - tileName, - metadata, + tileId, 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, + tileId, success: false, error: err.message }); diff --git a/ui/src/utils/coordinates.js b/ui/src/utils/coordinates.js index ba2e7e0..6a830ee 100644 --- a/ui/src/utils/coordinates.js +++ b/ui/src/utils/coordinates.js @@ -38,7 +38,7 @@ export function formatDistance(meters, useImperial = false) { * Format bearing angle */ export function formatBearing(degrees) { - return `${degrees.toFixed(1)}°`; + return `${degrees.toFixed(2)}°`; } /** diff --git a/ui/src/utils/geometry.js b/ui/src/utils/geometry.js index 0557c4e..721981a 100644 --- a/ui/src/utils/geometry.js +++ b/ui/src/utils/geometry.js @@ -40,7 +40,7 @@ export function calculateBearing(lng1, lat1, lng2, lat2) { * Extend a line from point1 through point2 to a far distance (100km) * Used for ray drawing */ -export function extendRay(lng1, lat1, lng2, lat2, bounds) { +export function extendRay(lng1, lat1, lng2, lat2) { const bearing = calculateBearing(lng1, lat1, lng2, lat2); const bearingRad = bearing * Math.PI / 180; @@ -56,4 +56,27 @@ export function extendRay(lng1, lat1, lng2, lat2, bounds) { Math.cos(d / R) - Math.sin(phi_1) * Math.sin(phi_2)); return [labmda_2 * 180 / Math.PI, phi_2 * 180 / Math.PI]; +} + +/** + * Generate a densely-sampled ray from pt1 through pt2 + * Creates many intermediate points so the line appears straight in Mercator projection + */ +export function generateRayCoordinates(lng1, lat1, lng2, lat2, numSegments = 1000) { + const dLng = lng2 - lng1; + const dLat = lat2 - lat1; + + // Extend the ray far beyond point 2 + const extensionFactor = 100; + + const coords = []; + for (let i = 0; i <= numSegments; i++) { + const t = (i / numSegments) * extensionFactor; + coords.push([ + lng1 + dLng * t, + lat1 + dLat * t + ]); + } + + return coords; } \ No newline at end of file