@nice2dev/spatial-core 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -0
- package/dist/bim/index.d.ts +366 -0
- package/dist/bim/index.d.ts.map +1 -0
- package/dist/bim/index.js +60 -0
- package/dist/bim/index.js.map +1 -0
- package/dist/cad/index.d.ts +329 -0
- package/dist/cad/index.d.ts.map +1 -0
- package/dist/cad/index.js +124 -0
- package/dist/cad/index.js.map +1 -0
- package/dist/ecad/index.d.ts +316 -0
- package/dist/ecad/index.d.ts.map +1 -0
- package/dist/ecad/index.js +11 -0
- package/dist/ecad/index.js.map +1 -0
- package/dist/export/index.d.ts +93 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/export/index.js +522 -0
- package/dist/export/index.js.map +1 -0
- package/dist/floor-plan/index.d.ts +248 -0
- package/dist/floor-plan/index.d.ts.map +1 -0
- package/dist/floor-plan/index.js +228 -0
- package/dist/floor-plan/index.js.map +1 -0
- package/dist/grid/index.d.ts +160 -0
- package/dist/grid/index.d.ts.map +1 -0
- package/dist/grid/index.js +319 -0
- package/dist/grid/index.js.map +1 -0
- package/dist/import/import.worker.d.ts +28 -0
- package/dist/import/import.worker.d.ts.map +1 -0
- package/dist/import/import.worker.js +52 -0
- package/dist/import/import.worker.js.map +1 -0
- package/dist/import/index.d.ts +111 -0
- package/dist/import/index.d.ts.map +1 -0
- package/dist/import/index.js +1092 -0
- package/dist/import/index.js.map +1 -0
- package/dist/import/workerImport.d.ts +56 -0
- package/dist/import/workerImport.d.ts.map +1 -0
- package/dist/import/workerImport.js +207 -0
- package/dist/import/workerImport.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/interior/index.d.ts +241 -0
- package/dist/interior/index.d.ts.map +1 -0
- package/dist/interior/index.js +101 -0
- package/dist/interior/index.js.map +1 -0
- package/dist/measurement/index.d.ts +186 -0
- package/dist/measurement/index.d.ts.map +1 -0
- package/dist/measurement/index.js +400 -0
- package/dist/measurement/index.js.map +1 -0
- package/dist/objects/index.d.ts +288 -0
- package/dist/objects/index.d.ts.map +1 -0
- package/dist/objects/index.js +463 -0
- package/dist/objects/index.js.map +1 -0
- package/dist/serialization/index.d.ts +421 -0
- package/dist/serialization/index.d.ts.map +1 -0
- package/dist/serialization/index.js +412 -0
- package/dist/serialization/index.js.map +1 -0
- package/dist/topology/index.d.ts +252 -0
- package/dist/topology/index.d.ts.map +1 -0
- package/dist/topology/index.js +525 -0
- package/dist/topology/index.js.map +1 -0
- package/dist/transitions/index.d.ts +141 -0
- package/dist/transitions/index.d.ts.map +1 -0
- package/dist/transitions/index.js +160 -0
- package/dist/transitions/index.js.map +1 -0
- package/dist/unified/index.d.ts +225 -0
- package/dist/unified/index.d.ts.map +1 -0
- package/dist/unified/index.js +474 -0
- package/dist/unified/index.js.map +1 -0
- package/dist/virtualization/QuadTree.d.ts +68 -0
- package/dist/virtualization/QuadTree.d.ts.map +1 -0
- package/dist/virtualization/QuadTree.js +228 -0
- package/dist/virtualization/QuadTree.js.map +1 -0
- package/dist/virtualization/ViewportCulling.d.ts +92 -0
- package/dist/virtualization/ViewportCulling.d.ts.map +1 -0
- package/dist/virtualization/ViewportCulling.js +123 -0
- package/dist/virtualization/ViewportCulling.js.map +1 -0
- package/dist/virtualization/index.d.ts +9 -0
- package/dist/virtualization/index.d.ts.map +1 -0
- package/dist/virtualization/index.js +9 -0
- package/dist/virtualization/index.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuadTree — Spatial indexing for efficient 2D queries
|
|
3
|
+
*
|
|
4
|
+
* Used for viewport culling with large numbers of objects (1000+).
|
|
5
|
+
* Provides O(log n) queries for objects within a rectangular region.
|
|
6
|
+
*/
|
|
7
|
+
/** Max items per node before splitting */
|
|
8
|
+
const DEFAULT_MAX_ITEMS = 10;
|
|
9
|
+
/** Max depth to prevent infinite recursion */
|
|
10
|
+
const MAX_DEPTH = 8;
|
|
11
|
+
/**
|
|
12
|
+
* QuadTree for spatial indexing
|
|
13
|
+
*/
|
|
14
|
+
export class QuadTree {
|
|
15
|
+
root;
|
|
16
|
+
maxItems;
|
|
17
|
+
itemMap = new Map();
|
|
18
|
+
constructor(bounds, maxItemsPerNode = DEFAULT_MAX_ITEMS) {
|
|
19
|
+
this.root = {
|
|
20
|
+
bounds,
|
|
21
|
+
items: [],
|
|
22
|
+
children: null,
|
|
23
|
+
};
|
|
24
|
+
this.maxItems = maxItemsPerNode;
|
|
25
|
+
}
|
|
26
|
+
/** Insert an item into the quadtree */
|
|
27
|
+
insert(item) {
|
|
28
|
+
this.itemMap.set(item.id, item);
|
|
29
|
+
this.insertIntoNode(this.root, item, 0);
|
|
30
|
+
}
|
|
31
|
+
/** Remove an item by ID */
|
|
32
|
+
remove(id) {
|
|
33
|
+
const item = this.itemMap.get(id);
|
|
34
|
+
if (!item) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
this.itemMap.delete(id);
|
|
38
|
+
return this.removeFromNode(this.root, item);
|
|
39
|
+
}
|
|
40
|
+
/** Update an item's bounds */
|
|
41
|
+
update(id, newBounds) {
|
|
42
|
+
const item = this.itemMap.get(id);
|
|
43
|
+
if (!item) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
this.remove(id);
|
|
47
|
+
item.bounds = newBounds;
|
|
48
|
+
this.insert(item);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
/** Query all items intersecting with the given bounds */
|
|
52
|
+
query(bounds) {
|
|
53
|
+
const results = [];
|
|
54
|
+
this.queryNode(this.root, bounds, results);
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
/** Get all items */
|
|
58
|
+
getAll() {
|
|
59
|
+
return Array.from(this.itemMap.values());
|
|
60
|
+
}
|
|
61
|
+
/** Get item by ID */
|
|
62
|
+
get(id) {
|
|
63
|
+
return this.itemMap.get(id);
|
|
64
|
+
}
|
|
65
|
+
/** Get total item count */
|
|
66
|
+
get size() {
|
|
67
|
+
return this.itemMap.size;
|
|
68
|
+
}
|
|
69
|
+
/** Clear all items */
|
|
70
|
+
clear() {
|
|
71
|
+
this.itemMap.clear();
|
|
72
|
+
this.root.items = [];
|
|
73
|
+
this.root.children = null;
|
|
74
|
+
}
|
|
75
|
+
/** Rebuild the quadtree (useful after many removes) */
|
|
76
|
+
rebuild() {
|
|
77
|
+
const allItems = Array.from(this.itemMap.values());
|
|
78
|
+
this.root.items = [];
|
|
79
|
+
this.root.children = null;
|
|
80
|
+
for (const item of allItems) {
|
|
81
|
+
this.insertIntoNode(this.root, item, 0);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// ══════════════════════════════════════════════════════════════
|
|
85
|
+
// Private methods
|
|
86
|
+
// ══════════════════════════════════════════════════════════════
|
|
87
|
+
insertIntoNode(node, item, depth) {
|
|
88
|
+
// If node has children, try to insert into a child
|
|
89
|
+
if (node.children) {
|
|
90
|
+
const childIndex = this.getChildIndex(node, item.bounds);
|
|
91
|
+
if (childIndex !== -1) {
|
|
92
|
+
this.insertIntoNode(node.children[childIndex], item, depth + 1);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Item spans multiple quadrants, store in this node
|
|
96
|
+
node.items.push(item);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Add to this node
|
|
100
|
+
node.items.push(item);
|
|
101
|
+
// Split if needed and not at max depth
|
|
102
|
+
if (node.items.length > this.maxItems && depth < MAX_DEPTH) {
|
|
103
|
+
this.split(node);
|
|
104
|
+
// Re-insert items into children
|
|
105
|
+
const itemsToReinsert = [...node.items];
|
|
106
|
+
node.items = [];
|
|
107
|
+
for (const i of itemsToReinsert) {
|
|
108
|
+
this.insertIntoNode(node, i, depth);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
removeFromNode(node, item) {
|
|
113
|
+
// Check this node's items
|
|
114
|
+
const idx = node.items.findIndex((i) => i.id === item.id);
|
|
115
|
+
if (idx !== -1) {
|
|
116
|
+
node.items.splice(idx, 1);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
// Check children
|
|
120
|
+
if (node.children) {
|
|
121
|
+
for (const child of node.children) {
|
|
122
|
+
if (this.boundsIntersect(child.bounds, item.bounds)) {
|
|
123
|
+
if (this.removeFromNode(child, item)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
queryNode(node, bounds, results) {
|
|
132
|
+
// Check items in this node
|
|
133
|
+
for (const item of node.items) {
|
|
134
|
+
if (this.boundsIntersect(item.bounds, bounds)) {
|
|
135
|
+
results.push(item);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Check children
|
|
139
|
+
if (node.children) {
|
|
140
|
+
for (const child of node.children) {
|
|
141
|
+
if (this.boundsIntersect(child.bounds, bounds)) {
|
|
142
|
+
this.queryNode(child, bounds, results);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
split(node) {
|
|
148
|
+
const { x, y, width, height } = node.bounds;
|
|
149
|
+
const hw = width / 2;
|
|
150
|
+
const hh = height / 2;
|
|
151
|
+
node.children = [
|
|
152
|
+
{ bounds: { x, y, width: hw, height: hh }, items: [], children: null }, // NW
|
|
153
|
+
{ bounds: { x: x + hw, y, width: hw, height: hh }, items: [], children: null }, // NE
|
|
154
|
+
{ bounds: { x, y: y + hh, width: hw, height: hh }, items: [], children: null }, // SW
|
|
155
|
+
{ bounds: { x: x + hw, y: y + hh, width: hw, height: hh }, items: [], children: null }, // SE
|
|
156
|
+
];
|
|
157
|
+
}
|
|
158
|
+
getChildIndex(node, bounds) {
|
|
159
|
+
if (!node.children) {
|
|
160
|
+
return -1;
|
|
161
|
+
}
|
|
162
|
+
const midX = node.bounds.x + node.bounds.width / 2;
|
|
163
|
+
const midY = node.bounds.y + node.bounds.height / 2;
|
|
164
|
+
const inLeft = bounds.x + bounds.width <= midX;
|
|
165
|
+
const inRight = bounds.x >= midX;
|
|
166
|
+
const inTop = bounds.y + bounds.height <= midY;
|
|
167
|
+
const inBottom = bounds.y >= midY;
|
|
168
|
+
if (inTop && inLeft) {
|
|
169
|
+
return 0;
|
|
170
|
+
} // NW
|
|
171
|
+
if (inTop && inRight) {
|
|
172
|
+
return 1;
|
|
173
|
+
} // NE
|
|
174
|
+
if (inBottom && inLeft) {
|
|
175
|
+
return 2;
|
|
176
|
+
} // SW
|
|
177
|
+
if (inBottom && inRight) {
|
|
178
|
+
return 3;
|
|
179
|
+
} // SE
|
|
180
|
+
return -1; // Spans multiple quadrants
|
|
181
|
+
}
|
|
182
|
+
boundsIntersect(a, b) {
|
|
183
|
+
return (a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Create a QuadTree for a floor plan with automatic bounds detection.
|
|
188
|
+
*/
|
|
189
|
+
export function createFloorPlanQuadTree(items, padding = 100) {
|
|
190
|
+
// Calculate bounds from all items
|
|
191
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
192
|
+
for (const item of items) {
|
|
193
|
+
const { x, y } = item.position;
|
|
194
|
+
const { width = 20, height = 20 } = item.size ?? {};
|
|
195
|
+
minX = Math.min(minX, x - width / 2);
|
|
196
|
+
minY = Math.min(minY, y - height / 2);
|
|
197
|
+
maxX = Math.max(maxX, x + width / 2);
|
|
198
|
+
maxY = Math.max(maxY, y + height / 2);
|
|
199
|
+
}
|
|
200
|
+
// Handle empty items
|
|
201
|
+
if (!Number.isFinite(minX)) {
|
|
202
|
+
minX = minY = 0;
|
|
203
|
+
maxX = maxY = 1000;
|
|
204
|
+
}
|
|
205
|
+
const bounds = {
|
|
206
|
+
x: minX - padding,
|
|
207
|
+
y: minY - padding,
|
|
208
|
+
width: maxX - minX + padding * 2,
|
|
209
|
+
height: maxY - minY + padding * 2,
|
|
210
|
+
};
|
|
211
|
+
const quadTree = new QuadTree(bounds);
|
|
212
|
+
for (const item of items) {
|
|
213
|
+
const { x, y } = item.position;
|
|
214
|
+
const { width = 20, height = 20 } = item.size ?? {};
|
|
215
|
+
quadTree.insert({
|
|
216
|
+
id: item.id,
|
|
217
|
+
bounds: {
|
|
218
|
+
x: x - width / 2,
|
|
219
|
+
y: y - height / 2,
|
|
220
|
+
width,
|
|
221
|
+
height,
|
|
222
|
+
},
|
|
223
|
+
data: item.data,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return quadTree;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=QuadTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuadTree.js","sourceRoot":"","sources":["../../src/virtualization/QuadTree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewportCulling — Utilities for efficient viewport-based rendering
|
|
3
|
+
*
|
|
4
|
+
* Calculates visible bounds and filters objects for rendering optimization.
|
|
5
|
+
*/
|
|
6
|
+
import type { Bounds, QuadTree, QuadTreeItem } from './QuadTree';
|
|
7
|
+
/** Viewport state with pan/zoom */
|
|
8
|
+
export interface ViewportState {
|
|
9
|
+
/** Current zoom level (1 = 100%) */
|
|
10
|
+
zoom: number;
|
|
11
|
+
/** Pan offset in screen coordinates */
|
|
12
|
+
pan: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** Container size in pixels */
|
|
18
|
+
export interface ContainerSize {
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Calculate visible world bounds from viewport state.
|
|
24
|
+
*
|
|
25
|
+
* @param viewport - Current viewport pan/zoom state
|
|
26
|
+
* @param containerSize - Container dimensions in pixels
|
|
27
|
+
* @param overscan - Extra margin to render outside visible area (default 100px)
|
|
28
|
+
* @returns World-space bounds of the visible area
|
|
29
|
+
*/
|
|
30
|
+
export declare function calculateVisibleBounds(viewport: ViewportState, containerSize: ContainerSize, overscan?: number): Bounds;
|
|
31
|
+
/**
|
|
32
|
+
* Check if an object's bounds are within the visible viewport.
|
|
33
|
+
*
|
|
34
|
+
* @param objectBounds - Object bounds in world coordinates
|
|
35
|
+
* @param visibleBounds - Visible area bounds in world coordinates
|
|
36
|
+
* @returns true if the object should be rendered
|
|
37
|
+
*/
|
|
38
|
+
export declare function isInViewport(objectBounds: Bounds, visibleBounds: Bounds): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Filter items to only those visible in the viewport.
|
|
41
|
+
*
|
|
42
|
+
* @param items - Array of items with position and optional size
|
|
43
|
+
* @param visibleBounds - Visible bounds in world coordinates
|
|
44
|
+
* @returns Filtered array of visible items
|
|
45
|
+
*/
|
|
46
|
+
export declare function filterVisibleItems<T extends {
|
|
47
|
+
position: {
|
|
48
|
+
x: number;
|
|
49
|
+
y: number;
|
|
50
|
+
};
|
|
51
|
+
size?: {
|
|
52
|
+
width: number;
|
|
53
|
+
height: number;
|
|
54
|
+
};
|
|
55
|
+
}>(items: T[], visibleBounds: Bounds): T[];
|
|
56
|
+
/**
|
|
57
|
+
* Query visible items from a QuadTree based on viewport.
|
|
58
|
+
*
|
|
59
|
+
* @param quadTree - QuadTree spatial index
|
|
60
|
+
* @param viewport - Current viewport state
|
|
61
|
+
* @param containerSize - Container dimensions
|
|
62
|
+
* @param overscan - Extra margin to render
|
|
63
|
+
* @returns Array of visible items from the quadtree
|
|
64
|
+
*/
|
|
65
|
+
export declare function queryVisibleFromQuadTree<T>(quadTree: QuadTree<T>, viewport: ViewportState, containerSize: ContainerSize, overscan?: number): QuadTreeItem<T>[];
|
|
66
|
+
/**
|
|
67
|
+
* Calculate if virtual rendering is beneficial based on object count.
|
|
68
|
+
*
|
|
69
|
+
* @param totalObjects - Total number of objects in the scene
|
|
70
|
+
* @param threshold - Minimum objects for virtual rendering (default 200)
|
|
71
|
+
* @returns true if virtual rendering should be used
|
|
72
|
+
*/
|
|
73
|
+
export declare function shouldUseVirtualRendering(totalObjects: number, threshold?: number): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Calculate rendering statistics for debugging/monitoring.
|
|
76
|
+
*/
|
|
77
|
+
export declare function calculateRenderStats(totalObjects: number, visibleObjects: number, viewport: ViewportState): {
|
|
78
|
+
total: number;
|
|
79
|
+
visible: number;
|
|
80
|
+
culled: number;
|
|
81
|
+
cullPercentage: number;
|
|
82
|
+
zoom: number;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Debounced quadtree update for dynamic scenes.
|
|
86
|
+
* Returns a function that batches updates.
|
|
87
|
+
*/
|
|
88
|
+
export declare function createQuadTreeUpdater<T>(quadTree: QuadTree<T>, debounceMs?: number): {
|
|
89
|
+
scheduleUpdate: (id: string, bounds: Bounds) => void;
|
|
90
|
+
flush: () => void;
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=ViewportCulling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ViewportCulling.d.ts","sourceRoot":"","sources":["../../src/virtualization/ViewportCulling.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEjE,mCAAmC;AACnC,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/B;AAED,+BAA+B;AAC/B,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,aAAa,EACvB,aAAa,EAAE,aAAa,EAC5B,QAAQ,SAAM,GACb,MAAM,CAgBR;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAOjF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,SAAS;IAAE,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAC1F,KAAK,EAAE,CAAC,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,CAAC,EAAE,CAYxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,QAAQ,EAAE,aAAa,EACvB,aAAa,EAAE,aAAa,EAC5B,QAAQ,SAAM,GACb,YAAY,CAAC,CAAC,CAAC,EAAE,CAGnB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,OAAO,CAExF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,aAAa,GACtB;IACD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd,CASA;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,UAAU,SAAK,GACd;IACD,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAuBA"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewportCulling — Utilities for efficient viewport-based rendering
|
|
3
|
+
*
|
|
4
|
+
* Calculates visible bounds and filters objects for rendering optimization.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Calculate visible world bounds from viewport state.
|
|
8
|
+
*
|
|
9
|
+
* @param viewport - Current viewport pan/zoom state
|
|
10
|
+
* @param containerSize - Container dimensions in pixels
|
|
11
|
+
* @param overscan - Extra margin to render outside visible area (default 100px)
|
|
12
|
+
* @returns World-space bounds of the visible area
|
|
13
|
+
*/
|
|
14
|
+
export function calculateVisibleBounds(viewport, containerSize, overscan = 100) {
|
|
15
|
+
// Convert screen coordinates to world coordinates
|
|
16
|
+
// Screen origin is at pan.x, pan.y after zoom
|
|
17
|
+
// World coord = (screen - pan) / zoom
|
|
18
|
+
const worldWidth = (containerSize.width + overscan * 2) / viewport.zoom;
|
|
19
|
+
const worldHeight = (containerSize.height + overscan * 2) / viewport.zoom;
|
|
20
|
+
const worldX = (-viewport.pan.x - overscan) / viewport.zoom;
|
|
21
|
+
const worldY = (-viewport.pan.y - overscan) / viewport.zoom;
|
|
22
|
+
return {
|
|
23
|
+
x: worldX,
|
|
24
|
+
y: worldY,
|
|
25
|
+
width: worldWidth,
|
|
26
|
+
height: worldHeight,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if an object's bounds are within the visible viewport.
|
|
31
|
+
*
|
|
32
|
+
* @param objectBounds - Object bounds in world coordinates
|
|
33
|
+
* @param visibleBounds - Visible area bounds in world coordinates
|
|
34
|
+
* @returns true if the object should be rendered
|
|
35
|
+
*/
|
|
36
|
+
export function isInViewport(objectBounds, visibleBounds) {
|
|
37
|
+
return (objectBounds.x < visibleBounds.x + visibleBounds.width &&
|
|
38
|
+
objectBounds.x + objectBounds.width > visibleBounds.x &&
|
|
39
|
+
objectBounds.y < visibleBounds.y + visibleBounds.height &&
|
|
40
|
+
objectBounds.y + objectBounds.height > visibleBounds.y);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Filter items to only those visible in the viewport.
|
|
44
|
+
*
|
|
45
|
+
* @param items - Array of items with position and optional size
|
|
46
|
+
* @param visibleBounds - Visible bounds in world coordinates
|
|
47
|
+
* @returns Filtered array of visible items
|
|
48
|
+
*/
|
|
49
|
+
export function filterVisibleItems(items, visibleBounds) {
|
|
50
|
+
return items.filter((item) => {
|
|
51
|
+
const { x, y } = item.position;
|
|
52
|
+
const { width = 20, height = 20 } = item.size ?? {};
|
|
53
|
+
const bounds = {
|
|
54
|
+
x: x - width / 2,
|
|
55
|
+
y: y - height / 2,
|
|
56
|
+
width,
|
|
57
|
+
height,
|
|
58
|
+
};
|
|
59
|
+
return isInViewport(bounds, visibleBounds);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Query visible items from a QuadTree based on viewport.
|
|
64
|
+
*
|
|
65
|
+
* @param quadTree - QuadTree spatial index
|
|
66
|
+
* @param viewport - Current viewport state
|
|
67
|
+
* @param containerSize - Container dimensions
|
|
68
|
+
* @param overscan - Extra margin to render
|
|
69
|
+
* @returns Array of visible items from the quadtree
|
|
70
|
+
*/
|
|
71
|
+
export function queryVisibleFromQuadTree(quadTree, viewport, containerSize, overscan = 100) {
|
|
72
|
+
const visibleBounds = calculateVisibleBounds(viewport, containerSize, overscan);
|
|
73
|
+
return quadTree.query(visibleBounds);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Calculate if virtual rendering is beneficial based on object count.
|
|
77
|
+
*
|
|
78
|
+
* @param totalObjects - Total number of objects in the scene
|
|
79
|
+
* @param threshold - Minimum objects for virtual rendering (default 200)
|
|
80
|
+
* @returns true if virtual rendering should be used
|
|
81
|
+
*/
|
|
82
|
+
export function shouldUseVirtualRendering(totalObjects, threshold = 200) {
|
|
83
|
+
return totalObjects >= threshold;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Calculate rendering statistics for debugging/monitoring.
|
|
87
|
+
*/
|
|
88
|
+
export function calculateRenderStats(totalObjects, visibleObjects, viewport) {
|
|
89
|
+
const culled = totalObjects - visibleObjects;
|
|
90
|
+
return {
|
|
91
|
+
total: totalObjects,
|
|
92
|
+
visible: visibleObjects,
|
|
93
|
+
culled,
|
|
94
|
+
cullPercentage: totalObjects > 0 ? Math.round((culled / totalObjects) * 100) : 0,
|
|
95
|
+
zoom: viewport.zoom,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Debounced quadtree update for dynamic scenes.
|
|
100
|
+
* Returns a function that batches updates.
|
|
101
|
+
*/
|
|
102
|
+
export function createQuadTreeUpdater(quadTree, debounceMs = 16) {
|
|
103
|
+
const pendingUpdates = new Map();
|
|
104
|
+
let timeoutId = null;
|
|
105
|
+
const flush = () => {
|
|
106
|
+
if (pendingUpdates.size === 0) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
for (const [id, bounds] of pendingUpdates) {
|
|
110
|
+
quadTree.update(id, bounds);
|
|
111
|
+
}
|
|
112
|
+
pendingUpdates.clear();
|
|
113
|
+
timeoutId = null;
|
|
114
|
+
};
|
|
115
|
+
const scheduleUpdate = (id, bounds) => {
|
|
116
|
+
pendingUpdates.set(id, bounds);
|
|
117
|
+
if (!timeoutId) {
|
|
118
|
+
timeoutId = setTimeout(flush, debounceMs);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
return { scheduleUpdate, flush };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=ViewportCulling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ViewportCulling.js","sourceRoot":"","sources":["../../src/virtualization/ViewportCulling.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtualization — Efficient rendering for large floor plans
|
|
3
|
+
*
|
|
4
|
+
* Provides spatial indexing (QuadTree) and viewport culling utilities
|
|
5
|
+
* for rendering optimization with 1000+ objects.
|
|
6
|
+
*/
|
|
7
|
+
export { QuadTree, createFloorPlanQuadTree, type Bounds, type QuadTreeItem, } from './QuadTree';
|
|
8
|
+
export { calculateVisibleBounds, isInViewport, filterVisibleItems, queryVisibleFromQuadTree, shouldUseVirtualRendering, calculateRenderStats, createQuadTreeUpdater, type ViewportState, type ContainerSize, } from './ViewportCulling';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/virtualization/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,QAAQ,EACR,uBAAuB,EACvB,KAAK,MAAM,EACX,KAAK,YAAY,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACH,sBAAsB,EACtB,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,aAAa,GACrB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtualization — Efficient rendering for large floor plans
|
|
3
|
+
*
|
|
4
|
+
* Provides spatial indexing (QuadTree) and viewport culling utilities
|
|
5
|
+
* for rendering optimization with 1000+ objects.
|
|
6
|
+
*/
|
|
7
|
+
export { QuadTree, createFloorPlanQuadTree, } from './QuadTree';
|
|
8
|
+
export { calculateVisibleBounds, isInViewport, filterVisibleItems, queryVisibleFromQuadTree, shouldUseVirtualRendering, calculateRenderStats, createQuadTreeUpdater, } from './ViewportCulling';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/virtualization/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,QAAQ,EACR,uBAAuB,GAG1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACH,sBAAsB,EACtB,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,GAGxB,MAAM,mBAAmB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nice2dev/spatial-core",
|
|
3
|
+
"version": "1.0.10",
|
|
4
|
+
"description": "Unified spatial/floor-plan/CAD core logic for Nice2Dev UI components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./grid": {
|
|
15
|
+
"import": "./dist/grid/index.js",
|
|
16
|
+
"types": "./dist/grid/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./objects": {
|
|
19
|
+
"import": "./dist/objects/index.js",
|
|
20
|
+
"types": "./dist/objects/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./floor-plan": {
|
|
23
|
+
"import": "./dist/floor-plan/index.js",
|
|
24
|
+
"types": "./dist/floor-plan/index.d.ts"
|
|
25
|
+
},
|
|
26
|
+
"./measurement": {
|
|
27
|
+
"import": "./dist/measurement/index.js",
|
|
28
|
+
"types": "./dist/measurement/index.d.ts"
|
|
29
|
+
},
|
|
30
|
+
"./serialization": {
|
|
31
|
+
"import": "./dist/serialization/index.js",
|
|
32
|
+
"types": "./dist/serialization/index.d.ts"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc -p tsconfig.build.json",
|
|
41
|
+
"dev": "tsc -p tsconfig.build.json --watch",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:watch": "vitest",
|
|
44
|
+
"lint": "eslint src --ext .ts",
|
|
45
|
+
"clean": "rimraf dist"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"spatial",
|
|
49
|
+
"floor-plan",
|
|
50
|
+
"cad",
|
|
51
|
+
"grid",
|
|
52
|
+
"editor",
|
|
53
|
+
"nice2dev"
|
|
54
|
+
],
|
|
55
|
+
"author": "NiceToDev",
|
|
56
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"typescript": "^5.3.0",
|
|
59
|
+
"vitest": "^1.2.0",
|
|
60
|
+
"rimraf": "^5.0.0"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {},
|
|
63
|
+
"sideEffects": false
|
|
64
|
+
}
|