< Summary

Information
Class: Trailblazer.Pathing.NavigationConnection
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Map/NavigationConnection.cs
Line coverage
100%
Covered lines: 90
Uncovered lines: 0
Coverable lines: 90
Total lines: 198
Line coverage: 100%
Branch coverage
100%
Covered branches: 38
Total branches: 38
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Witnesses()100%11100%
.ctor(...)100%22100%
Equals(...)100%2828100%
Equals(...)100%11100%
GetHashCode()100%22100%
CopyWitnesses(...)100%66100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Map/NavigationConnection.cs

#LineLine coverage
 1//=======================================================================
 2// NavigationConnection.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Collections.Generic;
 10using System.Collections.ObjectModel;
 11using FixedMathSharp;
 12using GridForge.Spatial;
 13using SwiftCollections.Utility;
 14
 15namespace Trailblazer.Pathing;
 16
 17/// <summary>
 18/// Describes one directed, source-map-owned physical connection or shortcut.
 19/// </summary>
 20public sealed class NavigationConnection : IEquatable<NavigationConnection>
 21{
 22    private readonly NavigationCellAddress[] _witnesses;
 23    private readonly ReadOnlyCollection<NavigationCellAddress> _witnessView;
 24
 25    /// <summary>
 26    /// The stable map-local connection identifier.
 27    /// </summary>
 28    public string Id { get; }
 29
 30    /// <summary>
 31    /// The local source-cell index in the owning map.
 32    /// </summary>
 33    public VoxelIndex SourceIndex { get; }
 34
 35    /// <summary>
 36    /// The durable destination-cell address.
 37    /// </summary>
 38    public NavigationCellAddress Destination { get; }
 39
 40    /// <summary>
 41    /// The exact world-space point where traversal leaves the source cell.
 42    /// </summary>
 43    public Vector3d EntryAnchor { get; }
 44
 45    /// <summary>
 46    /// The exact world-space point where traversal enters the destination cell.
 47    /// </summary>
 48    public Vector3d ExitAnchor { get; }
 49
 50    /// <summary>
 51    /// The inclusive horizontal radius clearance through the complete connection corridor.
 52    /// </summary>
 53    public Fixed64 PortalRadiusClearance { get; }
 54
 55    /// <summary>
 56    /// The inclusive vertical clearance through the complete connection corridor.
 57    /// </summary>
 58    public Fixed64 PortalHeightClearance { get; }
 59
 60    /// <summary>
 61    /// The cells whose presence, blockage, and clearance certify this connection.
 62    /// </summary>
 6681663    public IReadOnlyList<NavigationCellAddress> Witnesses => _witnessView;
 64
 65    /// <summary>
 66    /// The non-negative surcharge added after geometric travel cost.
 67    /// </summary>
 68    public Fixed64 AdditionalCost { get; }
 69
 70    /// <summary>
 71    /// Indicates that the complete connection cost certifies a Euclidean lower bound.
 72    /// </summary>
 73    public bool IsLowerBoundCertified { get; }
 74
 75    /// <summary>
 76    /// Creates one complete directed connection definition.
 77    /// </summary>
 455078    public NavigationConnection(
 455079        string id,
 455080        VoxelIndex sourceIndex,
 455081        NavigationCellAddress destination,
 455082        Vector3d entryAnchor,
 455083        Vector3d exitAnchor,
 455084        Fixed64 portalRadiusClearance,
 455085        Fixed64 portalHeightClearance,
 455086        IEnumerable<NavigationCellAddress>? witnesses = null,
 455087        Fixed64 additionalCost = default,
 455088        bool isLowerBoundCertified = false)
 89    {
 455090        SwiftThrowHelper.ThrowIfArgument(
 455091            string.IsNullOrWhiteSpace(id),
 455092            nameof(id),
 455093            "Connection ID cannot be null, empty, or whitespace.");
 455094        SwiftThrowHelper.ThrowIfArgument(
 455095            portalRadiusClearance < Fixed64.Zero,
 455096            nameof(portalRadiusClearance),
 455097            "Portal radius clearance must be non-negative.");
 455098        SwiftThrowHelper.ThrowIfArgument(
 455099            portalHeightClearance <= Fixed64.Zero,
 4550100            nameof(portalHeightClearance),
 4550101            "Portal height clearance must be positive.");
 4549102        SwiftThrowHelper.ThrowIfArgument(
 4549103            additionalCost < Fixed64.Zero,
 4549104            nameof(additionalCost),
 4549105            "Additional cost must be non-negative.");
 4549106        SwiftThrowHelper.ThrowIfArgument(
 4549107            string.IsNullOrWhiteSpace(destination.MapId),
 4549108            nameof(destination),
 4549109            "Destination must contain a valid map ID.");
 110
 4549111        Id = id;
 4549112        SourceIndex = sourceIndex;
 4549113        Destination = destination;
 4549114        EntryAnchor = entryAnchor;
 4549115        ExitAnchor = exitAnchor;
 4549116        PortalRadiusClearance = portalRadiusClearance;
 4549117        PortalHeightClearance = portalHeightClearance;
 4549118        AdditionalCost = additionalCost;
 4549119        IsLowerBoundCertified = isLowerBoundCertified;
 4549120        _witnesses = CopyWitnesses(witnesses);
 10378121        for (int i = 0; i < _witnesses.Length; i++)
 122        {
 640123            SwiftThrowHelper.ThrowIfArgument(
 640124                string.IsNullOrWhiteSpace(_witnesses[i].MapId),
 640125                nameof(witnesses),
 640126                "Every witness must contain a valid map ID.");
 127        }
 4549128        _witnessView = Array.AsReadOnly(_witnesses);
 4549129    }
 130
 131    /// <inheritdoc/>
 132    public bool Equals(NavigationConnection? other)
 133    {
 289134        if (ReferenceEquals(this, other))
 9135            return true;
 280136        if (other is null
 280137            || !string.Equals(Id, other.Id, StringComparison.Ordinal)
 280138            || !SourceIndex.Equals(other.SourceIndex)
 280139            || !Destination.Equals(other.Destination)
 280140            || EntryAnchor != other.EntryAnchor
 280141            || ExitAnchor != other.ExitAnchor
 280142            || PortalRadiusClearance != other.PortalRadiusClearance
 280143            || PortalHeightClearance != other.PortalHeightClearance
 280144            || AdditionalCost != other.AdditionalCost
 280145            || IsLowerBoundCertified != other.IsLowerBoundCertified
 280146            || _witnesses.Length != other._witnesses.Length)
 147        {
 35148            return false;
 149        }
 150
 496151        for (int i = 0; i < _witnesses.Length; i++)
 152        {
 4153            if (!_witnesses[i].Equals(other._witnesses[i]))
 1154                return false;
 155        }
 156
 244157        return true;
 158    }
 159
 160    /// <inheritdoc/>
 13161    public override bool Equals(object? obj) => Equals(obj as NavigationConnection);
 162
 163    /// <inheritdoc/>
 164    public override int GetHashCode()
 165    {
 6166        int idHash = SwiftHashTools.GetDeterministicStringEqualityComparer().GetHashCode(Id);
 6167        int hash = SwiftHashTools.CombineHashCodes(idHash, SourceIndex.GetHashCode());
 6168        hash = SwiftHashTools.CombineHashCodes(hash, Destination.GetHashCode());
 6169        hash = SwiftHashTools.CombineHashCodes(hash, EntryAnchor.GetHashCode());
 6170        hash = SwiftHashTools.CombineHashCodes(hash, ExitAnchor.GetHashCode());
 6171        hash = SwiftHashTools.CombineHashCodes(hash, PortalRadiusClearance.GetHashCode());
 6172        hash = SwiftHashTools.CombineHashCodes(hash, PortalHeightClearance.GetHashCode());
 6173        hash = SwiftHashTools.CombineHashCodes(hash, AdditionalCost.GetHashCode());
 6174        hash = SwiftHashTools.CombineHashCodes(hash, IsLowerBoundCertified ? 1 : 0);
 20175        for (int i = 0; i < _witnesses.Length; i++)
 4176            hash = SwiftHashTools.CombineHashCodes(hash, _witnesses[i].GetHashCode());
 6177        return hash;
 178    }
 179
 180    private static NavigationCellAddress[] CopyWitnesses(
 181        IEnumerable<NavigationCellAddress>? witnesses)
 182    {
 4549183        if (witnesses == null)
 4335184            return Array.Empty<NavigationCellAddress>();
 185
 214186        if (witnesses is ICollection<NavigationCellAddress> collection)
 187        {
 202188            var copy = new NavigationCellAddress[collection.Count];
 202189            collection.CopyTo(copy, 0);
 202190            return copy;
 191        }
 192
 12193        var values = new SwiftCollections.SwiftList<NavigationCellAddress>();
 72194        foreach (NavigationCellAddress witness in witnesses)
 24195            values.Add(witness);
 12196        return values.ToArray();
 197    }
 198}