// MIT License - Copyright (c) 2025 wallstop
// Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE
// ReSharper disable once CheckNamespace
namespace WallstopStudios.UnityHelpers.Core.Extension
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using DataStructure.Adapters;
using UnityEngine;
using WallstopStudios.UnityHelpers.Utils;
// GeometryConcaveHullGrid.cs - Grid-aware entry points for FastVector3Int inputs
// See GeometryConcaveHull.cs for full concave hull architecture documentation
///
/// Grid-aware concave hull entry points (FastVector3Int + Grid contexts).
/// Provides hull generation for Unity Grid-based tile systems.
///
public static partial class UnityExtensions
{
///
/// Unified concave hull entry point with explicit strategy handling for Grid contexts.
///
public static List BuildConcaveHull(
this IReadOnlyCollection gridPositions,
Grid grid,
ConcaveHullOptions? options = null
)
{
ConcaveHullOptions appliedOptions = options ?? ConcaveHullOptions.Default;
using PooledResource> sourcePointsLease =
Buffers.List.Get(out List sourcePoints);
sourcePoints.AddRange(
gridPositions ?? throw new ArgumentNullException(nameof(gridPositions))
);
List hull;
switch (appliedOptions.Strategy)
{
case ConcaveHullStrategy.Knn:
#pragma warning disable CS0618 // Type or member is obsolete
hull = gridPositions.BuildConcaveHull2(
grid,
Math.Max(3, appliedOptions.NearestNeighbors)
);
#pragma warning restore CS0618 // Type or member is obsolete
break;
case ConcaveHullStrategy.EdgeSplit:
#pragma warning disable CS0618 // Type or member is obsolete
hull = gridPositions.BuildConcaveHull3(
grid,
Math.Max(1, appliedOptions.BucketSize),
appliedOptions.AngleThreshold
);
#pragma warning restore CS0618 // Type or member is obsolete
break;
default:
throw new InvalidEnumArgumentException(
nameof(appliedOptions.Strategy),
(int)appliedOptions.Strategy,
typeof(ConcaveHullStrategy)
);
}
#if ENABLE_CONCAVE_HULL_STATS
ConcaveHullRepairStats repairStats = new(hull.Count, sourcePoints.Count);
MaybeRepairConcaveCorners(
hull,
sourcePoints,
appliedOptions.Strategy,
appliedOptions.AngleThreshold,
repairStats
);
TrackHullRepairStats(hull, repairStats);
#else
MaybeRepairConcaveCorners(
hull,
sourcePoints,
appliedOptions.Strategy,
appliedOptions.AngleThreshold
);
#endif
return hull;
}
public static List BuildConcaveHullKnn(
this IReadOnlyCollection gridPositions,
Grid grid,
int nearestNeighbors = 3
)
{
#pragma warning disable CS0618 // Type or member is obsolete
ConcaveHullOptions options = ConcaveHullOptions
.Default.WithStrategy(ConcaveHullStrategy.Knn)
.WithNearestNeighbors(Math.Max(3, nearestNeighbors));
return gridPositions.BuildConcaveHull(grid, options);
#pragma warning restore CS0618 // Type or member is obsolete
}
public static List BuildConcaveHullEdgeSplit(
this IReadOnlyCollection gridPositions,
Grid grid,
int bucketSize = 40,
float angleThreshold = 90f
)
{
#pragma warning disable CS0618 // Type or member is obsolete
int clampedBucketSize = Math.Max(1, bucketSize);
float effectiveAngleThreshold = clampedBucketSize <= 1 ? 0f : angleThreshold;
ConcaveHullOptions options = ConcaveHullOptions
.Default.WithStrategy(ConcaveHullStrategy.EdgeSplit)
.WithBucketSize(clampedBucketSize)
.WithAngleThreshold(effectiveAngleThreshold);
return gridPositions.BuildConcaveHull(grid, options);
#pragma warning restore CS0618 // Type or member is obsolete
}
}
}