31 #ifndef LSST_AP_CLUSTER_DETAIL_KDTREE_CC
32 #define LSST_AP_CLUSTER_DETAIL_KDTREE_CC
40 namespace lsst {
namespace ap {
namespace cluster {
namespace detail {
54 template <
int K,
typename DataT>
55 std::pair<double, int> maxExtentAndDim(
Point<K, DataT> const *
const points,
58 typedef Eigen::Matrix<double, K, 1> Vector;
62 for (
int d = 0;
d < K; ++
d) {
63 minv[
d] = std::numeric_limits<double>::infinity();
64 maxv[
d] = -std::numeric_limits<double>::infinity();
66 for (
int i = 0; i < numPoints; ++i) {
67 Vector
const & v = points[i].
coords;
68 for (
int d = 0;
d < K; ++
d) {
73 double maxExtent = maxv[0] - minv[0];
75 for (
int d = 1;
d < K; ++
d) {
76 double extent = maxv[
d] - minv[
d];
77 if (extent > maxExtent) {
82 return std::make_pair(maxExtent, maxD);
91 PointCmp(
int dim) :
d(dim) { }
93 template <
int K,
typename DataT>
94 bool operator()(Point<K, DataT>
const & p1, Point<K, DataT>
const & p2)
const {
95 return p1.coords.coeff(
d) < p2.coords.coeff(
d);
114 template <
int K,
typename DataT>
118 double leafExtentThreshold) :
120 _numPoints(numPoints),
124 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
125 "pointer to Point array is null");
127 if (numPoints <= 0) {
128 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
129 "number of input points must be > 0");
131 if (pointsPerLeaf < 1) {
132 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
133 "target number of points per leaf must be > 0");
137 for (; h <
MAX_HEIGHT && numPoints / (1 << h) > pointsPerLeaf; ++h) { }
139 int n = (1 << (h + 1)) - 1;
141 boost::scoped_array<KDTreeNode> nodes(
new KDTreeNode[n]);
144 build(leafExtentThreshold);
147 template <
int K,
typename DataT>
166 template <
int K,
typename DataT>
167 template <
typename MetricT>
170 MetricT
const & metric)
172 bool descend[MAX_HEIGHT];
178 if (_nodes[node].splitDim == -1) {
181 int right = _nodes[node].right;
182 if ((node & (node + 1)) != 0) {
185 left = _nodes[node - 1].right;
187 for (
int i = left; i < right; ++i) {
188 _points[i].dist = metric(v, _points[i].coords);
191 for (
int i = left; i < right; ++i) {
192 if (_points[i].dist <= dist) {
196 _points[tail].next = i;
202 node = (node - 1) >> 1;
204 for (; h >= 0 && !descend[h]; --h) {
205 node = (node - 1) >> 1;
212 node = (node << 1) + 2;
216 double split = _nodes[node].split;
217 double vd = v.coeff(_nodes[node].splitDim);
218 if (metric(vd, split) <= dist) {
221 node = (node << 1) + 1;
223 }
else if (vd < split) {
226 node = (node << 1) + 1;
231 node = (node << 1) + 2;
242 template <
int K,
typename DataT>
247 int right = _numPoints;
250 _nodes[node].right = right;
253 std::pair<double, int> extDim = maxExtentAndDim(_points + left,
255 if (extDim.first > leafExtentThreshold) {
256 _nodes[node].splitDim = extDim.second;
258 int median = left + ((right - left) >> 1);
259 std::nth_element(_points + left, _points + median,
260 _points + right, PointCmp(extDim.second));
262 _nodes[node].split = _points[right].coords.coeff(extDim.second);
264 node = (node << 1) + 1;
275 _nodes[c].right = right;
276 }
while (h2 < _height);
280 for (; h > 0 && (node & 1) == 0; --h) {
281 node = (node - 1) >> 1;
288 right = _nodes[(node - 1) >> 1].right;
295 #endif // LSST_AP_CLUSTER_DETAIL_KDTREE_CC
void swap(Ellipse< DataT > &a, Ellipse< DataT > &b)
void swap(ImageBase< PixelT > &a, ImageBase< PixelT > &b)
Low-level k-d tree class used by the OPTICS implementation.
std::vector< SourceCatalog > const cluster(SourceCatalog const &sources, ClusteringControl const &control)
boost::scoped_array< KDTreeNode > _nodes
Eigen::Matrix< double, K, 1 > coords
Point coordinates.
int inRange(Vector const &v, double const distance, MetricT const &metric)
KDTree(Point< K, DataT > *points, int numPoints, int pointsPerLeaf, double leafExtentThreshold)
void build(double leafExtentThreshold)
#define LSST_EXCEPT(type,...)
Eigen::Matrix< double, K, 1 > Vector
static int const MAX_HEIGHT
Maximum tree height.