com.wallstop-studios.unity-helpers 2.0.0-rc76.1 → 2.0.0-rc76.4
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/Editor/Sprites/SpriteCropper.cs +9 -2
- package/Editor/Sprites/SpritePivotAdjustor.cs +259 -0
- package/Editor/Sprites/SpritePivotAdjustor.cs.meta +3 -0
- package/Runtime/Core/DataStructure/Circle.cs +1 -1
- package/Runtime/Core/DataStructure/CyclicBuffer.cs +65 -2
- package/Runtime/Core/DataStructure/ISpatialTree.cs +7 -46
- package/Runtime/Core/DataStructure/KDTree.cs +266 -130
- package/Runtime/Core/DataStructure/QuadTree.cs +258 -128
- package/Runtime/Core/DataStructure/Trie.cs +359 -0
- package/Runtime/Core/DataStructure/Trie.cs.meta +3 -0
- package/Runtime/Core/Extension/EnumExtensions.cs +4 -4
- package/Runtime/Core/Helper/UnityMainThreadDispatcher.cs +3 -1
- package/Runtime/Core/Threading/SingleThreadedThreadPool.cs +7 -2
- package/Runtime/UI/LayeredImage.cs +0 -1
- package/Tests/Runtime/DataStructures/SpatialTreeTests.cs +6 -6
- package/Tests/Runtime/Performance/QuadTreePerformanceTests.cs +1 -1
- package/Tests/Runtime/Performance/SpatialTreePerformanceTest.cs +23 -18
- package/package.json +4 -1
- package/Editor/UI.meta +0 -3
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
using System;
|
|
4
4
|
using System.Collections.Generic;
|
|
5
5
|
using System.Collections.Immutable;
|
|
6
|
-
using System.Linq;
|
|
7
6
|
using Extension;
|
|
8
7
|
using UnityEngine;
|
|
9
8
|
using Utils;
|
|
@@ -11,27 +10,48 @@
|
|
|
11
10
|
[Serializable]
|
|
12
11
|
public sealed class KDTree<T> : ISpatialTree<T>
|
|
13
12
|
{
|
|
14
|
-
|
|
13
|
+
[Serializable]
|
|
14
|
+
public readonly struct Entry
|
|
15
|
+
{
|
|
16
|
+
public readonly T value;
|
|
17
|
+
public readonly Vector2 position;
|
|
18
|
+
|
|
19
|
+
public Entry(T value, Vector2 position)
|
|
20
|
+
{
|
|
21
|
+
this.value = value;
|
|
22
|
+
this.position = position;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
15
25
|
|
|
16
26
|
[Serializable]
|
|
17
|
-
public sealed class KDTreeNode
|
|
27
|
+
public sealed class KDTreeNode
|
|
18
28
|
{
|
|
19
29
|
public readonly Bounds boundary;
|
|
20
|
-
public readonly KDTreeNode
|
|
21
|
-
public readonly KDTreeNode
|
|
22
|
-
public readonly
|
|
30
|
+
public readonly KDTreeNode left;
|
|
31
|
+
public readonly KDTreeNode right;
|
|
32
|
+
public readonly Entry[] entries;
|
|
23
33
|
public readonly bool isTerminal;
|
|
24
34
|
|
|
25
|
-
public KDTreeNode(
|
|
26
|
-
List<V> elements,
|
|
27
|
-
Func<V, Vector2> elementTransformer,
|
|
28
|
-
int bucketSize,
|
|
29
|
-
bool isXAxis,
|
|
30
|
-
bool balanced
|
|
31
|
-
)
|
|
35
|
+
public KDTreeNode(List<Entry> elements, int bucketSize, bool isXAxis, bool balanced)
|
|
32
36
|
{
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
bool initializedBoundary = false;
|
|
38
|
+
Bounds bounds = new();
|
|
39
|
+
foreach (Entry element in elements)
|
|
40
|
+
{
|
|
41
|
+
if (initializedBoundary)
|
|
42
|
+
{
|
|
43
|
+
bounds.Encapsulate(element.position);
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
{
|
|
47
|
+
bounds = new Bounds(element.position, new Vector3(0f, 0f, 1f));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
initializedBoundary = true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
boundary = bounds;
|
|
54
|
+
this.entries = 0 < elements.Count ? elements.ToArray() : Array.Empty<Entry>();
|
|
35
55
|
isTerminal = elements.Count <= bucketSize;
|
|
36
56
|
if (isTerminal)
|
|
37
57
|
{
|
|
@@ -40,76 +60,79 @@
|
|
|
40
60
|
|
|
41
61
|
if (balanced)
|
|
42
62
|
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
63
|
+
if (isXAxis)
|
|
64
|
+
{
|
|
65
|
+
Array.Sort(
|
|
66
|
+
this.entries,
|
|
67
|
+
(lhs, rhs) => lhs.position.x.CompareTo(rhs.position.x)
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
else
|
|
48
71
|
{
|
|
49
|
-
|
|
72
|
+
Array.Sort(
|
|
73
|
+
this.entries,
|
|
74
|
+
(lhs, rhs) => lhs.position.y.CompareTo(rhs.position.y)
|
|
75
|
+
);
|
|
50
76
|
}
|
|
51
|
-
elements.Sort(Comparison);
|
|
52
77
|
|
|
53
78
|
int cutoff = elements.Count / 2;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
|
|
80
|
+
List<Entry> leftList = new();
|
|
81
|
+
List<Entry> rightList = new();
|
|
82
|
+
for (int i = 0; i < this.entries.Length; ++i)
|
|
83
|
+
{
|
|
84
|
+
Entry element = this.entries[i];
|
|
85
|
+
if (i < cutoff)
|
|
86
|
+
{
|
|
87
|
+
leftList.Add(element);
|
|
88
|
+
}
|
|
89
|
+
else
|
|
90
|
+
{
|
|
91
|
+
rightList.Add(element);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
left = new KDTreeNode(leftList, bucketSize, !isXAxis, true);
|
|
96
|
+
right = new KDTreeNode(rightList, bucketSize, !isXAxis, true);
|
|
68
97
|
}
|
|
69
98
|
else
|
|
70
99
|
{
|
|
71
100
|
Vector2 cutoff = boundary.center;
|
|
72
101
|
if (isXAxis)
|
|
73
102
|
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
false,
|
|
90
|
-
false
|
|
91
|
-
);
|
|
103
|
+
List<Entry> leftList = new();
|
|
104
|
+
List<Entry> rightList = new();
|
|
105
|
+
foreach (Entry element in this.entries)
|
|
106
|
+
{
|
|
107
|
+
if (element.position.x <= cutoff.x)
|
|
108
|
+
{
|
|
109
|
+
leftList.Add(element);
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
{
|
|
113
|
+
rightList.Add(element);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
left = new KDTreeNode(leftList, bucketSize, false, false);
|
|
117
|
+
right = new KDTreeNode(rightList, bucketSize, false, false);
|
|
92
118
|
}
|
|
93
119
|
else
|
|
94
120
|
{
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
true,
|
|
111
|
-
false
|
|
112
|
-
);
|
|
121
|
+
List<Entry> leftList = new();
|
|
122
|
+
List<Entry> rightList = new();
|
|
123
|
+
foreach (Entry element in this.entries)
|
|
124
|
+
{
|
|
125
|
+
if (element.position.y <= cutoff.y)
|
|
126
|
+
{
|
|
127
|
+
leftList.Add(element);
|
|
128
|
+
}
|
|
129
|
+
else
|
|
130
|
+
{
|
|
131
|
+
rightList.Add(element);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
left = new KDTreeNode(leftList, bucketSize, true, false);
|
|
135
|
+
right = new KDTreeNode(rightList, bucketSize, true, false);
|
|
113
136
|
}
|
|
114
137
|
}
|
|
115
138
|
}
|
|
@@ -119,11 +142,9 @@
|
|
|
119
142
|
|
|
120
143
|
public readonly ImmutableArray<T> elements;
|
|
121
144
|
public Bounds Boundary => _bounds;
|
|
122
|
-
public Func<T, Vector2> ElementTransformer => _elementTransformer;
|
|
123
145
|
|
|
124
146
|
private readonly Bounds _bounds;
|
|
125
|
-
private readonly
|
|
126
|
-
private readonly KDTreeNode<T> _head;
|
|
147
|
+
private readonly KDTreeNode _head;
|
|
127
148
|
|
|
128
149
|
public KDTree(
|
|
129
150
|
IEnumerable<T> points,
|
|
@@ -132,74 +153,178 @@
|
|
|
132
153
|
bool balanced = true
|
|
133
154
|
)
|
|
134
155
|
{
|
|
135
|
-
|
|
136
|
-
|
|
156
|
+
if (elementTransformer is null)
|
|
157
|
+
{
|
|
158
|
+
throw new ArgumentNullException(nameof(elementTransformer));
|
|
159
|
+
}
|
|
137
160
|
elements =
|
|
138
161
|
points?.ToImmutableArray() ?? throw new ArgumentNullException(nameof(points));
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
162
|
+
Bounds bounds = new();
|
|
163
|
+
bool boundsInitialized = false;
|
|
164
|
+
List<Entry> entries = new();
|
|
165
|
+
foreach (T element in elements)
|
|
166
|
+
{
|
|
167
|
+
Vector2 elementPosition = elementTransformer(element);
|
|
168
|
+
if (boundsInitialized)
|
|
169
|
+
{
|
|
170
|
+
bounds.Encapsulate(elementPosition);
|
|
171
|
+
}
|
|
172
|
+
else
|
|
173
|
+
{
|
|
174
|
+
bounds = new Bounds(elementPosition, new Vector3(0f, 0f, 1f));
|
|
175
|
+
}
|
|
176
|
+
boundsInitialized = true;
|
|
177
|
+
entries.Add(new Entry(element, elementPosition));
|
|
178
|
+
}
|
|
179
|
+
_bounds = bounds;
|
|
180
|
+
_head = new KDTreeNode(
|
|
181
|
+
entries,
|
|
143
182
|
bucketSize: bucketSize,
|
|
144
183
|
isXAxis: true,
|
|
145
184
|
balanced: balanced
|
|
146
185
|
);
|
|
147
186
|
}
|
|
148
187
|
|
|
149
|
-
public
|
|
188
|
+
public List<T> GetElementsInRange(
|
|
189
|
+
Vector2 position,
|
|
190
|
+
float range,
|
|
191
|
+
List<T> elementsInRange,
|
|
192
|
+
float minimumRange = 0
|
|
193
|
+
)
|
|
150
194
|
{
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
195
|
+
elementsInRange.Clear();
|
|
196
|
+
Bounds bounds = new(position, new Vector3(range * 2, range * 2, 1f));
|
|
154
197
|
|
|
155
|
-
public IEnumerable<T> GetElementsInBounds(Bounds bounds, Stack<KDTreeNode<T>> nodeBuffer)
|
|
156
|
-
{
|
|
157
198
|
if (!bounds.FastIntersects2D(_bounds))
|
|
158
199
|
{
|
|
159
|
-
|
|
200
|
+
return elementsInRange;
|
|
160
201
|
}
|
|
161
202
|
|
|
162
|
-
Stack<KDTreeNode
|
|
203
|
+
Stack<KDTreeNode> nodesToVisit = Buffers<KDTreeNode>.Stack;
|
|
163
204
|
nodesToVisit.Clear();
|
|
164
205
|
nodesToVisit.Push(_head);
|
|
165
206
|
|
|
166
|
-
|
|
207
|
+
List<KDTreeNode> resultBuffer = Buffers<KDTreeNode>.List;
|
|
208
|
+
resultBuffer.Clear();
|
|
209
|
+
|
|
210
|
+
while (nodesToVisit.TryPop(out KDTreeNode currentNode))
|
|
167
211
|
{
|
|
168
|
-
if (currentNode.isTerminal)
|
|
212
|
+
if (currentNode.isTerminal || bounds.Overlaps2D(currentNode.boundary))
|
|
169
213
|
{
|
|
170
|
-
|
|
214
|
+
resultBuffer.Add(currentNode);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
KDTreeNode leftNode = currentNode.left;
|
|
219
|
+
if (0 < leftNode.entries.Length && bounds.FastIntersects2D(leftNode.boundary))
|
|
220
|
+
{
|
|
221
|
+
nodesToVisit.Push(leftNode);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
KDTreeNode rightNode = currentNode.right;
|
|
225
|
+
if (0 < rightNode.entries.Length && bounds.FastIntersects2D(rightNode.boundary))
|
|
226
|
+
{
|
|
227
|
+
nodesToVisit.Push(rightNode);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (0 < minimumRange)
|
|
232
|
+
{
|
|
233
|
+
float minimumRangeSquared = minimumRange * minimumRange;
|
|
234
|
+
float rangeSquared = range * range;
|
|
235
|
+
foreach (KDTreeNode node in resultBuffer)
|
|
236
|
+
{
|
|
237
|
+
foreach (Entry element in node.entries)
|
|
171
238
|
{
|
|
172
|
-
|
|
239
|
+
float squareDistance = (element.position - position).sqrMagnitude;
|
|
240
|
+
if (squareDistance <= minimumRangeSquared || rangeSquared < squareDistance)
|
|
173
241
|
{
|
|
174
|
-
|
|
242
|
+
continue;
|
|
175
243
|
}
|
|
244
|
+
|
|
245
|
+
elementsInRange.Add(element.value);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else
|
|
250
|
+
{
|
|
251
|
+
float rangeSquared = range * range;
|
|
252
|
+
foreach (KDTreeNode node in resultBuffer)
|
|
253
|
+
{
|
|
254
|
+
foreach (Entry element in node.entries)
|
|
255
|
+
{
|
|
256
|
+
if ((element.position - position).sqrMagnitude <= rangeSquared)
|
|
257
|
+
{
|
|
258
|
+
elementsInRange.Add(element.value);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return elementsInRange;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
public List<T> GetElementsInBounds(Bounds bounds, List<T> elementsInBounds)
|
|
268
|
+
{
|
|
269
|
+
Stack<KDTreeNode> buffer = Buffers<KDTreeNode>.Stack;
|
|
270
|
+
return GetElementsInBounds(bounds, elementsInBounds, buffer);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
public List<T> GetElementsInBounds(
|
|
274
|
+
Bounds bounds,
|
|
275
|
+
List<T> elementsInBounds,
|
|
276
|
+
Stack<KDTreeNode> nodeBuffer
|
|
277
|
+
)
|
|
278
|
+
{
|
|
279
|
+
elementsInBounds.Clear();
|
|
280
|
+
if (!bounds.FastIntersects2D(_bounds))
|
|
281
|
+
{
|
|
282
|
+
return elementsInBounds;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
Stack<KDTreeNode> nodesToVisit = nodeBuffer ?? new Stack<KDTreeNode>();
|
|
286
|
+
nodesToVisit.Clear();
|
|
287
|
+
nodesToVisit.Push(_head);
|
|
288
|
+
|
|
289
|
+
while (nodesToVisit.TryPop(out KDTreeNode currentNode))
|
|
290
|
+
{
|
|
291
|
+
if (bounds.Overlaps2D(currentNode.boundary))
|
|
292
|
+
{
|
|
293
|
+
foreach (Entry element in currentNode.entries)
|
|
294
|
+
{
|
|
295
|
+
elementsInBounds.Add(element.value);
|
|
176
296
|
}
|
|
177
297
|
|
|
178
298
|
continue;
|
|
179
299
|
}
|
|
180
300
|
|
|
181
|
-
if (
|
|
301
|
+
if (currentNode.isTerminal)
|
|
182
302
|
{
|
|
183
|
-
foreach (
|
|
303
|
+
foreach (Entry element in currentNode.entries)
|
|
184
304
|
{
|
|
185
|
-
|
|
305
|
+
if (bounds.FastContains2D(element.position))
|
|
306
|
+
{
|
|
307
|
+
elementsInBounds.Add(element.value);
|
|
308
|
+
}
|
|
186
309
|
}
|
|
187
310
|
|
|
188
311
|
continue;
|
|
189
312
|
}
|
|
190
313
|
|
|
191
|
-
KDTreeNode
|
|
192
|
-
if (0 < leftNode.
|
|
314
|
+
KDTreeNode leftNode = currentNode.left;
|
|
315
|
+
if (0 < leftNode.entries.Length && bounds.FastIntersects2D(leftNode.boundary))
|
|
193
316
|
{
|
|
194
317
|
nodesToVisit.Push(leftNode);
|
|
195
318
|
}
|
|
196
319
|
|
|
197
|
-
KDTreeNode
|
|
198
|
-
if (0 < rightNode.
|
|
320
|
+
KDTreeNode rightNode = currentNode.right;
|
|
321
|
+
if (0 < rightNode.entries.Length && bounds.FastIntersects2D(rightNode.boundary))
|
|
199
322
|
{
|
|
200
323
|
nodesToVisit.Push(rightNode);
|
|
201
324
|
}
|
|
202
325
|
}
|
|
326
|
+
|
|
327
|
+
return elementsInBounds;
|
|
203
328
|
}
|
|
204
329
|
|
|
205
330
|
public void GetApproximateNearestNeighbors(
|
|
@@ -208,14 +333,16 @@
|
|
|
208
333
|
List<T> nearestNeighbors
|
|
209
334
|
)
|
|
210
335
|
{
|
|
211
|
-
Stack<KDTreeNode
|
|
336
|
+
Stack<KDTreeNode> nodeBuffer = Buffers<KDTreeNode>.Stack;
|
|
212
337
|
HashSet<T> nearestNeighborBuffer = Buffers<T>.HashSet;
|
|
338
|
+
List<Entry> nearestNeighborsCache = Buffers<Entry>.List;
|
|
213
339
|
GetApproximateNearestNeighbors(
|
|
214
340
|
position,
|
|
215
341
|
count,
|
|
216
342
|
nearestNeighbors,
|
|
217
343
|
nodeBuffer,
|
|
218
|
-
nearestNeighborBuffer
|
|
344
|
+
nearestNeighborBuffer,
|
|
345
|
+
nearestNeighborsCache
|
|
219
346
|
);
|
|
220
347
|
}
|
|
221
348
|
|
|
@@ -224,69 +351,78 @@
|
|
|
224
351
|
Vector2 position,
|
|
225
352
|
int count,
|
|
226
353
|
List<T> nearestNeighbors,
|
|
227
|
-
Stack<KDTreeNode
|
|
228
|
-
HashSet<T> nearestNeighborBuffer
|
|
354
|
+
Stack<KDTreeNode> nodeBuffer,
|
|
355
|
+
HashSet<T> nearestNeighborBuffer,
|
|
356
|
+
List<Entry> nearestNeighborsCache
|
|
229
357
|
)
|
|
230
358
|
{
|
|
231
359
|
nearestNeighbors.Clear();
|
|
232
360
|
|
|
233
|
-
KDTreeNode
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
361
|
+
KDTreeNode current = _head;
|
|
362
|
+
nodeBuffer ??= new Stack<KDTreeNode>();
|
|
363
|
+
nodeBuffer.Clear();
|
|
364
|
+
nodeBuffer.Push(_head);
|
|
365
|
+
nearestNeighborBuffer ??= new HashSet<T>(count);
|
|
366
|
+
nearestNeighborBuffer.Clear();
|
|
367
|
+
nearestNeighborsCache ??= new List<Entry>(count);
|
|
368
|
+
nearestNeighborsCache.Clear();
|
|
239
369
|
|
|
240
370
|
while (!current.isTerminal)
|
|
241
371
|
{
|
|
242
|
-
KDTreeNode
|
|
243
|
-
KDTreeNode
|
|
372
|
+
KDTreeNode left = current.left;
|
|
373
|
+
KDTreeNode right = current.right;
|
|
244
374
|
if (
|
|
245
375
|
((Vector2)left.boundary.center - position).sqrMagnitude
|
|
246
376
|
< ((Vector2)right.boundary.center - position).sqrMagnitude
|
|
247
377
|
)
|
|
248
378
|
{
|
|
249
|
-
|
|
379
|
+
nodeBuffer.Push(left);
|
|
250
380
|
current = left;
|
|
251
|
-
if (left.
|
|
381
|
+
if (left.entries.Length <= count)
|
|
252
382
|
{
|
|
253
383
|
break;
|
|
254
384
|
}
|
|
255
385
|
}
|
|
256
386
|
else
|
|
257
387
|
{
|
|
258
|
-
|
|
388
|
+
nodeBuffer.Push(right);
|
|
259
389
|
current = right;
|
|
260
|
-
if (right.
|
|
390
|
+
if (right.entries.Length <= count)
|
|
261
391
|
{
|
|
262
392
|
break;
|
|
263
393
|
}
|
|
264
394
|
}
|
|
265
395
|
}
|
|
266
396
|
|
|
267
|
-
while (
|
|
397
|
+
while (
|
|
398
|
+
nearestNeighborBuffer.Count < count && nodeBuffer.TryPop(out KDTreeNode selected)
|
|
399
|
+
)
|
|
268
400
|
{
|
|
269
|
-
foreach (
|
|
401
|
+
foreach (Entry element in selected.entries)
|
|
270
402
|
{
|
|
271
|
-
|
|
403
|
+
if (nearestNeighborBuffer.Add(element.value))
|
|
404
|
+
{
|
|
405
|
+
nearestNeighborsCache.Add(element);
|
|
406
|
+
}
|
|
272
407
|
}
|
|
273
408
|
}
|
|
274
409
|
|
|
275
|
-
|
|
276
|
-
{
|
|
277
|
-
nearestNeighbors.Add(element);
|
|
278
|
-
}
|
|
279
|
-
if (count < nearestNeighbors.Count)
|
|
410
|
+
if (count < nearestNeighborsCache.Count)
|
|
280
411
|
{
|
|
281
412
|
Vector2 localPosition = position;
|
|
282
|
-
|
|
283
|
-
nearestNeighbors.RemoveRange(count, nearestNeighbors.Count - count);
|
|
413
|
+
nearestNeighborsCache.Sort(NearestComparison);
|
|
284
414
|
|
|
285
|
-
int NearestComparison(
|
|
286
|
-
(
|
|
287
|
-
(
|
|
415
|
+
int NearestComparison(Entry lhs, Entry rhs) =>
|
|
416
|
+
(lhs.position - localPosition).sqrMagnitude.CompareTo(
|
|
417
|
+
(rhs.position - localPosition).sqrMagnitude
|
|
288
418
|
);
|
|
289
419
|
}
|
|
420
|
+
|
|
421
|
+
nearestNeighbors.Clear();
|
|
422
|
+
for (int i = 0; i < nearestNeighborsCache.Count && i < count; ++i)
|
|
423
|
+
{
|
|
424
|
+
nearestNeighbors.Add(nearestNeighborsCache[i].value);
|
|
425
|
+
}
|
|
290
426
|
}
|
|
291
427
|
}
|
|
292
428
|
}
|