@woosh/meep-engine 2.87.6 → 2.88.1
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/build/meep.cjs +26 -4
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +26 -4
- package/editor/view/ecs/HierarchicalEntityListView.js +1 -1
- package/editor/view/v2/prototypeEditor.js +1 -1
- package/package.json +1 -1
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +4 -2
- package/src/core/bvh2/bvh3/BVH.spec.js +15 -3
- package/src/core/geom/2d/aabb/aabb2_clip_line_cohen_sutherland.d.ts +16 -0
- package/src/core/geom/2d/aabb/aabb2_clip_line_cohen_sutherland.d.ts.map +1 -0
- package/src/core/geom/2d/aabb/aabb2_clip_line_cohen_sutherland.js +149 -0
- package/src/core/geom/2d/aabb/aabb2_intersects_circle.d.ts +13 -0
- package/src/core/geom/2d/aabb/aabb2_intersects_circle.d.ts.map +1 -0
- package/src/core/geom/2d/aabb/aabb2_intersects_circle.js +27 -0
- package/src/core/geom/2d/hash-grid/SpatialHashGrid.d.ts +41 -6
- package/src/core/geom/2d/hash-grid/SpatialHashGrid.d.ts.map +1 -1
- package/src/core/geom/2d/hash-grid/SpatialHashGrid.js +92 -22
- package/src/core/geom/2d/hash-grid/SpatialHashGrid.spec.js +98 -2
- package/src/core/geom/2d/hash-grid/prototypeGridQueries.d.ts +2 -0
- package/src/core/geom/2d/hash-grid/prototypeGridQueries.d.ts.map +1 -0
- package/src/core/geom/2d/hash-grid/prototypeGridQueries.js +387 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts +12 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +160 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.spec.d.ts +2 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.spec.d.ts.map +1 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.spec.js +85 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts +14 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +132 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_line.spec.d.ts +2 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_line.spec.d.ts.map +1 -0
- package/src/core/geom/2d/hash-grid/shg_query_elements_line.spec.js +102 -0
- package/src/core/geom/2d/line/line2_distance_to_point_sqr.d.ts +11 -0
- package/src/core/geom/2d/line/line2_distance_to_point_sqr.d.ts.map +1 -0
- package/src/core/geom/2d/line/line2_distance_to_point_sqr.js +39 -0
- package/src/core/geom/2d/quad-tree/QuadTreeNode.spec.js +53 -0
- package/src/core/geom/2d/quad-tree/qt_match_data_by_circle.spec.d.ts +2 -0
- package/src/core/geom/2d/quad-tree/qt_match_data_by_circle.spec.d.ts.map +1 -0
- package/src/core/geom/2d/quad-tree/qt_match_data_by_circle.spec.js +86 -0
- package/src/core/model/ObservedString.d.ts.map +1 -1
- package/src/core/model/ObservedString.js +1 -1
- package/src/engine/animation/curve/ecd_bind_animation_curve.js +1 -1
- package/src/engine/ecs/name/Name.d.ts +25 -0
- package/src/engine/ecs/name/Name.d.ts.map +1 -0
- package/src/engine/ecs/name/Name.js +42 -0
- package/src/engine/ecs/name/NameSerializationAdapter.d.ts +18 -0
- package/src/engine/ecs/name/NameSerializationAdapter.d.ts.map +1 -0
- package/src/engine/ecs/name/NameSerializationAdapter.js +29 -0
- package/src/engine/ecs/transform/Transform.d.ts +2 -2
- package/src/engine/graphics/canvas/canvas2d_draw_grid.js +1 -1
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.d.ts.map +1 -1
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +17 -1
- package/src/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +1 -1
- package/src/core/geom/2d/hash-grid/shg_query_raycast.d.ts +0 -14
- package/src/core/geom/2d/hash-grid/shg_query_raycast.d.ts.map +0 -1
- package/src/core/geom/2d/hash-grid/shg_query_raycast.js +0 -21
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { randomFloatBetween } from "../../../math/random/randomFloatBetween.js";
|
|
2
|
+
import { seededRandom } from "../../../math/random/seededRandom.js";
|
|
3
|
+
import { shg_query_elements_circle } from "./shg_query_elements_circle.js";
|
|
4
|
+
import { SpatialHashGrid } from "./SpatialHashGrid.js";
|
|
5
|
+
|
|
6
|
+
test("performance, 10k objects, 1m queries", () => {
|
|
7
|
+
const OBJECT_COUNT = 30000;
|
|
8
|
+
const QUERY_COUNT = 1e6;
|
|
9
|
+
|
|
10
|
+
const QUERY_DISTANCE_MIN = 0.1;
|
|
11
|
+
const QUERY_DISTANCE_MAX = 0.2;
|
|
12
|
+
|
|
13
|
+
const grid = new SpatialHashGrid(128, 128, 2);
|
|
14
|
+
|
|
15
|
+
const grid_bounds_x1 = grid.size_x * grid.scale;
|
|
16
|
+
const grid_bounds_y1 = grid.size_y * grid.scale;
|
|
17
|
+
|
|
18
|
+
const random = seededRandom();
|
|
19
|
+
|
|
20
|
+
// fill
|
|
21
|
+
for (let i = 0; i < OBJECT_COUNT; i++) {
|
|
22
|
+
const el = grid.element_allocate();
|
|
23
|
+
|
|
24
|
+
grid.element_set_user_data(el, i);
|
|
25
|
+
|
|
26
|
+
const width = randomFloatBetween(random, 0.2, 1);
|
|
27
|
+
const height = randomFloatBetween(random, 0.2, 1);
|
|
28
|
+
const x0 = randomFloatBetween(random, 0, grid_bounds_x1 - width);
|
|
29
|
+
const y0 = randomFloatBetween(random, 0, grid_bounds_y1 - height);
|
|
30
|
+
|
|
31
|
+
grid.element_set_bounds_primitive(el,
|
|
32
|
+
x0,
|
|
33
|
+
y0,
|
|
34
|
+
x0 + width,
|
|
35
|
+
y0 + height
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
grid.element_insert(el);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const queries = new Float32Array(QUERY_COUNT * 3);
|
|
43
|
+
|
|
44
|
+
// build queries
|
|
45
|
+
for (let i = 0; i < QUERY_COUNT; i++) {
|
|
46
|
+
|
|
47
|
+
const offset = i * 3;
|
|
48
|
+
|
|
49
|
+
// pick radius
|
|
50
|
+
const radius = randomFloatBetween(random, QUERY_DISTANCE_MIN, QUERY_DISTANCE_MAX);
|
|
51
|
+
|
|
52
|
+
// pick starting point
|
|
53
|
+
const ax = randomFloatBetween(random, radius, grid_bounds_x1 - radius);
|
|
54
|
+
const ay = randomFloatBetween(random, radius, grid_bounds_y1 - radius);
|
|
55
|
+
|
|
56
|
+
queries[offset] = ax;
|
|
57
|
+
queries[offset + 1] = ay;
|
|
58
|
+
|
|
59
|
+
queries[offset + 2] = radius;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// execute
|
|
63
|
+
const t0 = performance.now();
|
|
64
|
+
|
|
65
|
+
const result = [];
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < QUERY_COUNT; i++) {
|
|
68
|
+
|
|
69
|
+
const offset = i * 3;
|
|
70
|
+
|
|
71
|
+
shg_query_elements_circle(
|
|
72
|
+
result, 0, grid,
|
|
73
|
+
queries[offset],
|
|
74
|
+
queries[offset + 1],
|
|
75
|
+
queries[offset + 2],
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const duration = performance.now() - t0;
|
|
80
|
+
|
|
81
|
+
const duration_seconds = duration * 1e-3;
|
|
82
|
+
|
|
83
|
+
console.log(`Duration ${duration_seconds}s, ${(QUERY_COUNT / duration_seconds).toFixed(2)} cycles per second`);
|
|
84
|
+
|
|
85
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Note that line coordinates MUST lie within the grid
|
|
4
|
+
* @param {number[]} result
|
|
5
|
+
* @param {number} result_offset
|
|
6
|
+
* @param {SpatialHashGrid} grid
|
|
7
|
+
* @param {number} x0 first line point X
|
|
8
|
+
* @param {number} y0 first line point Y
|
|
9
|
+
* @param {number} x1 second line point X
|
|
10
|
+
* @param {number} y1 second line point Y
|
|
11
|
+
* @returns {number} number of elements added to result array
|
|
12
|
+
*/
|
|
13
|
+
export function shg_query_elements_line(result: number[], result_offset: number, grid: SpatialHashGrid, x0: number, y0: number, x1: number, y1: number): number;
|
|
14
|
+
//# sourceMappingURL=shg_query_elements_line.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shg_query_elements_line.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/2d/hash-grid/shg_query_elements_line.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;GAWG;AACH,gDATW,MAAM,EAAE,iBACR,MAAM,6BAEN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,MAAM,CA0GlB"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { assert } from "../../../assert.js";
|
|
2
|
+
import { aabb2_clip_line_cohen_sutherland } from "../aabb/aabb2_clip_line_cohen_sutherland.js";
|
|
3
|
+
import { line2_distance_to_point_sqr } from "../line/line2_distance_to_point_sqr.js";
|
|
4
|
+
import {
|
|
5
|
+
COLUMN_ELEMENT_X0,
|
|
6
|
+
COLUMN_ELEMENT_X1,
|
|
7
|
+
COLUMN_ELEMENT_Y0,
|
|
8
|
+
COLUMN_ELEMENT_Y1,
|
|
9
|
+
NULL_POINTER
|
|
10
|
+
} from "./SpatialHashGrid.js";
|
|
11
|
+
|
|
12
|
+
const scratch_float32 = new Float32Array(4);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* Note that line coordinates MUST lie within the grid
|
|
17
|
+
* @param {number[]} result
|
|
18
|
+
* @param {number} result_offset
|
|
19
|
+
* @param {SpatialHashGrid} grid
|
|
20
|
+
* @param {number} x0 first line point X
|
|
21
|
+
* @param {number} y0 first line point Y
|
|
22
|
+
* @param {number} x1 second line point X
|
|
23
|
+
* @param {number} y1 second line point Y
|
|
24
|
+
* @returns {number} number of elements added to result array
|
|
25
|
+
*/
|
|
26
|
+
export function shg_query_elements_line(
|
|
27
|
+
result, result_offset,
|
|
28
|
+
grid,
|
|
29
|
+
x0, y0,
|
|
30
|
+
x1, y1
|
|
31
|
+
) {
|
|
32
|
+
|
|
33
|
+
// shg_query_elements_line.visited.splice(0, shg_query_elements_line.visited.length); // DEBUG
|
|
34
|
+
|
|
35
|
+
assert.ok(x0 <= grid.size_x * grid.scale && x0 >= 0, `x0(=${x0}) out of bounds`);
|
|
36
|
+
assert.ok(x1 <= grid.size_x * grid.scale && x1 >= 0, `x1(=${x1}) out of bounds`);
|
|
37
|
+
assert.ok(y0 <= grid.size_y * grid.scale && y0 >= 0, `y0(=${y0}) out of bounds`);
|
|
38
|
+
assert.ok(y1 <= grid.size_y * grid.scale && y1 >= 0, `y1(=${y1}) out of bounds`);
|
|
39
|
+
|
|
40
|
+
// rasterize line
|
|
41
|
+
const scale_inverse = grid.scale_inverse;
|
|
42
|
+
|
|
43
|
+
// below is a modified version of Bresenham's line algorithm
|
|
44
|
+
const grid_x0 = x0 * scale_inverse;
|
|
45
|
+
const grid_y0 = y0 * scale_inverse;
|
|
46
|
+
const grid_x1 = x1 * scale_inverse;
|
|
47
|
+
const grid_y1 = y1 * scale_inverse;
|
|
48
|
+
|
|
49
|
+
let igrid_x0 = Math.floor(grid_x0);
|
|
50
|
+
let igrid_y0 = Math.floor(grid_y0);
|
|
51
|
+
let igrid_x1 = Math.floor(grid_x1);
|
|
52
|
+
let igrid_y1 = Math.floor(grid_y1);
|
|
53
|
+
|
|
54
|
+
const step_x = igrid_x0 < igrid_x1 ? 1 : -1;
|
|
55
|
+
const step_y = igrid_y0 < igrid_y1 ? 1 : -1;
|
|
56
|
+
|
|
57
|
+
const element_pool = grid.element_pool;
|
|
58
|
+
const element_float32 = element_pool.data_float32;
|
|
59
|
+
|
|
60
|
+
let result_count = 0;
|
|
61
|
+
|
|
62
|
+
let x = igrid_x0;
|
|
63
|
+
let y = igrid_y0;
|
|
64
|
+
|
|
65
|
+
for (; ;) {
|
|
66
|
+
|
|
67
|
+
const cell_index = grid.cell_position_to_index(x, y);
|
|
68
|
+
|
|
69
|
+
// shg_query_elements_line.visited.push(x, y); // DEBUG
|
|
70
|
+
|
|
71
|
+
let node = grid.cell_get_first_node(cell_index);
|
|
72
|
+
|
|
73
|
+
while (node !== NULL_POINTER) {
|
|
74
|
+
|
|
75
|
+
const element = grid.node_get_element(node);
|
|
76
|
+
|
|
77
|
+
// check element bounds
|
|
78
|
+
const element_address = element_pool.element_word(element);
|
|
79
|
+
|
|
80
|
+
const element_x0 = element_float32[element_address + COLUMN_ELEMENT_X0];
|
|
81
|
+
const element_y0 = element_float32[element_address + COLUMN_ELEMENT_Y0];
|
|
82
|
+
const element_x1 = element_float32[element_address + COLUMN_ELEMENT_X1];
|
|
83
|
+
const element_y1 = element_float32[element_address + COLUMN_ELEMENT_Y1];
|
|
84
|
+
|
|
85
|
+
if (aabb2_clip_line_cohen_sutherland(
|
|
86
|
+
scratch_float32, 0,
|
|
87
|
+
element_x0, element_y0,
|
|
88
|
+
element_x1, element_y1,
|
|
89
|
+
x0, y0, x1, y1
|
|
90
|
+
)) {
|
|
91
|
+
// intersection with the element
|
|
92
|
+
result[result_offset + result_count] = element;
|
|
93
|
+
|
|
94
|
+
result_count++;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
// read out next element in the linked list
|
|
99
|
+
node = grid.node_get_same_cell_next_node(node);
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (x === igrid_x1 && y === igrid_y1) {
|
|
104
|
+
// we're done
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// check moves forward
|
|
109
|
+
const move_x_distance = line2_distance_to_point_sqr(
|
|
110
|
+
grid_x0, grid_y0, grid_x1, grid_y1,
|
|
111
|
+
x + step_x + 0.5, y + 0.5
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const move_y_distance = line2_distance_to_point_sqr(
|
|
115
|
+
grid_x0, grid_y0, grid_x1, grid_y1,
|
|
116
|
+
x + 0.5, y + step_y + 0.5
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (move_x_distance <= move_y_distance && x !== igrid_x1) {
|
|
120
|
+
x += step_x;
|
|
121
|
+
} else if (y !== igrid_y1) {
|
|
122
|
+
y += step_y;
|
|
123
|
+
} else {
|
|
124
|
+
// unexpected, or we just reached the end
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return result_count;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// shg_query_elements_line.visited = []; // DEBUG
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shg_query_elements_line.spec.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/2d/hash-grid/shg_query_elements_line.spec.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { randomFloatBetween } from "../../../math/random/randomFloatBetween.js";
|
|
2
|
+
import { seededRandom } from "../../../math/random/seededRandom.js";
|
|
3
|
+
import { shg_query_elements_line } from "./shg_query_elements_line.js";
|
|
4
|
+
import { SpatialHashGrid } from "./SpatialHashGrid.js";
|
|
5
|
+
|
|
6
|
+
test.skip("performance, 10k objects, 100k queries", () => {
|
|
7
|
+
const OBJECT_COUNT = 30000;
|
|
8
|
+
const QUERY_COUNT = 100000;
|
|
9
|
+
|
|
10
|
+
const QUERY_DISTANCE_MIN = 0.1;
|
|
11
|
+
const QUERY_DISTANCE_MAX = 0.2;
|
|
12
|
+
|
|
13
|
+
const grid = new SpatialHashGrid(128, 128, 1);
|
|
14
|
+
|
|
15
|
+
const grid_bounds_x1 = grid.size_x * grid.scale;
|
|
16
|
+
const grid_bounds_y1 = grid.size_y * grid.scale;
|
|
17
|
+
|
|
18
|
+
const random = seededRandom();
|
|
19
|
+
|
|
20
|
+
// fill
|
|
21
|
+
for (let i = 0; i < OBJECT_COUNT; i++) {
|
|
22
|
+
const el = grid.element_allocate();
|
|
23
|
+
|
|
24
|
+
grid.element_set_user_data(el, i);
|
|
25
|
+
|
|
26
|
+
const width = randomFloatBetween(random, 0.2, 1);
|
|
27
|
+
const height = randomFloatBetween(random, 0.2, 1);
|
|
28
|
+
const x0 = randomFloatBetween(random, 0, grid_bounds_x1 - width);
|
|
29
|
+
const y0 = randomFloatBetween(random, 0, grid_bounds_y1 - height);
|
|
30
|
+
|
|
31
|
+
grid.element_set_bounds_primitive(el,
|
|
32
|
+
x0,
|
|
33
|
+
y0,
|
|
34
|
+
x0 + width,
|
|
35
|
+
y0 + height
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
grid.element_insert(el);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const queries = new Float32Array(QUERY_COUNT * 4);
|
|
43
|
+
|
|
44
|
+
// build queries
|
|
45
|
+
for (let i = 0; i < QUERY_COUNT; i++) {
|
|
46
|
+
|
|
47
|
+
const offset = i * 4;
|
|
48
|
+
|
|
49
|
+
// pick starting point
|
|
50
|
+
const ax = randomFloatBetween(random, 0.001, grid_bounds_x1 - 0.001);
|
|
51
|
+
const ay = randomFloatBetween(random, 0.001, grid_bounds_y1 - 0.001);
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
const angle = randomFloatBetween(random, -Math.PI, Math.PI);
|
|
55
|
+
|
|
56
|
+
let direction_x = Math.cos(angle);
|
|
57
|
+
let direction_y = Math.sin(angle);
|
|
58
|
+
|
|
59
|
+
if (direction_x * (ax - grid_bounds_x1 * 0.5) > 0) {
|
|
60
|
+
direction_x = -direction_x;
|
|
61
|
+
}
|
|
62
|
+
if (direction_y * (ay - grid_bounds_y1 * 0.5) > 0) {
|
|
63
|
+
direction_y = -direction_y;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const query_distance = randomFloatBetween(random, QUERY_DISTANCE_MIN, QUERY_DISTANCE_MAX);
|
|
67
|
+
|
|
68
|
+
const bx = ax + direction_x * query_distance;
|
|
69
|
+
const by = ay + direction_y * query_distance;
|
|
70
|
+
|
|
71
|
+
queries[offset] = ax;
|
|
72
|
+
queries[offset + 1] = ay;
|
|
73
|
+
|
|
74
|
+
queries[offset + 2] = bx;
|
|
75
|
+
queries[offset + 3] = by;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// execute
|
|
79
|
+
const t0 = performance.now();
|
|
80
|
+
|
|
81
|
+
const result = [];
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < QUERY_COUNT; i++) {
|
|
84
|
+
|
|
85
|
+
const offset = i * 4;
|
|
86
|
+
|
|
87
|
+
shg_query_elements_line(
|
|
88
|
+
result, 0, grid,
|
|
89
|
+
queries[offset],
|
|
90
|
+
queries[offset + 1],
|
|
91
|
+
queries[offset + 2],
|
|
92
|
+
queries[offset + 3],
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const duration = performance.now() - t0;
|
|
97
|
+
|
|
98
|
+
const duration_seconds = duration * 1e-3;
|
|
99
|
+
|
|
100
|
+
console.log(`Duration ${duration_seconds}s, ${(QUERY_COUNT / duration_seconds).toFixed(2)} cycles per second`);
|
|
101
|
+
|
|
102
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes squared shortest distance between a line segment(defined by 2 points) and a point
|
|
3
|
+
* @param {number} x0
|
|
4
|
+
* @param {number} y0
|
|
5
|
+
* @param {number} x1
|
|
6
|
+
* @param {number} y1
|
|
7
|
+
* @param {number} px
|
|
8
|
+
* @param {number} py
|
|
9
|
+
*/
|
|
10
|
+
export function line2_distance_to_point_sqr(x0: number, y0: number, x1: number, y1: number, px: number, py: number): number;
|
|
11
|
+
//# sourceMappingURL=line2_distance_to_point_sqr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line2_distance_to_point_sqr.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/2d/line/line2_distance_to_point_sqr.js"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,gDAPW,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,UA4BhB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { clamp01 } from "../../../math/clamp01.js";
|
|
2
|
+
import { v2_distance_sqr } from "../../vec2/v2_distance_sqr.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Computes squared shortest distance between a line segment(defined by 2 points) and a point
|
|
6
|
+
* @param {number} x0
|
|
7
|
+
* @param {number} y0
|
|
8
|
+
* @param {number} x1
|
|
9
|
+
* @param {number} y1
|
|
10
|
+
* @param {number} px
|
|
11
|
+
* @param {number} py
|
|
12
|
+
*/
|
|
13
|
+
export function line2_distance_to_point_sqr(
|
|
14
|
+
x0, y0,
|
|
15
|
+
x1, y1,
|
|
16
|
+
px, py
|
|
17
|
+
) {
|
|
18
|
+
// get line delta
|
|
19
|
+
const line_delta_x = x1 - x0;
|
|
20
|
+
const line_delta_y = y1 - y0;
|
|
21
|
+
|
|
22
|
+
// find closest point
|
|
23
|
+
const sp0_x = px - x0;
|
|
24
|
+
const sp0_y = py - y0;
|
|
25
|
+
|
|
26
|
+
//
|
|
27
|
+
const d2 = line_delta_x * line_delta_x + line_delta_y * line_delta_y;
|
|
28
|
+
|
|
29
|
+
const d3 = line_delta_x * sp0_x + line_delta_y * sp0_y;
|
|
30
|
+
|
|
31
|
+
const t = clamp01(d3 / d2);
|
|
32
|
+
|
|
33
|
+
// compute point on the line
|
|
34
|
+
const lp_x = line_delta_x * t + x0;
|
|
35
|
+
const lp_y = line_delta_y * t + y0;
|
|
36
|
+
|
|
37
|
+
// compute distance from the point in question to the point on the line
|
|
38
|
+
return v2_distance_sqr(px, py, lp_x, lp_y);
|
|
39
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { jest } from "@jest/globals";
|
|
2
|
+
import { randomFloatBetween } from "../../../math/random/randomFloatBetween.js";
|
|
3
|
+
import { seededRandom } from "../../../math/random/seededRandom.js";
|
|
2
4
|
import { QuadTreeDatum } from "./QuadTreeDatum.js";
|
|
3
5
|
import { QuadTreeNode } from "./QuadTreeNode.js";
|
|
4
6
|
|
|
@@ -180,3 +182,54 @@ test('test traverseRectangleIntersections', () => {
|
|
|
180
182
|
expect(visitor0).toHaveBeenCalledWith(d, 0, 0, 3, 3);
|
|
181
183
|
expect(visitor0).toHaveBeenCalledWith(e, 0, 0, 3, 3);
|
|
182
184
|
});
|
|
185
|
+
|
|
186
|
+
test.skip("performance, insertion 1m random", () => {
|
|
187
|
+
const tree = new QuadTreeNode(0, 0, 100, 100);
|
|
188
|
+
|
|
189
|
+
const random = seededRandom(42);
|
|
190
|
+
|
|
191
|
+
const N = 1000000;
|
|
192
|
+
|
|
193
|
+
const boxes = new Float32Array(N * 4);
|
|
194
|
+
|
|
195
|
+
for (let i = 0; i < N; i++) {
|
|
196
|
+
|
|
197
|
+
const position_x = randomFloatBetween(random, 0, 98);
|
|
198
|
+
const position_y = randomFloatBetween(random, 0, 98);
|
|
199
|
+
|
|
200
|
+
const size_x = randomFloatBetween(random, 0.1, 2);
|
|
201
|
+
const size_y = randomFloatBetween(random, 0.1, 2);
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
const i4 = i * 4;
|
|
205
|
+
boxes[i4] = position_x;
|
|
206
|
+
boxes[i4 + 1] = position_y;
|
|
207
|
+
boxes[i4 + 2] = position_x + size_x;
|
|
208
|
+
boxes[i4 + 3] = position_y + size_y;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// perform insertion
|
|
212
|
+
const t0 = performance.now();
|
|
213
|
+
|
|
214
|
+
for (let i = 0; i < N; i++) {
|
|
215
|
+
const i4 = i * 4;
|
|
216
|
+
|
|
217
|
+
const x0 = boxes[i4];
|
|
218
|
+
const y0 = boxes[i4 + 1];
|
|
219
|
+
const x1 = boxes[i4 + 2];
|
|
220
|
+
const y1 = boxes[i4 + 3];
|
|
221
|
+
|
|
222
|
+
tree.add(i,
|
|
223
|
+
x0,
|
|
224
|
+
y0,
|
|
225
|
+
x1,
|
|
226
|
+
y1
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const duration = performance.now() - t0;
|
|
231
|
+
|
|
232
|
+
const duration_seconds = duration * 1e-3;
|
|
233
|
+
|
|
234
|
+
console.log(`Duration ${duration_seconds}s, ${(N / duration_seconds).toFixed(2)} records per second`);
|
|
235
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qt_match_data_by_circle.spec.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/2d/quad-tree/qt_match_data_by_circle.spec.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { returnTrue } from "../../../function/returnTrue.js";
|
|
2
|
+
import { randomFloatBetween } from "../../../math/random/randomFloatBetween.js";
|
|
3
|
+
import { seededRandom } from "../../../math/random/seededRandom.js";
|
|
4
|
+
import { qt_match_data_by_circle } from "./qt_match_data_by_circle.js";
|
|
5
|
+
import { QuadTreeNode } from "./QuadTreeNode.js";
|
|
6
|
+
|
|
7
|
+
test.skip("performance, 10k objects, 1m queries", () => {
|
|
8
|
+
const OBJECT_COUNT = 30000;
|
|
9
|
+
const QUERY_COUNT = 1e6;
|
|
10
|
+
|
|
11
|
+
const QUERY_DISTANCE_MIN = 0.1;
|
|
12
|
+
const QUERY_DISTANCE_MAX = 0.2;
|
|
13
|
+
|
|
14
|
+
const grid_bounds_x1 = 256;
|
|
15
|
+
const grid_bounds_y1 = 256;
|
|
16
|
+
|
|
17
|
+
const tree = new QuadTreeNode(0, 0, grid_bounds_x1, grid_bounds_y1);
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const random = seededRandom();
|
|
21
|
+
|
|
22
|
+
// fill
|
|
23
|
+
for (let i = 0; i < OBJECT_COUNT; i++) {
|
|
24
|
+
|
|
25
|
+
const width = randomFloatBetween(random, 0.2, 1);
|
|
26
|
+
const height = randomFloatBetween(random, 0.2, 1);
|
|
27
|
+
const x0 = randomFloatBetween(random, 0, grid_bounds_x1 - width);
|
|
28
|
+
const y0 = randomFloatBetween(random, 0, grid_bounds_y1 - height);
|
|
29
|
+
|
|
30
|
+
tree.add(i,
|
|
31
|
+
x0,
|
|
32
|
+
y0,
|
|
33
|
+
x0 + width,
|
|
34
|
+
y0 + height
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
const queries = new Float32Array(QUERY_COUNT * 3);
|
|
41
|
+
|
|
42
|
+
// build queries
|
|
43
|
+
for (let i = 0; i < QUERY_COUNT; i++) {
|
|
44
|
+
|
|
45
|
+
const offset = i * 3;
|
|
46
|
+
|
|
47
|
+
// pick radius
|
|
48
|
+
const radius = randomFloatBetween(random, QUERY_DISTANCE_MIN, QUERY_DISTANCE_MAX);
|
|
49
|
+
|
|
50
|
+
// pick starting point
|
|
51
|
+
const ax = randomFloatBetween(random, radius, grid_bounds_x1 - radius);
|
|
52
|
+
const ay = randomFloatBetween(random, radius, grid_bounds_y1 - radius);
|
|
53
|
+
|
|
54
|
+
queries[offset] = ax;
|
|
55
|
+
queries[offset + 1] = ay;
|
|
56
|
+
|
|
57
|
+
queries[offset + 2] = radius;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// execute
|
|
61
|
+
const t0 = performance.now();
|
|
62
|
+
|
|
63
|
+
const result = [];
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < QUERY_COUNT; i++) {
|
|
66
|
+
|
|
67
|
+
const offset = i * 3;
|
|
68
|
+
|
|
69
|
+
qt_match_data_by_circle(
|
|
70
|
+
result,
|
|
71
|
+
0,
|
|
72
|
+
tree,
|
|
73
|
+
queries[offset],
|
|
74
|
+
queries[offset + 1],
|
|
75
|
+
queries[offset + 2],
|
|
76
|
+
returnTrue
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const duration = performance.now() - t0;
|
|
81
|
+
|
|
82
|
+
const duration_seconds = duration * 1e-3;
|
|
83
|
+
|
|
84
|
+
console.log(`Duration ${duration_seconds}s, ${(QUERY_COUNT / duration_seconds).toFixed(2)} cycles per second`);
|
|
85
|
+
|
|
86
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObservedString.d.ts","sourceRoot":"","sources":["../../../../src/core/model/ObservedString.js"],"names":[],"mappings":";AASA;IACI;;;;OAIG;IACH,
|
|
1
|
+
{"version":3,"file":"ObservedString.d.ts","sourceRoot":"","sources":["../../../../src/core/model/ObservedString.js"],"names":[],"mappings":";AASA;IACI;;;;OAIG;IACH,oBAHW,MAAM,EAgBhB;IARG;;;;OAIG;IACH,gBAAoB;IAEpB,0DAA6B;IAmBjC;;;;OAIG;IACH,oBAFa,cAAc,CAa1B;IAED;;;OAGG;IACH,YAFW,cAAc,QAIxB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACZ,OAAO,CAInB;IAED;;;OAGG;IACH,mBAEC;IAED;;;OAGG;IACH,2BAIC;IAED,iBAEC;IAED,yBAEC;IAED;;;OAGG;IACH,2CAEC;IAED;;;OAGG;IACH,6CAIC;IAED,eAEC;IAGL;;;;OAIG;IACH,2BAFU,OAAO,CAEwB;CAPxC;mBA1HkB,4BAA4B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Name from "
|
|
1
|
+
import Name from "../../ecs/name/Name.js";
|
|
2
2
|
import { AnimatedValueBinding } from "../../graphics/ecs/mesh-v2/aggregate/animation/AnimatedValueBinding.js";
|
|
3
3
|
import { BoundQuaternionWriter } from "../../graphics/ecs/mesh-v2/aggregate/animation/BoundQuaternionWriter.js";
|
|
4
4
|
import { BoundValueWriter } from "../../graphics/ecs/mesh-v2/aggregate/animation/BoundValueWriter.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export default Name;
|
|
2
|
+
declare class Name extends ObservedString {
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {string} [value]
|
|
6
|
+
*/
|
|
7
|
+
constructor(value?: string);
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
12
|
+
getLocalizationKey(): string;
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @param {Localization} localization
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
getLocalizedValue(localization: Localization): string;
|
|
19
|
+
clone(): Name;
|
|
20
|
+
}
|
|
21
|
+
declare namespace Name {
|
|
22
|
+
let typeName: string;
|
|
23
|
+
}
|
|
24
|
+
import ObservedString from "../../../core/model/ObservedString.js";
|
|
25
|
+
//# sourceMappingURL=Name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Name.d.ts","sourceRoot":"","sources":["../../../../../src/engine/ecs/name/Name.js"],"names":[],"mappings":";AAEA;IACI;;;OAGG;IACH,oBAFW,MAAM,EAIhB;IAED;;;OAGG;IACH,sBAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,+CAFa,MAAM,CAIlB;IAED,cAMC;CACJ;;;;2BAnC0B,uCAAuC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import ObservedString from "../../../core/model/ObservedString.js";
|
|
2
|
+
|
|
3
|
+
class Name extends ObservedString {
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {string} [value]
|
|
7
|
+
*/
|
|
8
|
+
constructor(value = "") {
|
|
9
|
+
super(value);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
16
|
+
getLocalizationKey() {
|
|
17
|
+
return `component.name.${this.getValue()}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @param {Localization} localization
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
getLocalizedValue(localization) {
|
|
26
|
+
return localization.getString(this.getLocalizationKey());
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
clone() {
|
|
30
|
+
const clone = new Name();
|
|
31
|
+
|
|
32
|
+
clone.copy(this);
|
|
33
|
+
|
|
34
|
+
return clone;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Name.typeName = "Name";
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
export default Name;
|
|
42
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class NameSerializationAdapter extends BinaryClassSerializationAdapter {
|
|
2
|
+
klass: typeof Name;
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {BinaryBuffer} buffer
|
|
6
|
+
* @param {Name} value
|
|
7
|
+
*/
|
|
8
|
+
serialize(buffer: BinaryBuffer, value: Name): void;
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param {BinaryBuffer} buffer
|
|
12
|
+
* @param {Name} value
|
|
13
|
+
*/
|
|
14
|
+
deserialize(buffer: BinaryBuffer, value: Name): void;
|
|
15
|
+
}
|
|
16
|
+
import { BinaryClassSerializationAdapter } from "../storage/binary/BinaryClassSerializationAdapter.js";
|
|
17
|
+
import Name from "./Name.js";
|
|
18
|
+
//# sourceMappingURL=NameSerializationAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NameSerializationAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/engine/ecs/name/NameSerializationAdapter.js"],"names":[],"mappings":"AAGA;IACI,mBAAa;IAGb;;;;OAIG;IACH,uCAFW,IAAI,QAId;IAGD;;;;OAIG;IACH,yCAFW,IAAI,QAMd;CAEJ;gDA5B+C,sDAAsD;iBACrF,WAAW"}
|