< Summary

Class:KDTree[T]
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/Utils/KDTree.cs
Covered lines:51
Uncovered lines:0
Coverable lines:51
Total lines:97
Line coverage:100% (51 of 51)
Covered branches:0
Total branches:0
Covered methods:4
Total methods:4
Method coverage:100% (4 of 4)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
KDTree(...)0%110100%
NearestNeighbor(...)0%220100%
NearestNeighbor(...)0%12120100%
BuildTree(...)0%220100%

File(s)

/github/workspace/Assets/Scripts/Utils/KDTree.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using UnityEngine;
 5
 6// K-D tree node.
 7public class KDNode<T> {
 8  public T Data { get; internal set; }
 9  public KDNode<T> Left { get; internal set; }
 10  public KDNode<T> Right { get; internal set; }
 11}
 12
 13// K-D tree with 2D coordinates.
 14public class KDTree<T> {
 15  // Root node.
 16  private KDNode<T> _root;
 17
 18  // Function to get the coordinates from the tree elements.
 19  private Func<T, Vector2> _getCoordinates;
 20
 5621  public KDTree(IReadOnlyList<T> points, Func<T, Vector2> getCoordinates) {
 2822    _getCoordinates = getCoordinates;
 2823    _root = BuildTree(points, depth: 0);
 2824  }
 25
 26  // Find the nearest neighbor to the target node.
 5727  public T NearestNeighbor(in Vector2 target) {
 5728    KDNode<T> neighbor = NearestNeighbor(_root, target, depth: 0, bestNode: null);
 6129    if (neighbor == null) {
 430      return default(T);
 31    }
 5332    return neighbor.Data;
 5733  }
 34
 35  // Find the nearest neighbor to the target node.
 36  private KDNode<T> NearestNeighbor(KDNode<T> node, in Vector2 target, int depth,
 32137                                    KDNode<T> bestNode) {
 42438    if (node == null) {
 10339      return bestNode;
 40    }
 41
 21842    Vector2 nodeCoordinates = _getCoordinates(node.Data);
 21843    float currentDistance = Vector2.Distance(nodeCoordinates, target);
 21844    float bestDistance = bestNode == null
 45                             ? float.MaxValue
 46                             : Vector2.Distance(_getCoordinates(bestNode.Data), target);
 36447    if (currentDistance < bestDistance) {
 14648      bestNode = node;
 14649      bestDistance = currentDistance;
 14650    }
 51
 21852    int axis = depth % 2;
 21853    float targetCoordinatesValue = axis == 0 ? target.x : target.y;
 21854    float nodeCoordinatesValue = axis == 0 ? nodeCoordinates.x : nodeCoordinates.y;
 21855    KDNode<T> nextBranch = targetCoordinatesValue < nodeCoordinatesValue ? node.Left : node.Right;
 21856    KDNode<T> otherBranch = targetCoordinatesValue < nodeCoordinatesValue ? node.Right : node.Left;
 57
 58    // Explore the next branch first.
 21859    bestNode = NearestNeighbor(nextBranch, target, depth + 1, bestNode);
 43660    if (bestNode != null) {
 21861      bestDistance = Vector2.Distance(_getCoordinates(bestNode.Data), target);
 21862      ;
 21863    }
 64
 65    // Explore the other branch.
 26466    if (Mathf.Abs(targetCoordinatesValue - nodeCoordinatesValue) < bestDistance) {
 4667      bestNode = NearestNeighbor(otherBranch, target, depth + 1, bestNode);
 4668    }
 21869    return bestNode;
 32170  }
 71
 72  // Construct a tree from the list of points.
 171673  private KDNode<T> BuildTree(IReadOnlyList<T> points, int depth) {
 258874    if (points.Count == 0) {
 87275      return null;
 76    }
 77
 84478    int k = 2;
 84479    int axis = depth % k;
 80
 81    // Sort the points by axis and find the median.
 84482    List<T> sortedPoints =
 482283        points.OrderBy(point => (axis == 0 ? _getCoordinates(point).x : _getCoordinates(point).y))
 84            .ToList();
 84485    int medianIndex = sortedPoints.Count / 2;
 84486    T medianPoint = sortedPoints[medianIndex];
 87
 84488    var node = new KDNode<T> { Data = medianPoint };
 84489    List<T> leftPoints = sortedPoints.GetRange(0, medianIndex);
 84490    List<T> rightPoints =
 91        sortedPoints.GetRange(medianIndex + 1, sortedPoints.Count - medianIndex - 1);
 92
 84493    node.Left = BuildTree(leftPoints, depth + 1);
 84494    node.Right = BuildTree(rightPoints, depth + 1);
 84495    return node;
 171696  }
 97}