// 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 } } }