UNPKG

com.wallstop-studios.unity-helpers

Version:

Treasure chest of Unity developer tools

116 lines (82 loc) 6.23 kB
# Hulls (Convex vs Concave) ## TL;DR — When To Use Which - Convex hull: fastest, safe outer bound; great for coarse collisions and visibility. - Concave hull: follows shape detail; tunable fidelity vs. stability via k/alpha parameters. This guide explains convex and concave hulls, when to use each, and how they differ. ## Convex Hull - The smallest convex polygon that contains all points. - Algorithms: Monotone Chain (a.k.a. Andrew’s), Graham Scan, Jarvis March. - Characteristics - Always convex; no inward dents. - Stable and deterministic for fixed input. - Often used for coarse collision proxies, shape bounds, and visibility. Illustration: ![Convex Hull](../../images/spatial/convex-hull.svg) ## Concave Hull - A polygon that can indent to follow the shape of points more closely. - Algorithms: k-nearest-neighbor based, alpha-shapes, ball-pivoting variants. - Characteristics - Can capture shape detail; may exclude sparse outliers. - Parameterized by k (neighbors) or alpha (radius) controlling “concavity”. - May create holes or self-intersections if not constrained; validate output. Illustration: ![Concave Hull](../../images/spatial/concave-hull.svg) ## Choosing Between Them - Use convex hull when you need a fast, safe, and simple bound with predictable performance. - Use concave hull when shape fidelity matters (e.g., silhouette, path enclosure) and you accept a tunable trade-off between detail and stability. ## Tips - Preprocess: remove duplicate points and optionally simplify clusters. - Postprocess: enforce clockwise/CCW winding and run self-intersection checks for concave hulls. - Numerical stability: add small epsilons for collinear checks; include or exclude boundary points consistently. ## API Reference (Grid vs. Gridless) All hull helpers now offer both grid-aware (`Grid` + `FastVector3Int`) and gridless variants so you can work directly with `Vector2`/`FastVector3Int` data: - Convex hull - `points.BuildConvexHull(includeColinearPoints: false)` for pure `Vector2`. - `fastPoints.BuildConvexHull(includeColinearPoints: false)` for `FastVector3Int` without a `Grid`. - `fastPoints.BuildConvexHull(grid, includeColinearPoints: false)` when you need `Grid.CellToWorld` conversions. - Algorithm selection via `ConvexHullAlgorithm` is available for both gridful and gridless overloads. - Concave hull - `vectorPoints.BuildConcaveHull(options)` / `BuildConcaveHullKnn` / `BuildConcaveHullEdgeSplit` for `Vector2`. - `fastPoints.BuildConcaveHull(options)` plus the `Knn`/`EdgeSplit` helpers for `FastVector3Int` without requiring a `Grid`. - `fastPoints.BuildConcaveHull(grid, options)` remains available when your data lives in grid space. - > ⚠️ The legacy line-division overload `BuildConcaveHull(IEnumerable<FastVector3Int>, Grid, float scaleFactor, float concavity)` has been retired and now throws `NotSupportedException`. Switch to `ConcaveHullStrategy.Knn` or `ConcaveHullStrategy.EdgeSplit` instead. Because the new overloads reuse the pooled implementations under the hood, behaviour (winding, pruning, GC profile) matches the grid versions—pick whichever signature best matches your data source. ## Gridless vs. Grid-Aware Quickstart - Pick the **gridless** overloads when your points already live in world/local space (`Vector2`, `Vector3`, or `FastVector3Int` without a `Grid`). This keeps the hull math independent of Unity’s tile conversion layer. - Pick the **grid-aware** overloads when you have cell coordinates tied to a `Grid` or `Tilemap` and you want the helper to respect `Grid.CellToWorld` so you can visualize the hull in scene space. Gridless example — pure `Vector2` data for nav areas or spline fitting: ```csharp using System.Collections.Generic; using UnityEngine; using WallstopStudios.UnityHelpers.Core.Extension; // outlinePoints could come from mouse clicks or a baked spline List<Vector2> outlinePoints = CollectOutlineSamples(); UnityExtensions.ConcaveHullOptions outlineOptions = UnityExtensions.ConcaveHullOptions.Default .WithStrategy(UnityExtensions.ConcaveHullStrategy.EdgeSplit) .WithBucketSize(32) .WithAngleThreshold(70f); List<Vector2> hull = outlinePoints.BuildConcaveHull(outlineOptions); ``` Grid-aware example — `FastVector3Int` tiles aligned to a `Grid` for tilemaps or voxel data: ```csharp using System.Collections.Generic; using UnityEngine; using WallstopStudios.UnityHelpers.Core.DataStructure.Adapters; using WallstopStudios.UnityHelpers.Core.Extension; Grid grid = GetComponent<Grid>(); List<FastVector3Int> tileSamples = CollectTileCoordinates(); UnityExtensions.ConcaveHullOptions tileOptions = UnityExtensions.ConcaveHullOptions.Default .WithStrategy(UnityExtensions.ConcaveHullStrategy.Knn) .WithNearestNeighbors(5); List<FastVector3Int> gridHull = tileSamples.BuildConcaveHull(grid, tileOptions); ``` See `Samples~/Spatial Structures - 2D and 3D/Scripts/HullUsageDemo.cs` for a runnable MonoBehaviour that draws both loops (cyan for gridless, yellow for grid-aware) and logs the strategy/neighbor counts so you can copy the pattern directly into your own tooling, or just open `Samples~/Spatial Structures - 2D and 3D/Scenes/HullUsageDemo.unity` and press Play to watch both flows without extra setup. ## Collinear Points & includeColinearPoints - Convex hull helpers prune collinear points by default so only the true corners remain, even after grid-to-world projections introduce float skew. - Opt into boundary retention by passing `includeColinearPoints: true` to `BuildConvexHull` (gridless) or its grid-aware overloads. - Concave hulls inherit the pruned convex frontier; enabling collinear inclusion widens the seed set and can improve fidelity for dense edge sampling. - The comprehensive tests `UnityExtensionsComprehensiveTests.ConvexHullDenseSamplesOnAllEdgesCollapseToCorners` (grid) and `.Vector2ConvexHullDenseSamplesCollapseToCorners` (gridless) cover both paths so you can trust the deterministic behavior. ```csharp List<FastVector3Int> cornersOnly = gridPoints.BuildConvexHull(grid, includeColinearPoints: false); List<FastVector3Int> withEdges = gridPoints.BuildConvexHull(grid, includeColinearPoints: true); ```