mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Use functor for Kdtree's XYFunc. (#13074)
Kdtree uses a function pointer and incorrectly calls it a functor. The function pointer needs to be passed on instantiaton. Instead, use an actual functor. This simplifies instantiation.pull/13094/head
parent
369ea29e1e
commit
fc8685d618
|
@ -47,7 +47,6 @@ class Kdtree {
|
||||||
std::vector<node> nodes; ///< Pool of all nodes in the tree
|
std::vector<node> nodes; ///< Pool of all nodes in the tree
|
||||||
std::vector<size_t> free_list; ///< List of dead indices in the nodes vector
|
std::vector<size_t> free_list; ///< List of dead indices in the nodes vector
|
||||||
size_t root; ///< Index of root node
|
size_t root; ///< Index of root node
|
||||||
TxyFunc xyfunc; ///< Functor to extract a coordinate from an element
|
|
||||||
size_t unbalanced; ///< Number approximating how unbalanced the tree might be
|
size_t unbalanced; ///< Number approximating how unbalanced the tree might be
|
||||||
|
|
||||||
/** Create one new node in the tree, return its index in the pool */
|
/** Create one new node in the tree, return its index in the pool */
|
||||||
|
@ -69,8 +68,8 @@ class Kdtree {
|
||||||
CoordT SelectSplitCoord(It begin, It end, int level)
|
CoordT SelectSplitCoord(It begin, It end, int level)
|
||||||
{
|
{
|
||||||
It mid = begin + (end - begin) / 2;
|
It mid = begin + (end - begin) / 2;
|
||||||
std::nth_element(begin, mid, end, [&](T a, T b) { return this->xyfunc(a, level % 2) < this->xyfunc(b, level % 2); });
|
std::nth_element(begin, mid, end, [&](T a, T b) { return TxyFunc()(a, level % 2) < TxyFunc()(b, level % 2); });
|
||||||
return this->xyfunc(*mid, level % 2);
|
return TxyFunc()(*mid, level % 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Construct a subtree from elements between begin and end iterators, return index of root */
|
/** Construct a subtree from elements between begin and end iterators, return index of root */
|
||||||
|
@ -85,7 +84,7 @@ class Kdtree {
|
||||||
return this->AddNode(*begin);
|
return this->AddNode(*begin);
|
||||||
} else if (count > 1) {
|
} else if (count > 1) {
|
||||||
CoordT split_coord = SelectSplitCoord(begin, end, level);
|
CoordT split_coord = SelectSplitCoord(begin, end, level);
|
||||||
It split = std::partition(begin, end, [&](T v) { return this->xyfunc(v, level % 2) < split_coord; });
|
It split = std::partition(begin, end, [&](T v) { return TxyFunc()(v, level % 2) < split_coord; });
|
||||||
size_t newidx = this->AddNode(*split);
|
size_t newidx = this->AddNode(*split);
|
||||||
this->nodes[newidx].left = this->BuildSubtree(begin, split, level + 1);
|
this->nodes[newidx].left = this->BuildSubtree(begin, split, level + 1);
|
||||||
this->nodes[newidx].right = this->BuildSubtree(split + 1, end, level + 1);
|
this->nodes[newidx].right = this->BuildSubtree(split + 1, end, level + 1);
|
||||||
|
@ -129,9 +128,9 @@ class Kdtree {
|
||||||
node &n = this->nodes[node_idx];
|
node &n = this->nodes[node_idx];
|
||||||
|
|
||||||
/* Coordinate of element splitting at this node */
|
/* Coordinate of element splitting at this node */
|
||||||
CoordT nc = this->xyfunc(n.element, dim);
|
CoordT nc = TxyFunc()(n.element, dim);
|
||||||
/* Coordinate of the new element */
|
/* Coordinate of the new element */
|
||||||
CoordT ec = this->xyfunc(element, dim);
|
CoordT ec = TxyFunc()(element, dim);
|
||||||
/* Which side to insert on */
|
/* Which side to insert on */
|
||||||
size_t &next = (ec < nc) ? n.left : n.right;
|
size_t &next = (ec < nc) ? n.left : n.right;
|
||||||
|
|
||||||
|
@ -202,9 +201,9 @@ class Kdtree {
|
||||||
/* Dimension index of current level */
|
/* Dimension index of current level */
|
||||||
int dim = level % 2;
|
int dim = level % 2;
|
||||||
/* Coordinate of element splitting at this node */
|
/* Coordinate of element splitting at this node */
|
||||||
CoordT nc = this->xyfunc(n.element, dim);
|
CoordT nc = TxyFunc()(n.element, dim);
|
||||||
/* Coordinate of the element being removed */
|
/* Coordinate of the element being removed */
|
||||||
CoordT ec = this->xyfunc(element, dim);
|
CoordT ec = TxyFunc()(element, dim);
|
||||||
/* Which side to remove from */
|
/* Which side to remove from */
|
||||||
size_t next = (ec < nc) ? n.left : n.right;
|
size_t next = (ec < nc) ? n.left : n.right;
|
||||||
assert(next != INVALID_NODE); // node must exist somewhere and must be found before a leaf is reached
|
assert(next != INVALID_NODE); // node must exist somewhere and must be found before a leaf is reached
|
||||||
|
@ -222,7 +221,7 @@ class Kdtree {
|
||||||
|
|
||||||
DistT ManhattanDistance(const T &element, CoordT x, CoordT y) const
|
DistT ManhattanDistance(const T &element, CoordT x, CoordT y) const
|
||||||
{
|
{
|
||||||
return abs((DistT)this->xyfunc(element, 0) - (DistT)x) + abs((DistT)this->xyfunc(element, 1) - (DistT)y);
|
return abs((DistT)TxyFunc()(element, 0) - (DistT)x) + abs((DistT)TxyFunc()(element, 1) - (DistT)y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A data element and its distance to a searched-for point */
|
/** A data element and its distance to a searched-for point */
|
||||||
|
@ -245,7 +244,7 @@ class Kdtree {
|
||||||
const node &n = this->nodes[node_idx];
|
const node &n = this->nodes[node_idx];
|
||||||
|
|
||||||
/* Coordinate of element splitting at this node */
|
/* Coordinate of element splitting at this node */
|
||||||
CoordT c = this->xyfunc(n.element, dim);
|
CoordT c = TxyFunc()(n.element, dim);
|
||||||
/* This node's distance to target */
|
/* This node's distance to target */
|
||||||
DistT thisdist = ManhattanDistance(n.element, xy[0], xy[1]);
|
DistT thisdist = ManhattanDistance(n.element, xy[0], xy[1]);
|
||||||
/* Assume this node is the best choice for now */
|
/* Assume this node is the best choice for now */
|
||||||
|
@ -280,9 +279,9 @@ class Kdtree {
|
||||||
const node &n = this->nodes[node_idx];
|
const node &n = this->nodes[node_idx];
|
||||||
|
|
||||||
/* Coordinate of element splitting at this node */
|
/* Coordinate of element splitting at this node */
|
||||||
CoordT ec = this->xyfunc(n.element, dim);
|
CoordT ec = TxyFunc()(n.element, dim);
|
||||||
/* Opposite coordinate of element */
|
/* Opposite coordinate of element */
|
||||||
CoordT oc = this->xyfunc(n.element, 1 - dim);
|
CoordT oc = TxyFunc()(n.element, 1 - dim);
|
||||||
|
|
||||||
/* Test if this element is within rectangle */
|
/* Test if this element is within rectangle */
|
||||||
if (ec >= p1[dim] && ec < p2[dim] && oc >= p1[1 - dim] && oc < p2[1 - dim]) outputter(n.element);
|
if (ec >= p1[dim] && ec < p2[dim] && oc >= p1[1 - dim] && oc < p2[1 - dim]) outputter(n.element);
|
||||||
|
@ -321,8 +320,8 @@ class Kdtree {
|
||||||
if (node_idx == INVALID_NODE) return;
|
if (node_idx == INVALID_NODE) return;
|
||||||
|
|
||||||
const node &n = this->nodes[node_idx];
|
const node &n = this->nodes[node_idx];
|
||||||
CoordT cx = this->xyfunc(n.element, 0);
|
CoordT cx = TxyFunc()(n.element, 0);
|
||||||
CoordT cy = this->xyfunc(n.element, 1);
|
CoordT cy = TxyFunc()(n.element, 1);
|
||||||
|
|
||||||
assert(cx >= min_x);
|
assert(cx >= min_x);
|
||||||
assert(cx < max_x);
|
assert(cx < max_x);
|
||||||
|
@ -350,7 +349,7 @@ class Kdtree {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Construct a new Kdtree with the given xyfunc */
|
/** Construct a new Kdtree with the given xyfunc */
|
||||||
Kdtree(TxyFunc xyfunc) : root(INVALID_NODE), xyfunc(xyfunc), unbalanced(0) { }
|
Kdtree() : root(INVALID_NODE), unbalanced(0) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear and rebuild the tree from a new sequence of elements,
|
* Clear and rebuild the tree from a new sequence of elements,
|
||||||
|
|
|
@ -36,7 +36,7 @@ StationPool _station_pool("Station");
|
||||||
INSTANTIATE_POOL_METHODS(Station)
|
INSTANTIATE_POOL_METHODS(Station)
|
||||||
|
|
||||||
|
|
||||||
StationKdtree _station_kdtree(Kdtree_StationXYFunc);
|
StationKdtree _station_kdtree{};
|
||||||
|
|
||||||
void RebuildStationKdtree()
|
void RebuildStationKdtree()
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,8 +15,14 @@
|
||||||
#include "station_base.h"
|
#include "station_base.h"
|
||||||
#include "map_func.h"
|
#include "map_func.h"
|
||||||
|
|
||||||
inline uint16_t Kdtree_StationXYFunc(StationID stid, int dim) { return (dim == 0) ? TileX(BaseStation::Get(stid)->xy) : TileY(BaseStation::Get(stid)->xy); }
|
struct Kdtree_StationXYFunc {
|
||||||
typedef Kdtree<StationID, decltype(&Kdtree_StationXYFunc), uint16_t, int> StationKdtree;
|
inline uint16_t operator()(StationID stid, int dim)
|
||||||
|
{
|
||||||
|
return (dim == 0) ? TileX(BaseStation::Get(stid)->xy) : TileY(BaseStation::Get(stid)->xy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using StationKdtree = Kdtree<StationID, Kdtree_StationXYFunc, uint16_t, int>;
|
||||||
extern StationKdtree _station_kdtree;
|
extern StationKdtree _station_kdtree;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -68,7 +68,7 @@ TownPool _town_pool("Town");
|
||||||
INSTANTIATE_POOL_METHODS(Town)
|
INSTANTIATE_POOL_METHODS(Town)
|
||||||
|
|
||||||
|
|
||||||
TownKdtree _town_kdtree(&Kdtree_TownXYFunc);
|
TownKdtree _town_kdtree{};
|
||||||
|
|
||||||
void RebuildTownKdtree()
|
void RebuildTownKdtree()
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
TownKdtree _town_local_authority_kdtree(&Kdtree_TownXYFunc);
|
TownKdtree _town_local_authority_kdtree{};
|
||||||
|
|
||||||
typedef GUIList<const Town*, const bool &> GUITownList;
|
typedef GUIList<const Town*, const bool &> GUITownList;
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,14 @@
|
||||||
#include "core/kdtree.hpp"
|
#include "core/kdtree.hpp"
|
||||||
#include "town.h"
|
#include "town.h"
|
||||||
|
|
||||||
inline uint16_t Kdtree_TownXYFunc(TownID tid, int dim) { return (dim == 0) ? TileX(Town::Get(tid)->xy) : TileY(Town::Get(tid)->xy); }
|
struct Kdtree_TownXYFunc {
|
||||||
typedef Kdtree<TownID, decltype(&Kdtree_TownXYFunc), uint16_t, int> TownKdtree;
|
inline uint16_t operator()(TownID tid, int dim)
|
||||||
|
{
|
||||||
|
return (dim == 0) ? TileX(Town::Get(tid)->xy) : TileY(Town::Get(tid)->xy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using TownKdtree = Kdtree<TownID, Kdtree_TownXYFunc, uint16_t, int>;
|
||||||
extern TownKdtree _town_kdtree;
|
extern TownKdtree _town_kdtree;
|
||||||
extern TownKdtree _town_local_authority_kdtree;
|
extern TownKdtree _town_local_authority_kdtree;
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
Point _tile_fract_coords;
|
Point _tile_fract_coords;
|
||||||
|
|
||||||
|
|
||||||
ViewportSignKdtree _viewport_sign_kdtree(&Kdtree_ViewportSignXYFunc);
|
ViewportSignKdtree _viewport_sign_kdtree{};
|
||||||
static int _viewport_sign_maxwidth = 0;
|
static int _viewport_sign_maxwidth = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -70,12 +70,14 @@ struct ViewportSignKdtreeItem {
|
||||||
static ViewportSignKdtreeItem MakeSign(SignID id);
|
static ViewportSignKdtreeItem MakeSign(SignID id);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int32_t Kdtree_ViewportSignXYFunc(const ViewportSignKdtreeItem &item, int dim)
|
struct Kdtree_ViewportSignXYFunc {
|
||||||
{
|
inline int32_t operator()(const ViewportSignKdtreeItem &item, int dim)
|
||||||
return (dim == 0) ? item.center : item.top;
|
{
|
||||||
}
|
return (dim == 0) ? item.center : item.top;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
typedef Kdtree<ViewportSignKdtreeItem, decltype(&Kdtree_ViewportSignXYFunc), int32_t, int32_t> ViewportSignKdtree;
|
using ViewportSignKdtree = Kdtree<ViewportSignKdtreeItem, Kdtree_ViewportSignXYFunc, int32_t, int32_t>;
|
||||||
extern ViewportSignKdtree _viewport_sign_kdtree;
|
extern ViewportSignKdtree _viewport_sign_kdtree;
|
||||||
|
|
||||||
void RebuildViewportKdtree();
|
void RebuildViewportKdtree();
|
||||||
|
|
Loading…
Reference in New Issue