com.wallstop-studios.unity-helpers 2.0.0-rc05 → 2.0.0-rc07
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/Runtime/Core/DataStructure/TimedCache.cs +4 -3
- package/Runtime/Core/Extension/IListExtensions.cs +2 -2
- package/Runtime/Core/Extension/RandomExtensions.cs +23 -4
- package/Runtime/Core/Extension/UnityExtensions.cs +278 -90
- package/Runtime/Core/Helper/ArrayConverter.cs +39 -0
- package/Runtime/Core/Helper/ArrayConverter.cs.meta +3 -0
- package/Runtime/Core/Helper/Helpers.cs +133 -563
- package/Runtime/Core/Helper/Partials/LogHelpers.cs +13 -0
- package/Runtime/Core/Helper/Partials/LogHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/MathHelpers.cs +30 -0
- package/Runtime/Core/Helper/Partials/MathHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +388 -0
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/TransformHelpers.cs +167 -0
- package/Runtime/Core/Helper/Partials/TransformHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials.meta +3 -0
- package/Runtime/Core/Helper/WallMath.cs +85 -22
- package/Runtime/Core/Random/AbstractRandom.cs +208 -162
- package/Runtime/Core/Random/DotNetRandom.cs +3 -5
- package/Runtime/Core/Random/PRNG.cs +7 -0
- package/Runtime/Core/Random/PRNG.cs.meta +3 -0
- package/Runtime/Core/Random/PcgRandom.cs +4 -6
- package/Runtime/Core/Random/RandomState.cs +31 -3
- package/Runtime/Core/Random/SquirrelRandom.cs +12 -15
- package/Runtime/Core/Random/SystemRandom.cs +92 -46
- package/Runtime/Core/Random/ThreadLocalRandom.cs +2 -1
- package/Runtime/Core/Random/UnityRandom.cs +2 -4
- package/Runtime/Core/Random/WyRandom.cs +2 -4
- package/Runtime/Core/Random/XorShiftRandom.cs +3 -5
- package/Runtime/Core/Serialization/Serializer.cs +36 -14
- package/Runtime/Utils/CircleLineRenderer.cs +17 -5
- package/Tests/Runtime/DataStructures/SpatialTreeTests.cs +34 -10
- package/Tests/Runtime/Helper/ArrayConverterTests.cs +19 -0
- package/Tests/Runtime/Helper/ArrayConverterTests.cs.meta +3 -0
- package/Tests/Runtime/Helper/ObjectHelperTests.cs +402 -0
- package/Tests/Runtime/Helper/ObjectHelperTests.cs.meta +3 -0
- package/Tests/Runtime/Helper/WallMathTests.cs +221 -0
- package/Tests/Runtime/Helper/WallMathTests.cs.meta +3 -0
- package/Tests/Runtime/Helper.meta +3 -0
- package/Tests/Runtime/Performance/RandomPerformanceTests.cs +58 -3
- package/Tests/Runtime/Performance/SpatialTreePerformanceTest.cs +47 -34
- package/Tests/Runtime/Random/RandomTestBase.cs +284 -9
- package/Tests/Runtime/Random/SquirrelRandomTests.cs +5 -0
- package/Tests/Runtime/Serialization/JsonSerializationTest.cs +24 -11
- package/Tests/Runtime/Utils/SpriteRendererMetadataTests.cs +21 -17
- package/package.json +1 -1
|
@@ -43,7 +43,10 @@
|
|
|
43
43
|
{
|
|
44
44
|
float screenAspect = (float)Screen.width / Screen.height;
|
|
45
45
|
float cameraHeight = camera.orthographicSize * 2;
|
|
46
|
-
Bounds bounds = new(
|
|
46
|
+
Bounds bounds = new(
|
|
47
|
+
(Vector2)camera.transform.position,
|
|
48
|
+
new Vector3(cameraHeight * screenAspect, cameraHeight, 1)
|
|
49
|
+
);
|
|
47
50
|
return bounds;
|
|
48
51
|
}
|
|
49
52
|
|
|
@@ -109,7 +112,14 @@
|
|
|
109
112
|
{
|
|
110
113
|
return null;
|
|
111
114
|
}
|
|
112
|
-
return new BoundsInt(
|
|
115
|
+
return new BoundsInt(
|
|
116
|
+
xMin,
|
|
117
|
+
yMin,
|
|
118
|
+
zMin,
|
|
119
|
+
(xMax - xMin) + 1,
|
|
120
|
+
(yMax - yMin) + 1,
|
|
121
|
+
(zMax - zMin) + 1
|
|
122
|
+
);
|
|
113
123
|
}
|
|
114
124
|
|
|
115
125
|
public static BoundsInt? GetBounds(this IEnumerable<FastVector3Int> positions)
|
|
@@ -136,7 +146,14 @@
|
|
|
136
146
|
{
|
|
137
147
|
return null;
|
|
138
148
|
}
|
|
139
|
-
return new BoundsInt(
|
|
149
|
+
return new BoundsInt(
|
|
150
|
+
xMin,
|
|
151
|
+
yMin,
|
|
152
|
+
zMin,
|
|
153
|
+
(xMax - xMin) + 1,
|
|
154
|
+
(yMax - yMin) + 1,
|
|
155
|
+
(zMax - zMin) + 1
|
|
156
|
+
);
|
|
140
157
|
}
|
|
141
158
|
|
|
142
159
|
public static Bounds? GetBounds(this IEnumerable<Vector2> positions)
|
|
@@ -188,11 +205,19 @@
|
|
|
188
205
|
return null;
|
|
189
206
|
}
|
|
190
207
|
|
|
191
|
-
return new Bounds(
|
|
208
|
+
return new Bounds(
|
|
209
|
+
new Vector3(minX + (maxX - minX) / 2, minY + (maxY - minY) / 2),
|
|
210
|
+
new Vector3(maxX - minX, maxY - minY)
|
|
211
|
+
);
|
|
192
212
|
}
|
|
193
213
|
|
|
194
214
|
// https://www.habrador.com/tutorials/math/8-convex-hull/
|
|
195
|
-
public static List<Vector3Int> BuildConvexHull(
|
|
215
|
+
public static List<Vector3Int> BuildConvexHull(
|
|
216
|
+
this IEnumerable<Vector3Int> pointsSet,
|
|
217
|
+
Grid grid,
|
|
218
|
+
IRandom random = null,
|
|
219
|
+
bool includeColinearPoints = true
|
|
220
|
+
)
|
|
196
221
|
{
|
|
197
222
|
List<Vector3Int> points = pointsSet.ToList();
|
|
198
223
|
if (points.Count <= 3)
|
|
@@ -200,7 +225,7 @@
|
|
|
200
225
|
return points;
|
|
201
226
|
}
|
|
202
227
|
|
|
203
|
-
random ??=
|
|
228
|
+
random ??= PRNG.Instance;
|
|
204
229
|
|
|
205
230
|
Vector2 CellToWorld(Vector3Int position) => grid.CellToWorld(position);
|
|
206
231
|
|
|
@@ -211,7 +236,13 @@
|
|
|
211
236
|
Vector3Int testPoint = points[i];
|
|
212
237
|
Vector2 testPointWorldPosition = CellToWorld(testPoint);
|
|
213
238
|
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
|
214
|
-
if (
|
|
239
|
+
if (
|
|
240
|
+
testPointWorldPosition.x < startPointWorldPosition.x
|
|
241
|
+
|| (
|
|
242
|
+
Mathf.Approximately(testPointWorldPosition.x, startPointWorldPosition.x)
|
|
243
|
+
&& testPointWorldPosition.y < startPointWorldPosition.y
|
|
244
|
+
)
|
|
245
|
+
)
|
|
215
246
|
{
|
|
216
247
|
startPoint = testPoint;
|
|
217
248
|
startPointWorldPosition = testPointWorldPosition;
|
|
@@ -245,7 +276,11 @@
|
|
|
245
276
|
continue;
|
|
246
277
|
}
|
|
247
278
|
|
|
248
|
-
float relation = Geometry.IsAPointLeftOfVectorOrOnTheLine(
|
|
279
|
+
float relation = Geometry.IsAPointLeftOfVectorOrOnTheLine(
|
|
280
|
+
currentPointWorldPosition,
|
|
281
|
+
nextPointWorldPosition,
|
|
282
|
+
CellToWorld(point)
|
|
283
|
+
);
|
|
249
284
|
if (Mathf.Approximately(relation, 0))
|
|
250
285
|
{
|
|
251
286
|
colinearPoints.Add(point);
|
|
@@ -261,10 +296,12 @@
|
|
|
261
296
|
if (0 < colinearPoints.Count)
|
|
262
297
|
{
|
|
263
298
|
colinearPoints.Add(nextPoint);
|
|
264
|
-
colinearPoints.Sort(
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
299
|
+
colinearPoints.Sort(
|
|
300
|
+
(lhs, rhs) =>
|
|
301
|
+
(CellToWorld(lhs) - currentPointWorldPosition).sqrMagnitude.CompareTo(
|
|
302
|
+
(CellToWorld(rhs) - currentPointWorldPosition).sqrMagnitude
|
|
303
|
+
)
|
|
304
|
+
);
|
|
268
305
|
|
|
269
306
|
if (includeColinearPoints)
|
|
270
307
|
{
|
|
@@ -299,15 +336,20 @@
|
|
|
299
336
|
return convexHull;
|
|
300
337
|
}
|
|
301
338
|
|
|
302
|
-
public static List<FastVector3Int> BuildConvexHull(
|
|
339
|
+
public static List<FastVector3Int> BuildConvexHull(
|
|
340
|
+
this IEnumerable<FastVector3Int> pointsSet,
|
|
341
|
+
Grid grid,
|
|
342
|
+
IRandom random = null,
|
|
343
|
+
bool includeColinearPoints = false
|
|
344
|
+
)
|
|
303
345
|
{
|
|
304
346
|
List<FastVector3Int> points = pointsSet.ToList();
|
|
305
347
|
if (points.Count <= 3)
|
|
306
348
|
{
|
|
307
349
|
return points;
|
|
308
350
|
}
|
|
309
|
-
|
|
310
|
-
random ??=
|
|
351
|
+
|
|
352
|
+
random ??= PRNG.Instance;
|
|
311
353
|
|
|
312
354
|
Vector2 CellToWorld(FastVector3Int position) => grid.CellToWorld(position);
|
|
313
355
|
|
|
@@ -317,7 +359,13 @@
|
|
|
317
359
|
{
|
|
318
360
|
FastVector3Int testPoint = points[i];
|
|
319
361
|
Vector2 testPointWorldPosition = CellToWorld(testPoint);
|
|
320
|
-
if (
|
|
362
|
+
if (
|
|
363
|
+
testPointWorldPosition.x < startPointWorldPosition.x
|
|
364
|
+
|| (
|
|
365
|
+
Mathf.Approximately(testPointWorldPosition.x, startPointWorldPosition.x)
|
|
366
|
+
&& testPointWorldPosition.y < startPointWorldPosition.y
|
|
367
|
+
)
|
|
368
|
+
)
|
|
321
369
|
{
|
|
322
370
|
startPoint = testPoint;
|
|
323
371
|
startPointWorldPosition = testPointWorldPosition;
|
|
@@ -351,7 +399,11 @@
|
|
|
351
399
|
continue;
|
|
352
400
|
}
|
|
353
401
|
|
|
354
|
-
float relation = Geometry.IsAPointLeftOfVectorOrOnTheLine(
|
|
402
|
+
float relation = Geometry.IsAPointLeftOfVectorOrOnTheLine(
|
|
403
|
+
currentPointWorldPosition,
|
|
404
|
+
nextPointWorldPosition,
|
|
405
|
+
CellToWorld(point)
|
|
406
|
+
);
|
|
355
407
|
if (Mathf.Approximately(relation, 0))
|
|
356
408
|
{
|
|
357
409
|
colinearPoints.Add(point);
|
|
@@ -367,10 +419,12 @@
|
|
|
367
419
|
if (0 < colinearPoints.Count)
|
|
368
420
|
{
|
|
369
421
|
colinearPoints.Add(nextPoint);
|
|
370
|
-
colinearPoints.Sort(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
422
|
+
colinearPoints.Sort(
|
|
423
|
+
(lhs, rhs) =>
|
|
424
|
+
(CellToWorld(lhs) - currentPointWorldPosition).sqrMagnitude.CompareTo(
|
|
425
|
+
(CellToWorld(rhs) - currentPointWorldPosition).sqrMagnitude
|
|
426
|
+
)
|
|
427
|
+
);
|
|
374
428
|
|
|
375
429
|
if (includeColinearPoints)
|
|
376
430
|
{
|
|
@@ -405,8 +459,11 @@
|
|
|
405
459
|
return convexHull;
|
|
406
460
|
}
|
|
407
461
|
|
|
408
|
-
|
|
409
|
-
|
|
462
|
+
public static bool IsConvexHullInsideConvexHull(
|
|
463
|
+
this List<FastVector3Int> convexHull,
|
|
464
|
+
Grid grid,
|
|
465
|
+
List<FastVector3Int> maybeInside
|
|
466
|
+
)
|
|
410
467
|
{
|
|
411
468
|
foreach (FastVector3Int point in maybeInside)
|
|
412
469
|
{
|
|
@@ -419,13 +476,21 @@
|
|
|
419
476
|
return true;
|
|
420
477
|
}
|
|
421
478
|
|
|
422
|
-
public static bool IsPointInsideConvexHull(
|
|
479
|
+
public static bool IsPointInsideConvexHull(
|
|
480
|
+
this List<Vector3Int> convexHull,
|
|
481
|
+
Grid grid,
|
|
482
|
+
Vector3Int point
|
|
483
|
+
)
|
|
423
484
|
{
|
|
424
485
|
for (int i = 0; i < convexHull.Count; ++i)
|
|
425
486
|
{
|
|
426
487
|
Vector3Int lhs = convexHull[i];
|
|
427
488
|
Vector3Int rhs = convexHull[(i + 1) % convexHull.Count];
|
|
428
|
-
float relation = Geometry.IsAPointLeftOfVectorOrOnTheLine(
|
|
489
|
+
float relation = Geometry.IsAPointLeftOfVectorOrOnTheLine(
|
|
490
|
+
grid.CellToWorld(lhs),
|
|
491
|
+
grid.CellToWorld(rhs),
|
|
492
|
+
grid.CellToWorld(point)
|
|
493
|
+
);
|
|
429
494
|
if (relation < 0)
|
|
430
495
|
{
|
|
431
496
|
return false;
|
|
@@ -434,13 +499,21 @@
|
|
|
434
499
|
return true;
|
|
435
500
|
}
|
|
436
501
|
|
|
437
|
-
public static bool IsPointInsideConvexHull(
|
|
502
|
+
public static bool IsPointInsideConvexHull(
|
|
503
|
+
this List<FastVector3Int> convexHull,
|
|
504
|
+
Grid grid,
|
|
505
|
+
FastVector3Int point
|
|
506
|
+
)
|
|
438
507
|
{
|
|
439
508
|
for (int i = 0; i < convexHull.Count; ++i)
|
|
440
509
|
{
|
|
441
510
|
FastVector3Int lhs = convexHull[i];
|
|
442
511
|
FastVector3Int rhs = convexHull[(i + 1) % convexHull.Count];
|
|
443
|
-
float relation = Geometry.IsAPointLeftOfVectorOrOnTheLine(
|
|
512
|
+
float relation = Geometry.IsAPointLeftOfVectorOrOnTheLine(
|
|
513
|
+
grid.CellToWorld(lhs),
|
|
514
|
+
grid.CellToWorld(rhs),
|
|
515
|
+
grid.CellToWorld(point)
|
|
516
|
+
);
|
|
444
517
|
if (relation < 0)
|
|
445
518
|
{
|
|
446
519
|
return false;
|
|
@@ -449,7 +522,11 @@
|
|
|
449
522
|
return true;
|
|
450
523
|
}
|
|
451
524
|
|
|
452
|
-
public static bool IsConvexHullInsideConvexHull(
|
|
525
|
+
public static bool IsConvexHullInsideConvexHull(
|
|
526
|
+
this List<Vector3Int> convexHull,
|
|
527
|
+
Grid grid,
|
|
528
|
+
List<Vector3Int> maybeInside
|
|
529
|
+
)
|
|
453
530
|
{
|
|
454
531
|
foreach (Vector3Int point in maybeInside)
|
|
455
532
|
{
|
|
@@ -477,7 +554,7 @@
|
|
|
477
554
|
public HullEdge(FastVector3Int from, FastVector3Int to, Grid grid)
|
|
478
555
|
{
|
|
479
556
|
this.from = from;
|
|
480
|
-
this.to = to;
|
|
557
|
+
this.to = to;
|
|
481
558
|
_grid = grid;
|
|
482
559
|
fromWorld = grid.CellToWorld(from);
|
|
483
560
|
toWorld = grid.CellToWorld(to);
|
|
@@ -486,7 +563,12 @@
|
|
|
486
563
|
|
|
487
564
|
public bool Intersects(HullEdge other)
|
|
488
565
|
{
|
|
489
|
-
return UnityExtensions.Intersects(
|
|
566
|
+
return UnityExtensions.Intersects(
|
|
567
|
+
fromWorld,
|
|
568
|
+
toWorld,
|
|
569
|
+
other.fromWorld,
|
|
570
|
+
other.toWorld
|
|
571
|
+
);
|
|
490
572
|
}
|
|
491
573
|
|
|
492
574
|
public float LargestAngle(FastVector3Int point)
|
|
@@ -502,10 +584,7 @@
|
|
|
502
584
|
{
|
|
503
585
|
public static readonly ConcaveHullComparer Instance = new();
|
|
504
586
|
|
|
505
|
-
private ConcaveHullComparer()
|
|
506
|
-
{
|
|
507
|
-
|
|
508
|
-
}
|
|
587
|
+
private ConcaveHullComparer() { }
|
|
509
588
|
|
|
510
589
|
public int Compare(HullEdge lhs, HullEdge rhs)
|
|
511
590
|
{
|
|
@@ -525,7 +604,13 @@
|
|
|
525
604
|
}
|
|
526
605
|
}
|
|
527
606
|
|
|
528
|
-
public static List<FastVector3Int> BuildConcaveHull3(
|
|
607
|
+
public static List<FastVector3Int> BuildConcaveHull3(
|
|
608
|
+
this IReadOnlyCollection<FastVector3Int> gridPositions,
|
|
609
|
+
Grid grid,
|
|
610
|
+
IRandom random = null,
|
|
611
|
+
int bucketSize = 40,
|
|
612
|
+
float angleThreshold = 90f
|
|
613
|
+
)
|
|
529
614
|
{
|
|
530
615
|
List<FastVector3Int> convexHull = gridPositions.BuildConvexHull(grid, random);
|
|
531
616
|
List<HullEdge> concaveHullEdges = new();
|
|
@@ -538,7 +623,7 @@
|
|
|
538
623
|
HullEdge edge = new(lhs, rhs, grid);
|
|
539
624
|
_ = data.Add(edge);
|
|
540
625
|
}
|
|
541
|
-
|
|
626
|
+
|
|
542
627
|
HashSet<FastVector3Int> remainingPoints = gridPositions.ToHashSet();
|
|
543
628
|
remainingPoints.ExceptWith(convexHull);
|
|
544
629
|
|
|
@@ -550,7 +635,8 @@
|
|
|
550
635
|
throw new ArgumentException(nameof(gridPositions));
|
|
551
636
|
}
|
|
552
637
|
|
|
553
|
-
QuadTree<FastVector3Int> NewQuadTree() =>
|
|
638
|
+
QuadTree<FastVector3Int> NewQuadTree() =>
|
|
639
|
+
new(gridPositions, CellToWorld, maybeBounds.Value, bucketSize: bucketSize);
|
|
554
640
|
|
|
555
641
|
QuadTree<FastVector3Int> quadTree = NewQuadTree();
|
|
556
642
|
List<FastVector3Int> neighbors = Buffers<FastVector3Int>.List;
|
|
@@ -568,10 +654,13 @@
|
|
|
568
654
|
{
|
|
569
655
|
continue;
|
|
570
656
|
}
|
|
571
|
-
|
|
572
|
-
localMaximumDistance = Math.Max(
|
|
657
|
+
|
|
658
|
+
localMaximumDistance = Math.Max(
|
|
659
|
+
localMaximumDistance,
|
|
660
|
+
(CellToWorld(neighbor) - edgeCenter).sqrMagnitude
|
|
661
|
+
);
|
|
573
662
|
}
|
|
574
|
-
|
|
663
|
+
|
|
575
664
|
if (edge.edgeLength <= localMaximumDistance)
|
|
576
665
|
{
|
|
577
666
|
concaveHullEdges.Add(edge);
|
|
@@ -669,7 +758,12 @@
|
|
|
669
758
|
|
|
670
759
|
// https://www.researchgate.net/publication/220868874_Concave_hull_A_k-nearest_neighbours_approach_for_the_computation_of_the_region_occupied_by_a_set_of_points
|
|
671
760
|
|
|
672
|
-
public static List<FastVector3Int> BuildConcaveHull2(
|
|
761
|
+
public static List<FastVector3Int> BuildConcaveHull2(
|
|
762
|
+
this IReadOnlyCollection<FastVector3Int> gridPositions,
|
|
763
|
+
Grid grid,
|
|
764
|
+
IRandom random = null,
|
|
765
|
+
int nearestNeighbors = 3
|
|
766
|
+
)
|
|
673
767
|
{
|
|
674
768
|
const int minimumNearestNeighbors = 3;
|
|
675
769
|
nearestNeighbors = Math.Max(minimumNearestNeighbors, nearestNeighbors);
|
|
@@ -678,12 +772,12 @@
|
|
|
678
772
|
{
|
|
679
773
|
return dataSet;
|
|
680
774
|
}
|
|
681
|
-
|
|
775
|
+
|
|
682
776
|
nearestNeighbors = Math.Min(dataSet.Count, nearestNeighbors);
|
|
683
777
|
|
|
684
778
|
IComparer<FastVector3Int> comparison = Comparer<FastVector3Int>.Create(
|
|
685
|
-
(lhs, rhs) =>
|
|
686
|
-
|
|
779
|
+
(lhs, rhs) => grid.CellToWorld(lhs).y.CompareTo(grid.CellToWorld(rhs).y)
|
|
780
|
+
);
|
|
687
781
|
|
|
688
782
|
FastVector3Int? maybeFirst = null;
|
|
689
783
|
foreach (FastVector3Int gridPosition in dataSet)
|
|
@@ -755,8 +849,14 @@
|
|
|
755
849
|
Vector2 lhsPoint = grid.CellToWorld(lhs);
|
|
756
850
|
Vector2 rhsPoint = grid.CellToWorld(rhs);
|
|
757
851
|
|
|
758
|
-
float lhsAngle = AngleDifference(
|
|
759
|
-
|
|
852
|
+
float lhsAngle = AngleDifference(
|
|
853
|
+
previousAngle,
|
|
854
|
+
CalculateAngle(currentPoint, lhsPoint)
|
|
855
|
+
);
|
|
856
|
+
float rhsAngle = AngleDifference(
|
|
857
|
+
previousAngle,
|
|
858
|
+
CalculateAngle(currentPoint, rhsPoint)
|
|
859
|
+
);
|
|
760
860
|
return rhsAngle.CompareTo(lhsAngle);
|
|
761
861
|
}
|
|
762
862
|
|
|
@@ -771,11 +871,17 @@
|
|
|
771
871
|
{
|
|
772
872
|
Vector2 lhsPoint = grid.CellToWorld(lhs);
|
|
773
873
|
Vector2 rhsPoint = grid.CellToWorld(rhs);
|
|
774
|
-
return (lhsPoint - currentPoint).sqrMagnitude.CompareTo(
|
|
775
|
-
|
|
874
|
+
return (lhsPoint - currentPoint).sqrMagnitude.CompareTo(
|
|
875
|
+
(rhsPoint - currentPoint).sqrMagnitude
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
);
|
|
776
879
|
if (nearestNeighbors < clockwisePoints.Count)
|
|
777
880
|
{
|
|
778
|
-
clockwisePoints.RemoveRange(
|
|
881
|
+
clockwisePoints.RemoveRange(
|
|
882
|
+
nearestNeighbors,
|
|
883
|
+
clockwisePoints.Count - nearestNeighbors
|
|
884
|
+
);
|
|
779
885
|
}
|
|
780
886
|
}
|
|
781
887
|
|
|
@@ -816,13 +922,18 @@
|
|
|
816
922
|
{
|
|
817
923
|
if (!IsPositionInside(hull, dataSet[i], grid))
|
|
818
924
|
{
|
|
819
|
-
return BuildConcaveHull2(
|
|
925
|
+
return BuildConcaveHull2(
|
|
926
|
+
gridPositions,
|
|
927
|
+
grid,
|
|
928
|
+
random,
|
|
929
|
+
nearestNeighbors + 1
|
|
930
|
+
);
|
|
820
931
|
}
|
|
821
932
|
}
|
|
822
933
|
|
|
823
934
|
return hull;
|
|
824
935
|
}
|
|
825
|
-
|
|
936
|
+
|
|
826
937
|
current = clockwisePoints[i];
|
|
827
938
|
if (current != first)
|
|
828
939
|
{
|
|
@@ -839,7 +950,10 @@
|
|
|
839
950
|
dataSet.RemoveAtSwapBack(currentIndex);
|
|
840
951
|
}
|
|
841
952
|
|
|
842
|
-
previousAngle = CalculateAngle(
|
|
953
|
+
previousAngle = CalculateAngle(
|
|
954
|
+
grid.CellToWorld(hull[step - 1]),
|
|
955
|
+
grid.CellToWorld(hull[step - 2])
|
|
956
|
+
);
|
|
843
957
|
++step;
|
|
844
958
|
}
|
|
845
959
|
|
|
@@ -867,18 +981,24 @@
|
|
|
867
981
|
|
|
868
982
|
public Line(Vector2 from, Vector2 to)
|
|
869
983
|
{
|
|
870
|
-
this.from = from;
|
|
984
|
+
this.from = from;
|
|
871
985
|
this.to = to;
|
|
872
986
|
sqrMagnitude = (from - to).sqrMagnitude;
|
|
873
987
|
}
|
|
874
988
|
}
|
|
875
989
|
|
|
876
|
-
public static List<FastVector3Int> BuildConcaveHull(
|
|
990
|
+
public static List<FastVector3Int> BuildConcaveHull(
|
|
991
|
+
this IEnumerable<FastVector3Int> gridPositions,
|
|
992
|
+
Grid grid,
|
|
993
|
+
IRandom random = null,
|
|
994
|
+
float scaleFactor = 1,
|
|
995
|
+
float concavity = 0f
|
|
996
|
+
)
|
|
877
997
|
{
|
|
878
998
|
if (concavity < -1 || 1 < concavity)
|
|
879
999
|
{
|
|
880
1000
|
throw new ArgumentException($"Concavity must be between [-1, 1], was {concavity}");
|
|
881
|
-
}
|
|
1001
|
+
}
|
|
882
1002
|
|
|
883
1003
|
List<FastVector3Int> originalGridPositions = gridPositions.ToList();
|
|
884
1004
|
if (originalGridPositions.Count <= 3)
|
|
@@ -910,8 +1030,19 @@
|
|
|
910
1030
|
for (int i = 0; i < concaveHullLines.Count; ++i)
|
|
911
1031
|
{
|
|
912
1032
|
Line line = concaveHullLines[i];
|
|
913
|
-
IEnumerable<FastVector3Int> nearbyPoints = GetNearbyPoints(
|
|
914
|
-
|
|
1033
|
+
IEnumerable<FastVector3Int> nearbyPoints = GetNearbyPoints(
|
|
1034
|
+
line,
|
|
1035
|
+
unusedNodes,
|
|
1036
|
+
grid,
|
|
1037
|
+
scaleFactor
|
|
1038
|
+
);
|
|
1039
|
+
List<Line> dividedLine = GetDividedLine(
|
|
1040
|
+
line,
|
|
1041
|
+
nearbyPoints,
|
|
1042
|
+
concaveHullLines,
|
|
1043
|
+
grid,
|
|
1044
|
+
concavity
|
|
1045
|
+
);
|
|
915
1046
|
if (0 < dividedLine.Count)
|
|
916
1047
|
{
|
|
917
1048
|
aLineWasDividedInTheIteration = true;
|
|
@@ -922,8 +1053,7 @@
|
|
|
922
1053
|
break;
|
|
923
1054
|
}
|
|
924
1055
|
}
|
|
925
|
-
}
|
|
926
|
-
while (aLineWasDividedInTheIteration);
|
|
1056
|
+
} while (aLineWasDividedInTheIteration);
|
|
927
1057
|
|
|
928
1058
|
List<FastVector3Int> concaveHull = new(concaveHullLines.Count);
|
|
929
1059
|
if (concaveHullLines.Count <= 0)
|
|
@@ -939,12 +1069,11 @@
|
|
|
939
1069
|
concaveHullLines.RemoveAtSwapBack(0);
|
|
940
1070
|
while (0 < concaveHullLines.Count)
|
|
941
1071
|
{
|
|
942
|
-
int index = concaveHullLines.FindIndex(
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
});
|
|
1072
|
+
int index = concaveHullLines.FindIndex(line =>
|
|
1073
|
+
{
|
|
1074
|
+
FastVector3Int lineFrom = grid.WorldToCell(line.from);
|
|
1075
|
+
return lineFrom == to;
|
|
1076
|
+
});
|
|
948
1077
|
|
|
949
1078
|
currentlyConsideredLine = concaveHullLines[index];
|
|
950
1079
|
to = grid.WorldToCell(currentlyConsideredLine.to);
|
|
@@ -954,12 +1083,16 @@
|
|
|
954
1083
|
}
|
|
955
1084
|
concaveHull.Add(to);
|
|
956
1085
|
concaveHullLines.RemoveAtSwapBack(index);
|
|
957
|
-
}
|
|
1086
|
+
}
|
|
958
1087
|
|
|
959
1088
|
return concaveHull;
|
|
960
1089
|
}
|
|
961
1090
|
|
|
962
|
-
public static bool IsPositionInside(
|
|
1091
|
+
public static bool IsPositionInside(
|
|
1092
|
+
List<FastVector3Int> hull,
|
|
1093
|
+
FastVector3Int gridPosition,
|
|
1094
|
+
Grid grid
|
|
1095
|
+
)
|
|
963
1096
|
{
|
|
964
1097
|
bool isPositionInside = false;
|
|
965
1098
|
Vector2 position = grid.CellToWorld(gridPosition);
|
|
@@ -982,9 +1115,11 @@
|
|
|
982
1115
|
rhs = oldVector;
|
|
983
1116
|
}
|
|
984
1117
|
|
|
985
|
-
if (
|
|
986
|
-
(
|
|
987
|
-
(
|
|
1118
|
+
if (
|
|
1119
|
+
(newVector.x < position.x) == (position.x <= oldVector.x)
|
|
1120
|
+
&& (position.y - (long)lhs.y) * (rhs.x - lhs.x)
|
|
1121
|
+
< (rhs.y - (long)lhs.y) * (position.x - lhs.x)
|
|
1122
|
+
)
|
|
988
1123
|
{
|
|
989
1124
|
isPositionInside = !isPositionInside;
|
|
990
1125
|
}
|
|
@@ -993,14 +1128,25 @@
|
|
|
993
1128
|
return isPositionInside;
|
|
994
1129
|
}
|
|
995
1130
|
|
|
996
|
-
private static List<Line> GetDividedLine(
|
|
1131
|
+
private static List<Line> GetDividedLine(
|
|
1132
|
+
Line line,
|
|
1133
|
+
IEnumerable<FastVector3Int> nearbyPoints,
|
|
1134
|
+
List<Line> concaveHull,
|
|
1135
|
+
Grid grid,
|
|
1136
|
+
float concavity
|
|
1137
|
+
)
|
|
997
1138
|
{
|
|
998
1139
|
return GetDividedLine(line.from, line.to, nearbyPoints, concaveHull, grid, concavity);
|
|
999
1140
|
}
|
|
1000
1141
|
|
|
1001
1142
|
private static List<Line> GetDividedLine(
|
|
1002
|
-
Vector2 from,
|
|
1003
|
-
|
|
1143
|
+
Vector2 from,
|
|
1144
|
+
Vector2 to,
|
|
1145
|
+
IEnumerable<FastVector3Int> nearbyPoints,
|
|
1146
|
+
List<Line> concaveHull,
|
|
1147
|
+
Grid grid,
|
|
1148
|
+
float concavity
|
|
1149
|
+
)
|
|
1004
1150
|
{
|
|
1005
1151
|
List<Line> dividedLine = new(2);
|
|
1006
1152
|
Dictionary<Vector2, double> okMiddlePoints = new();
|
|
@@ -1012,7 +1158,10 @@
|
|
|
1012
1158
|
{
|
|
1013
1159
|
Line newLineA = new(from, point);
|
|
1014
1160
|
Line newLineB = new(point, to);
|
|
1015
|
-
if (
|
|
1161
|
+
if (
|
|
1162
|
+
!LineCollidesWithHull(newLineA, concaveHull)
|
|
1163
|
+
&& !LineCollidesWithHull(newLineB, concaveHull)
|
|
1164
|
+
)
|
|
1016
1165
|
{
|
|
1017
1166
|
okMiddlePoints[point] = cosine;
|
|
1018
1167
|
}
|
|
@@ -1074,12 +1223,23 @@
|
|
|
1074
1223
|
return Math.Round(cos, 4);
|
|
1075
1224
|
}
|
|
1076
1225
|
|
|
1077
|
-
private static IEnumerable<FastVector3Int> GetNearbyPoints(
|
|
1226
|
+
private static IEnumerable<FastVector3Int> GetNearbyPoints(
|
|
1227
|
+
Line line,
|
|
1228
|
+
ICollection<FastVector3Int> points,
|
|
1229
|
+
Grid grid,
|
|
1230
|
+
float scaleFactor
|
|
1231
|
+
)
|
|
1078
1232
|
{
|
|
1079
1233
|
return GetNearbyPoints(line.from, line.to, points, grid, scaleFactor);
|
|
1080
1234
|
}
|
|
1081
1235
|
|
|
1082
|
-
private static IEnumerable<FastVector3Int> GetNearbyPoints(
|
|
1236
|
+
private static IEnumerable<FastVector3Int> GetNearbyPoints(
|
|
1237
|
+
Vector2 from,
|
|
1238
|
+
Vector2 to,
|
|
1239
|
+
ICollection<FastVector3Int> points,
|
|
1240
|
+
Grid grid,
|
|
1241
|
+
float scaleFactor
|
|
1242
|
+
)
|
|
1083
1243
|
{
|
|
1084
1244
|
const int maxTries = 2;
|
|
1085
1245
|
for (int tries = 0; tries < maxTries; ++tries)
|
|
@@ -1114,13 +1274,15 @@
|
|
|
1114
1274
|
float yMin = Math.Min(from.y, to.y);
|
|
1115
1275
|
float xMax = Math.Max(from.x, to.x);
|
|
1116
1276
|
float yMax = Math.Max(from.y, to.y);
|
|
1117
|
-
|
|
1277
|
+
|
|
1118
1278
|
float width = xMax - xMin;
|
|
1119
1279
|
float height = yMax - yMin;
|
|
1120
|
-
return new Bounds(
|
|
1280
|
+
return new Bounds(
|
|
1281
|
+
new Vector3(xMin + width / 2, yMin + height / 2),
|
|
1282
|
+
new Vector3(width, height) * scaleFactor + new Vector3(0.001f, 0.001f)
|
|
1283
|
+
);
|
|
1121
1284
|
}
|
|
1122
1285
|
|
|
1123
|
-
|
|
1124
1286
|
// https://www.geeksforgeeks.org/how-to-check-if-a-given-point-lies-inside-a-polygon/#
|
|
1125
1287
|
|
|
1126
1288
|
/// <summary>
|
|
@@ -1132,7 +1294,12 @@
|
|
|
1132
1294
|
/// <param name="rhsFrom">LineSegmentB start point.</param>
|
|
1133
1295
|
/// <param name="rhsTo">LineSegmentB end point.</param>
|
|
1134
1296
|
/// <returns>True if the line segments intersect.</returns>
|
|
1135
|
-
public static bool Intersects(
|
|
1297
|
+
public static bool Intersects(
|
|
1298
|
+
Vector2 lhsFrom,
|
|
1299
|
+
Vector2 lhsTo,
|
|
1300
|
+
Vector2 rhsFrom,
|
|
1301
|
+
Vector2 rhsTo
|
|
1302
|
+
)
|
|
1136
1303
|
{
|
|
1137
1304
|
if (lhsFrom == rhsFrom)
|
|
1138
1305
|
{
|
|
@@ -1197,7 +1364,10 @@
|
|
|
1197
1364
|
/// <returns>True if q lies on the line segment pr.</returns>
|
|
1198
1365
|
public static bool LiesOnSegment(Vector2 p, Vector2 q, Vector2 r)
|
|
1199
1366
|
{
|
|
1200
|
-
return q.x <= Math.Max(p.x, r.x)
|
|
1367
|
+
return q.x <= Math.Max(p.x, r.x)
|
|
1368
|
+
&& Math.Min(p.x, r.x) <= q.x
|
|
1369
|
+
&& q.y <= Math.Max(p.y, r.y)
|
|
1370
|
+
&& Math.Min(p.y, r.y) <= q.y;
|
|
1201
1371
|
}
|
|
1202
1372
|
|
|
1203
1373
|
public enum OrientationType
|
|
@@ -1227,17 +1397,18 @@
|
|
|
1227
1397
|
|
|
1228
1398
|
#endregion
|
|
1229
1399
|
|
|
1230
|
-
public static Vector2 Rotate(this Vector2 v, float degrees)
|
|
1400
|
+
public static Vector2 Rotate(this Vector2 v, float degrees)
|
|
1401
|
+
{
|
|
1231
1402
|
float sin = Mathf.Sin(degrees * Mathf.Deg2Rad);
|
|
1232
1403
|
float cos = Mathf.Cos(degrees * Mathf.Deg2Rad);
|
|
1233
1404
|
|
|
1234
1405
|
float tx = v.x;
|
|
1235
1406
|
float ty = v.y;
|
|
1236
|
-
|
|
1407
|
+
|
|
1237
1408
|
Vector2 rotatedVector;
|
|
1238
1409
|
rotatedVector.x = (cos * tx) - (sin * ty);
|
|
1239
1410
|
rotatedVector.y = (sin * tx) + (cos * ty);
|
|
1240
|
-
|
|
1411
|
+
|
|
1241
1412
|
return rotatedVector;
|
|
1242
1413
|
}
|
|
1243
1414
|
|
|
@@ -1252,12 +1423,17 @@
|
|
|
1252
1423
|
|
|
1253
1424
|
Vector3 boundsMax = bounds.max;
|
|
1254
1425
|
Vector3 otherMin = other.min;
|
|
1255
|
-
return boundsMax.x >= otherMin.x
|
|
1426
|
+
return boundsMax.x >= otherMin.x
|
|
1427
|
+
&& boundsMax.y >= otherMin.y
|
|
1428
|
+
&& boundsMax.z >= otherMin.z;
|
|
1256
1429
|
}
|
|
1257
1430
|
|
|
1258
1431
|
public static bool FastContains2D(this BoundsInt bounds, FastVector3Int position)
|
|
1259
1432
|
{
|
|
1260
|
-
return position.x >= bounds.xMin
|
|
1433
|
+
return position.x >= bounds.xMin
|
|
1434
|
+
&& position.y >= bounds.yMin
|
|
1435
|
+
&& position.x < bounds.xMax
|
|
1436
|
+
&& position.y < bounds.yMax;
|
|
1261
1437
|
}
|
|
1262
1438
|
|
|
1263
1439
|
public static bool FastIntersects2D(this BoundsInt bounds, BoundsInt other)
|
|
@@ -1276,7 +1452,7 @@
|
|
|
1276
1452
|
if (position.x < min.x || position.y < bounds.min.y)
|
|
1277
1453
|
{
|
|
1278
1454
|
return false;
|
|
1279
|
-
}
|
|
1455
|
+
}
|
|
1280
1456
|
Vector3 max = bounds.max;
|
|
1281
1457
|
return position.x < max.x && position.y < max.y;
|
|
1282
1458
|
}
|
|
@@ -1312,7 +1488,14 @@
|
|
|
1312
1488
|
public static BoundsInt WithPadding(this BoundsInt bounds, int xPadding, int yPadding)
|
|
1313
1489
|
{
|
|
1314
1490
|
Vector3Int size = bounds.size;
|
|
1315
|
-
return new BoundsInt(
|
|
1491
|
+
return new BoundsInt(
|
|
1492
|
+
bounds.xMin - xPadding,
|
|
1493
|
+
bounds.yMin - yPadding,
|
|
1494
|
+
bounds.zMin,
|
|
1495
|
+
size.x + 2 * xPadding,
|
|
1496
|
+
size.y + 2 * yPadding,
|
|
1497
|
+
size.z
|
|
1498
|
+
);
|
|
1316
1499
|
}
|
|
1317
1500
|
|
|
1318
1501
|
public static void SetColors(this UnityEngine.UI.Slider slider, Color color)
|
|
@@ -1392,9 +1575,14 @@
|
|
|
1392
1575
|
yield break;
|
|
1393
1576
|
}
|
|
1394
1577
|
|
|
1395
|
-
foreach (
|
|
1578
|
+
foreach (
|
|
1579
|
+
EditorCurveBinding binding in AnimationUtility.GetObjectReferenceCurveBindings(clip)
|
|
1580
|
+
)
|
|
1396
1581
|
{
|
|
1397
|
-
ObjectReferenceKeyframe[] keyframes = AnimationUtility.GetObjectReferenceCurve(
|
|
1582
|
+
ObjectReferenceKeyframe[] keyframes = AnimationUtility.GetObjectReferenceCurve(
|
|
1583
|
+
clip,
|
|
1584
|
+
binding
|
|
1585
|
+
);
|
|
1398
1586
|
foreach (ObjectReferenceKeyframe frame in keyframes)
|
|
1399
1587
|
{
|
|
1400
1588
|
if (frame.value is Sprite sprite)
|