/** * Performance Benchmark: SpatialIndex with 50,000 elements * Verifies that the R-Tree spatial index can handle large datasets efficiently. */ import { describe, it, expect, beforeAll } from 'vitest'; import { SpatialIndex } from '../src/canvas/SpatialIndex'; import type { CADElement } from '../src/types/cad.types'; const N = 50_000; describe('Performance Benchmark: 50.000 Elemente', () => { let spatialIndex: SpatialIndex; let elements: CADElement[]; beforeAll(() => { spatialIndex = new SpatialIndex(); elements = []; // Generate 50k elements in a grid pattern for (let i = 0; i < N; i++) { const col = i % 200; const row = Math.floor(i / 200); elements.push({ id: `perf-el-${i}`, type: 'rect', layerId: 'layer-perf', x: col * 10, y: row * 10, width: 8, height: 8, properties: { stroke: '#000', fill: '#ccc' }, }); } }); it('should bulk-insert 50k elements in under 2s', () => { const start = performance.now(); spatialIndex.bulkInsert(elements); const elapsed = performance.now() - start; console.log(`Bulk insert ${N} elements: ${elapsed.toFixed(1)}ms`); expect(elapsed).toBeLessThan(2000); }); it('should search viewport with ~100 visible elements in under 10ms', () => { // Query a small viewport that contains ~100 elements const start = performance.now(); const results = spatialIndex.search({ minX: 0, minY: 0, maxX: 1000, maxY: 100 }); const elapsed = performance.now() - start; console.log(`Viewport search (~100 elements): ${elapsed.toFixed(2)}ms, found=${results.length}`); expect(results.length).toBeGreaterThan(50); expect(results.length).toBeLessThan(2000); expect(elapsed).toBeLessThan(10); }); it('should search large viewport (all elements) in under 100ms', () => { const start = performance.now(); const results = spatialIndex.search({ minX: 0, minY: 0, maxX: 20000, maxY: 2500 }); const elapsed = performance.now() - start; console.log(`Full viewport search: ${elapsed.toFixed(2)}ms, found=${results.length}`); expect(results.length).toBe(N); expect(elapsed).toBeLessThan(100); }); it('should handle 100 sequential viewport searches in under 500ms', () => { const start = performance.now(); for (let i = 0; i < 100; i++) { const x = (i * 20) % 2000; const y = (i * 5) % 500; spatialIndex.search({ minX: x, minY: y, maxX: x + 200, maxY: y + 100 }); } const elapsed = performance.now() - start; console.log(`100 sequential searches: ${elapsed.toFixed(2)}ms`); expect(elapsed).toBeLessThan(500); }); it('should remove 1000 elements in under 200ms', () => { const start = performance.now(); for (let i = 0; i < 1000; i++) { spatialIndex.remove(elements[i]); } const elapsed = performance.now() - start; console.log(`Remove 1000 elements: ${elapsed.toFixed(2)}ms`); expect(elapsed).toBeLessThan(200); // Verify count const results = spatialIndex.search({ minX: 0, minY: 0, maxX: 20000, maxY: 2500 }); expect(results.length).toBe(N - 1000); }); it('should clear all elements in under 50ms', () => { const start = performance.now(); spatialIndex.clear(); const elapsed = performance.now() - start; console.log(`Clear all: ${elapsed.toFixed(2)}ms`); expect(elapsed).toBeLessThan(50); expect(spatialIndex.search({ minX: 0, minY: 0, maxX: 20000, maxY: 2500 }).length).toBe(0); }); });