BIIIIG FIXES
This commit is contained in:
642
ui/src/App.vue
642
ui/src/App.vue
@@ -1,15 +1,17 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div ref="mapContainer" class="map-container"></div>
|
||||
<canvas ref="threeCanvas" class="three-canvas"></canvas>
|
||||
|
||||
<ShadingSandbox
|
||||
:visible="sandboxVisible"
|
||||
ref="ShadingSandbox"
|
||||
:offscreen="sandboxOffscreen"
|
||||
:initial-settings="DEFAULT_RENDER_SETTINGS"
|
||||
ref="sandboxRef"
|
||||
@close="sandboxVisible = false"
|
||||
@renderComplete="onRenderComplete"
|
||||
@error="onRenderError"
|
||||
/>
|
||||
|
||||
<div class="layer-controls">
|
||||
<div class="control-section">
|
||||
<label>Base Map:</label>
|
||||
@@ -35,366 +37,327 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import 'maplibre-gl/dist/maplibre-gl.css';
|
||||
import * as THREE from 'three';
|
||||
import ShadingSandbox from './ShadingSandbox.vue';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
ShadingSandbox
|
||||
},
|
||||
setup() {
|
||||
const mapContainer = ref(null);
|
||||
const threeCanvas = ref(null);
|
||||
const ShadingSandbox = ref(null);
|
||||
let map = null;
|
||||
let scene = null;
|
||||
let camera = null;
|
||||
let renderer = null;
|
||||
let lidarMeshes = [];
|
||||
const baseLayer = ref('osm');
|
||||
const showOctagon = ref(true);
|
||||
const showLidar = ref(true);
|
||||
|
||||
const sandboxVisible = ref(false);
|
||||
const currentTileData = ref(null);
|
||||
const tileCache = ref({});
|
||||
// Default render settings - used everywhere
|
||||
const DEFAULT_RENDER_SETTINGS = {
|
||||
azimuth: 90,
|
||||
altitude: 60,
|
||||
intensity: 1.2,
|
||||
heightScale: 3,
|
||||
terrainColor: 0x9A9996
|
||||
};
|
||||
|
||||
// Newark Octagon coordinates (converted from DMS to decimal)
|
||||
const octagonCoords = [
|
||||
[-82.44133, 40.05431], // 40°03'15.5"N 82°26'28.8"W
|
||||
[-82.44264, 40.05311], // 40°03'11.2"N 82°26'33.5"W
|
||||
[-82.44464, 40.05242], // 40°03'08.7"N 82°26'40.7"W
|
||||
[-82.44631, 40.05342], // 40°03'12.3"N 82°26'46.7"W
|
||||
[-82.44728, 40.05500], // 40°03'18.0"N 82°26'50.2"W
|
||||
[-82.44589, 40.05633], // 40°03'22.8"N 82°26'45.2"W
|
||||
[-82.44389, 40.05697], // 40°03'25.1"N 82°26'38.0"W
|
||||
[-82.44192, 40.05589], // 40°03'21.2"N 82°26'30.9"W
|
||||
[-82.44133, 40.05431], // Close the polygon
|
||||
];
|
||||
// Refs
|
||||
const mapContainer = ref(null);
|
||||
const sandboxRef = ref(null);
|
||||
const sandboxVisible = ref(false);
|
||||
const sandboxOffscreen = ref(false);
|
||||
const baseLayer = ref('osm');
|
||||
const showOctagon = ref(true);
|
||||
const showLidar = ref(true);
|
||||
const tileCache = ref({});
|
||||
const currentTileData = ref(null);
|
||||
|
||||
const octagonCenter = [-82.44383, 40.05469];
|
||||
// Map instance
|
||||
let map = null;
|
||||
|
||||
onMounted(() => {
|
||||
map = new maplibregl.Map({
|
||||
container: mapContainer.value,
|
||||
style: {
|
||||
version: 8,
|
||||
sources: {
|
||||
'osm': {
|
||||
type: 'raster',
|
||||
tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
|
||||
tileSize: 256,
|
||||
attribution: '© OpenStreetMap contributors'
|
||||
},
|
||||
'satellite': {
|
||||
type: 'raster',
|
||||
tiles: [
|
||||
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
|
||||
],
|
||||
tileSize: 256,
|
||||
attribution: 'Esri, Maxar, Earthstar Geographics, USDA FSA, USGS, Aerogrid, IGN, IGP, and the GIS User Community'
|
||||
}
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
id: 'osm-layer',
|
||||
type: 'raster',
|
||||
source: 'osm',
|
||||
layout: { visibility: 'visible' }
|
||||
},
|
||||
{
|
||||
id: 'satellite-layer',
|
||||
type: 'raster',
|
||||
source: 'satellite',
|
||||
layout: { visibility: 'none' }
|
||||
}
|
||||
]
|
||||
},
|
||||
center: octagonCenter,
|
||||
zoom: 15
|
||||
});
|
||||
// Tile names to load
|
||||
const TILE_NAMES = [
|
||||
'BS19820747',
|
||||
'BS19820748',
|
||||
'BS19830747',
|
||||
'BS19830748'
|
||||
];
|
||||
|
||||
map.on('load', () => {
|
||||
// Add octagon source and layer
|
||||
map.addSource('octagon', {
|
||||
type: 'geojson',
|
||||
data: {
|
||||
type: 'Feature',
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [octagonCoords]
|
||||
}
|
||||
}
|
||||
});
|
||||
// Newark Octagon coordinates
|
||||
const octagonCoords = [
|
||||
[-82.44133, 40.05431],
|
||||
[-82.44264, 40.05311],
|
||||
[-82.44464, 40.05242],
|
||||
[-82.44631, 40.05342],
|
||||
[-82.44728, 40.05500],
|
||||
[-82.44589, 40.05633],
|
||||
[-82.44389, 40.05697],
|
||||
[-82.44192, 40.05589],
|
||||
[-82.44133, 40.05431], // Close the polygon
|
||||
];
|
||||
|
||||
map.addLayer({
|
||||
id: 'octagon-fill',
|
||||
type: 'fill',
|
||||
source: 'octagon',
|
||||
paint: {
|
||||
'fill-color': '#ff0000',
|
||||
'fill-opacity': 0.2
|
||||
}
|
||||
});
|
||||
const octagonCenter = [-82.44383, 40.05469];
|
||||
|
||||
map.addLayer({
|
||||
id: 'octagon-outline',
|
||||
type: 'line',
|
||||
source: 'octagon',
|
||||
paint: {
|
||||
'line-color': '#ff0000',
|
||||
'line-width': 2
|
||||
}
|
||||
});
|
||||
// Coordinate conversion utilities
|
||||
function webMercatorToLonLat(x, y) {
|
||||
const R = 6378137; // Earth's radius in meters
|
||||
const lon = (x / R) * (180 / Math.PI);
|
||||
const lat = (2 * Math.atan(Math.exp(y / R)) - Math.PI / 2) * (180 / Math.PI);
|
||||
return [lon, lat];
|
||||
}
|
||||
|
||||
// Initialize Three.js
|
||||
initThreeJS();
|
||||
loadLidarTiles();
|
||||
// Parse .mound binary file
|
||||
async function parseMoundFile(url) {
|
||||
const response = await fetch(url);
|
||||
const buffer = await response.arrayBuffer();
|
||||
|
||||
const view = new DataView(buffer);
|
||||
let offset = 0;
|
||||
|
||||
const magic = String.fromCharCode(
|
||||
view.getUint8(offset++),
|
||||
view.getUint8(offset++),
|
||||
view.getUint8(offset++),
|
||||
view.getUint8(offset++)
|
||||
);
|
||||
|
||||
if (magic !== 'LIDR') {
|
||||
throw new Error('Invalid .mound file');
|
||||
}
|
||||
|
||||
const version = view.getUint32(offset, true); offset += 4;
|
||||
const pointCount = view.getUint32(offset, true); offset += 4;
|
||||
const triangleCount = view.getUint32(offset, true); offset += 4;
|
||||
const minX = view.getFloat32(offset, true); offset += 4;
|
||||
const minY = view.getFloat32(offset, true); offset += 4;
|
||||
const minZ = view.getFloat32(offset, true); offset += 4;
|
||||
const maxX = view.getFloat32(offset, true); offset += 4;
|
||||
const maxY = view.getFloat32(offset, true); offset += 4;
|
||||
const maxZ = view.getFloat32(offset, true); offset += 4;
|
||||
offset += 24; // Skip reserved bytes
|
||||
|
||||
const positions = new Float32Array(buffer, offset, pointCount * 3);
|
||||
offset += pointCount * 3 * 4;
|
||||
|
||||
const indices = new Uint32Array(buffer, offset, triangleCount * 3);
|
||||
|
||||
return {
|
||||
version,
|
||||
pointCount,
|
||||
triangleCount,
|
||||
bounds: { minX, minY, minZ, maxX, maxY, maxZ },
|
||||
positions,
|
||||
indices
|
||||
};
|
||||
}
|
||||
|
||||
// Load and render all lidar tiles
|
||||
async function loadLidarTiles() {
|
||||
console.log('Loading and rendering tiles...');
|
||||
|
||||
for (const tileName of TILE_NAMES) {
|
||||
try {
|
||||
console.log(`Loading ${tileName}...`);
|
||||
const data = await parseMoundFile(`/tiles/${tileName}.mound`);
|
||||
|
||||
// Cache tile data
|
||||
tileCache.value[tileName] = data;
|
||||
|
||||
// Render using ShadingSandbox
|
||||
if (sandboxRef.value) {
|
||||
const result = await sandboxRef.value.renderTileWithSettings(
|
||||
data,
|
||||
DEFAULT_RENDER_SETTINGS,
|
||||
512
|
||||
);
|
||||
|
||||
// Update Three.js on map move
|
||||
map.on('move', updateThreeCamera);
|
||||
map.on('zoom', updateThreeCamera);
|
||||
});
|
||||
});
|
||||
|
||||
const updateBaseLayer = () => {
|
||||
if (!map) return;
|
||||
|
||||
if (baseLayer.value === 'osm') {
|
||||
map.setLayoutProperty('osm-layer', 'visibility', 'visible');
|
||||
map.setLayoutProperty('satellite-layer', 'visibility', 'none');
|
||||
} else {
|
||||
map.setLayoutProperty('osm-layer', 'visibility', 'none');
|
||||
map.setLayoutProperty('satellite-layer', 'visibility', 'visible');
|
||||
}
|
||||
};
|
||||
|
||||
const toggleOctagon = () => {
|
||||
if (!map) return;
|
||||
|
||||
const visibility = showOctagon.value ? 'visible' : 'none';
|
||||
map.setLayoutProperty('octagon-fill', 'visibility', visibility);
|
||||
map.setLayoutProperty('octagon-outline', 'visibility', visibility);
|
||||
};
|
||||
|
||||
const toggleLidar = () => {
|
||||
lidarMeshes.forEach(mesh => {
|
||||
mesh.visible = showLidar.value;
|
||||
});
|
||||
if (renderer) renderer.render(scene, camera);
|
||||
};
|
||||
|
||||
// Convert lat/lon to Web Mercator meters (EPSG:3857)
|
||||
const lonLatToWebMercator = (lon, lat) => {
|
||||
const x = lon * 20037508.34 / 180;
|
||||
let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
|
||||
y = y * 20037508.34 / 180;
|
||||
return { x, y };
|
||||
};
|
||||
|
||||
const initThreeJS = () => {
|
||||
scene = new THREE.Scene();
|
||||
|
||||
camera = new THREE.OrthographicCamera(
|
||||
-1, 1, 1, -1, 0.1, 10000
|
||||
);
|
||||
camera.position.z = 1;
|
||||
|
||||
renderer = new THREE.WebGLRenderer({
|
||||
canvas: threeCanvas.value,
|
||||
alpha: true,
|
||||
antialias: true
|
||||
});
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.setClearColor(0x000000, 0);
|
||||
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
||||
directionalLight.position.set(1, 1, 1);
|
||||
scene.add(directionalLight);
|
||||
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
updateThreeCamera();
|
||||
};
|
||||
|
||||
const handleResize = () => {
|
||||
if (!renderer || !camera) return;
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
updateThreeCamera();
|
||||
};
|
||||
|
||||
const updateThreeCamera = () => {
|
||||
if (!map || !camera || !renderer) return;
|
||||
|
||||
const bounds = map.getBounds();
|
||||
const ne = bounds.getNorthEast();
|
||||
const sw = bounds.getSouthWest();
|
||||
|
||||
// Convert lat/lon bounds to Web Mercator meters
|
||||
const neMerc = lonLatToWebMercator(ne.lng, ne.lat);
|
||||
const swMerc = lonLatToWebMercator(sw.lng, sw.lat);
|
||||
|
||||
camera.left = swMerc.x;
|
||||
camera.right = neMerc.x;
|
||||
camera.top = neMerc.y;
|
||||
camera.bottom = swMerc.y;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
|
||||
const parseMoundFile = async (url) => {
|
||||
const response = await fetch(url);
|
||||
const buffer = await response.arrayBuffer();
|
||||
|
||||
const view = new DataView(buffer);
|
||||
let offset = 0;
|
||||
|
||||
const magic = String.fromCharCode(
|
||||
view.getUint8(offset++),
|
||||
view.getUint8(offset++),
|
||||
view.getUint8(offset++),
|
||||
view.getUint8(offset++)
|
||||
);
|
||||
|
||||
if (magic !== 'LIDR') {
|
||||
throw new Error('Invalid .mound file');
|
||||
}
|
||||
|
||||
const version = view.getUint32(offset, true); offset += 4;
|
||||
const pointCount = view.getUint32(offset, true); offset += 4;
|
||||
const triangleCount = view.getUint32(offset, true); offset += 4;
|
||||
const minX = view.getFloat32(offset, true); offset += 4;
|
||||
const minY = view.getFloat32(offset, true); offset += 4;
|
||||
const minZ = view.getFloat32(offset, true); offset += 4;
|
||||
const maxX = view.getFloat32(offset, true); offset += 4;
|
||||
const maxY = view.getFloat32(offset, true); offset += 4;
|
||||
const maxZ = view.getFloat32(offset, true); offset += 4;
|
||||
offset += 24; // Skip reserved
|
||||
|
||||
const positions = new Float32Array(buffer, offset, pointCount * 3);
|
||||
offset += pointCount * 3 * 4;
|
||||
|
||||
const indices = new Uint32Array(buffer, offset, triangleCount * 3);
|
||||
|
||||
return {
|
||||
pointCount,
|
||||
triangleCount,
|
||||
bounds: { minX, minY, minZ, maxX, maxY, maxZ },
|
||||
positions,
|
||||
indices
|
||||
};
|
||||
};
|
||||
|
||||
const loadLidarTiles = async () => {
|
||||
const tiles = [
|
||||
'BS19820747',
|
||||
'BS19820748',
|
||||
'BS19830747',
|
||||
'BS19830748'
|
||||
];
|
||||
|
||||
for (const tileName of tiles) {
|
||||
try {
|
||||
console.log(`Loading ${tileName}...`);
|
||||
const data = await parseMoundFile(`/tiles/${tileName}.mound`);
|
||||
if (result.success) {
|
||||
console.log(`Rendered ${tileName} in ${result.renderTime}ms (${result.width}x${result.height})`);
|
||||
|
||||
// Cache the tile data for sandbox use
|
||||
tileCache.value[tileName] = data;
|
||||
// Convert bounds to lat/lon
|
||||
const sw = webMercatorToLonLat(data.bounds.minX, data.bounds.minY);
|
||||
const ne = webMercatorToLonLat(data.bounds.maxX, data.bounds.maxY);
|
||||
|
||||
console.log(`${tileName} bounds:`, data.bounds);
|
||||
console.log(`First few positions:`, data.positions.slice(0, 15));
|
||||
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setAttribute('position', new THREE.BufferAttribute(data.positions, 3));
|
||||
geometry.setIndex(new THREE.BufferAttribute(data.indices, 1));
|
||||
geometry.computeVertexNormals();
|
||||
|
||||
const material = new THREE.MeshLambertMaterial({
|
||||
color: 0x8B7355,
|
||||
side: THREE.DoubleSide,
|
||||
wireframe: false
|
||||
// Add image source to map
|
||||
map.addSource(`tile-${tileName}`, {
|
||||
type: 'image',
|
||||
url: result.dataURL,
|
||||
coordinates: [
|
||||
[sw[0], ne[1]], // top-left
|
||||
[ne[0], ne[1]], // top-right
|
||||
[ne[0], sw[1]], // bottom-right
|
||||
[sw[0], sw[1]] // bottom-left
|
||||
]
|
||||
});
|
||||
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
scene.add(mesh);
|
||||
lidarMeshes.push(mesh);
|
||||
// Add layer
|
||||
map.addLayer({
|
||||
id: `tile-layer-${tileName}`,
|
||||
type: 'raster',
|
||||
source: `tile-${tileName}`,
|
||||
paint: {
|
||||
'raster-opacity': 0.8
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Loaded ${tileName}: ${data.pointCount} points, ${data.triangleCount} triangles`);
|
||||
console.log(`Mesh position:`, mesh.position);
|
||||
console.log(`Mesh in scene:`, scene.children.length);
|
||||
} catch (err) {
|
||||
console.error(`Failed to load ${tileName}:`, err);
|
||||
console.log(`Added ${tileName} to map at [${sw[0].toFixed(5)}, ${sw[1].toFixed(5)}] - [${ne[0].toFixed(5)}, ${ne[1].toFixed(5)}]`);
|
||||
} else {
|
||||
console.error(`Failed to render ${tileName}:`, result.error);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Map bounds:', map.getBounds().toArray());
|
||||
console.log('Camera:', camera);
|
||||
|
||||
updateThreeCamera();
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(`Failed to load ${tileName}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('All tiles loaded');
|
||||
}
|
||||
|
||||
const openSandbox = () => {
|
||||
// Open sandbox with first available tile
|
||||
const firstTile = Object.keys(tileCache.value)[0];
|
||||
if (firstTile) {
|
||||
currentTileData.value = tileCache.value[firstTile];
|
||||
sandboxVisible.value = true;
|
||||
|
||||
// Load tile data into renderer after it mounts
|
||||
setTimeout(() => {
|
||||
if (ShadingSandbox.value) {
|
||||
ShadingSandbox.value.loadTileData(currentTileData.value);
|
||||
}
|
||||
}, 100);
|
||||
// UI handlers
|
||||
function updateBaseLayer() {
|
||||
if (!map) return;
|
||||
|
||||
if (baseLayer.value === 'osm') {
|
||||
map.setLayoutProperty('osm-layer', 'visibility', 'visible');
|
||||
map.setLayoutProperty('satellite-layer', 'visibility', 'none');
|
||||
} else {
|
||||
map.setLayoutProperty('osm-layer', 'visibility', 'none');
|
||||
map.setLayoutProperty('satellite-layer', 'visibility', 'visible');
|
||||
}
|
||||
}
|
||||
|
||||
function toggleOctagon() {
|
||||
if (!map) return;
|
||||
|
||||
const visibility = showOctagon.value ? 'visible' : 'none';
|
||||
map.setLayoutProperty('octagon-fill', 'visibility', visibility);
|
||||
map.setLayoutProperty('octagon-outline', 'visibility', visibility);
|
||||
}
|
||||
|
||||
function toggleLidar() {
|
||||
if (!map) return;
|
||||
|
||||
const visibility = showLidar.value ? 'visible' : 'none';
|
||||
for (const tileName of TILE_NAMES) {
|
||||
const layerId = `tile-layer-${tileName}`;
|
||||
if (map.getLayer(layerId)) {
|
||||
map.setLayoutProperty(layerId, 'visibility', visibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function openSandbox() {
|
||||
const firstTile = Object.keys(tileCache.value)[0];
|
||||
if (firstTile) {
|
||||
currentTileData.value = tileCache.value[firstTile];
|
||||
sandboxVisible.value = true;
|
||||
|
||||
// Load tile data after sandbox mounts
|
||||
setTimeout(() => {
|
||||
if (sandboxRef.value) {
|
||||
sandboxRef.value.loadTileData(currentTileData.value);
|
||||
}
|
||||
};
|
||||
|
||||
const onRenderComplete = (data) => {
|
||||
console.log('Render complete:', {
|
||||
size: data.size,
|
||||
renderTime: data.renderTime,
|
||||
settings: data.settings
|
||||
});
|
||||
};
|
||||
|
||||
const onRenderError = (err) => {
|
||||
console.error('Renderer error:', err);
|
||||
};
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (renderer) {
|
||||
renderer.dispose();
|
||||
function onRenderComplete(data) {
|
||||
console.log('Render complete:', {
|
||||
size: `${data.width}x${data.height}`,
|
||||
renderTime: data.renderTime,
|
||||
settings: data.settings
|
||||
});
|
||||
}
|
||||
|
||||
function onRenderError(err) {
|
||||
console.error('Renderer error:', err);
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
map = new maplibregl.Map({
|
||||
container: mapContainer.value,
|
||||
style: {
|
||||
version: 8,
|
||||
sources: {
|
||||
'osm': {
|
||||
type: 'raster',
|
||||
tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
|
||||
tileSize: 256,
|
||||
attribution: '© OpenStreetMap contributors'
|
||||
},
|
||||
'satellite': {
|
||||
type: 'raster',
|
||||
tiles: [
|
||||
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
|
||||
],
|
||||
tileSize: 256,
|
||||
attribution: 'Esri, Maxar, Earthstar Geographics'
|
||||
}
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
id: 'osm-layer',
|
||||
type: 'raster',
|
||||
source: 'osm',
|
||||
layout: { visibility: 'visible' }
|
||||
},
|
||||
{
|
||||
id: 'satellite-layer',
|
||||
type: 'raster',
|
||||
source: 'satellite',
|
||||
layout: { visibility: 'none' }
|
||||
}
|
||||
]
|
||||
},
|
||||
center: octagonCenter,
|
||||
zoom: 15
|
||||
});
|
||||
|
||||
map.on('load', async () => {
|
||||
// Add octagon overlay
|
||||
map.addSource('octagon', {
|
||||
type: 'geojson',
|
||||
data: {
|
||||
type: 'Feature',
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [octagonCoords]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
mapContainer,
|
||||
threeCanvas,
|
||||
ShadingSandbox,
|
||||
baseLayer,
|
||||
showOctagon,
|
||||
showLidar,
|
||||
updateBaseLayer,
|
||||
toggleOctagon,
|
||||
toggleLidar,
|
||||
sandboxVisible,
|
||||
currentTileData,
|
||||
openSandbox,
|
||||
onRenderComplete,
|
||||
onRenderError
|
||||
};
|
||||
map.addLayer({
|
||||
id: 'octagon-fill',
|
||||
type: 'fill',
|
||||
source: 'octagon',
|
||||
paint: {
|
||||
'fill-color': '#ff0000',
|
||||
'fill-opacity': 0.2
|
||||
}
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: 'octagon-outline',
|
||||
type: 'line',
|
||||
source: 'octagon',
|
||||
paint: {
|
||||
'line-color': '#ff0000',
|
||||
'line-width': 2
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize sandbox offscreen for tile rendering
|
||||
sandboxOffscreen.value = true;
|
||||
sandboxVisible.value = true;
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
// Load and render tiles
|
||||
await loadLidarTiles();
|
||||
|
||||
// Hide sandbox
|
||||
sandboxVisible.value = false;
|
||||
sandboxOffscreen.value = false;
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (map) {
|
||||
map.remove();
|
||||
map = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -415,15 +378,6 @@ export default {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.three-canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.layer-controls {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
|
||||
Reference in New Issue
Block a user