< Summary

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
KDTree(...)0%2100%
NearestNeighbor(...)0%6200%
NearestNeighbor(...)0%1561200%
BuildTree(...)0%6200%

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
 021  public KDTree(IReadOnlyList<T> points, Func<T, Vector2> getCoordinates) {
 022    _getCoordinates = getCoordinates;
 023    _root = BuildTree(points, depth: 0);
 024  }
 25
 26  // Find the nearest neighbor to the target node.
 027  public T NearestNeighbor(in Vector2 target) {
 028    KDNode<T> neighbor = NearestNeighbor(_root, target, depth: 0, bestNode: null);
 029    if (neighbor == null) {
 030      return default(T);
 31    }
 032    return neighbor.Data;
 033  }
 34
 35  // Find the nearest neighbor to the target node.
 36  private KDNode<T> NearestNeighbor(KDNode<T> node, in Vector2 target, int depth,
 037                                    KDNode<T> bestNode) {
 038    if (node == null) {
 039      return bestNode;
 40    }
 41
 042    Vector2 nodeCoordinates = _getCoordinates(node.Data);
 043    float currentDistance = Vector2.Distance(nodeCoordinates, target);
 044    float bestDistance = bestNode == null
 45                             ? float.MaxValue
 46                             : Vector2.Distance(_getCoordinates(bestNode.Data), target);
 047    if (currentDistance < bestDistance) {
 048      bestNode = node;
 049      bestDistance = currentDistance;
 050    }
 51
 052    int axis = depth % 2;
 053    float targetCoordinatesValue = axis == 0 ? target.x : target.y;
 054    float nodeCoordinatesValue = axis == 0 ? nodeCoordinates.x : nodeCoordinates.y;
 055    KDNode<T> nextBranch = targetCoordinatesValue < nodeCoordinatesValue ? node.Left : node.Right;
 056    KDNode<T> otherBranch = targetCoordinatesValue < nodeCoordinatesValue ? node.Right : node.Left;
 57
 58    // Explore the next branch first.
 059    bestNode = NearestNeighbor(nextBranch, target, depth + 1, bestNode);
 060    if (bestNode != null) {
 061      bestDistance = Vector2.Distance(_getCoordinates(bestNode.Data), target);
 062      ;
 063    }
 64
 65    // Explore the other branch.
 066    if (Mathf.Abs(targetCoordinatesValue - nodeCoordinatesValue) < bestDistance) {
 067      bestNode = NearestNeighbor(otherBranch, target, depth + 1, bestNode);
 068    }
 069    return bestNode;
 070  }
 71
 72  // Construct a tree from the list of points.
 073  private KDNode<T> BuildTree(IReadOnlyList<T> points, int depth) {
 074    if (points.Count == 0) {
 075      return null;
 76    }
 77
 078    int k = 2;
 079    int axis = depth % k;
 80
 81    // Sort the points by axis and find the median.
 082    List<T> sortedPoints =
 083        points.OrderBy(point => (axis == 0 ? _getCoordinates(point).x : _getCoordinates(point).y))
 84            .ToList();
 085    int medianIndex = sortedPoints.Count / 2;
 086    T medianPoint = sortedPoints[medianIndex];
 87
 088    var node = new KDNode<T> { Data = medianPoint };
 089    List<T> leftPoints = sortedPoints.GetRange(0, medianIndex);
 090    List<T> rightPoints =
 91        sortedPoints.GetRange(medianIndex + 1, sortedPoints.Count - medianIndex - 1);
 92
 093    node.Left = BuildTree(leftPoints, depth + 1);
 094    node.Right = BuildTree(rightPoints, depth + 1);
 095    return node;
 096  }
 97}