#include "distance_base.h" struct PlainDist1D { static inline const double side_distance_from_min_max( const ckdtree * tree, const double x, const double min, const double max, const ckdtree_intp_t k ) { double s, t; s = 0; t = x - max; if (t > s) { s = t; } else { t = min - x; if (t > s) s = t; } return s; } static inline void interval_interval(const ckdtree * tree, const Rectangle& rect1, const Rectangle& rect2, const ckdtree_intp_t k, double *min, double *max) { /* Compute the minimum/maximum distance along dimension k between points in * two hyperrectangles. */ *min = ckdtree_fmax(0., fmax(rect1.mins()[k] - rect2.maxes()[k], rect2.mins()[k] - rect1.maxes()[k])); *max = ckdtree_fmax(rect1.maxes()[k] - rect2.mins()[k], rect2.maxes()[k] - rect1.mins()[k]); } static inline double point_point(const ckdtree * tree, const double *x, const double *y, const ckdtree_intp_t k) { return ckdtree_fabs(x[k] - y[k]); } }; typedef BaseMinkowskiDistPp MinkowskiDistPp; typedef BaseMinkowskiDistPinf MinkowskiDistPinf; typedef BaseMinkowskiDistP1 MinkowskiDistP1; typedef BaseMinkowskiDistP2 NonOptimizedMinkowskiDistP2; /* * Measuring distances * =================== */ inline double sqeuclidean_distance_double(const double *u, const double *v, ckdtree_intp_t n) { double s; ckdtree_intp_t i = 0; // manually unrolled loop, might be vectorized double acc[4] = {0., 0., 0., 0.}; for (; i + 4 <= n; i += 4) { double _u[4] = {u[i], u[i + 1], u[i + 2], u[i + 3]}; double _v[4] = {v[i], v[i + 1], v[i + 2], v[i + 3]}; double diff[4] = {_u[0] - _v[0], _u[1] - _v[1], _u[2] - _v[2], _u[3] - _v[3]}; acc[0] += diff[0] * diff[0]; acc[1] += diff[1] * diff[1]; acc[2] += diff[2] * diff[2]; acc[3] += diff[3] * diff[3]; } s = acc[0] + acc[1] + acc[2] + acc[3]; if (i < n) { for(; i= 0) { /* do not pass though 0 */ min = ckdtree_fabs(min); max = ckdtree_fabs(max); if(min < max) { *realmin = min; *realmax = max; } else { *realmin = max; *realmax = min; } } else { min = ckdtree_fabs(min); max = ckdtree_fabs(max); *realmax = ckdtree_fmax(max, min); *realmin = 0; } /* done with non-periodic dimension */ return; } if(max <= 0 || min >= 0) { /* do not pass through 0 */ min = ckdtree_fabs(min); max = ckdtree_fabs(max); if(min > max) { double t = min; min = max; max = t; } if(max < half) { /* all below half*/ *realmin = min; *realmax = max; } else if(min > half) { /* all above half */ *realmax = full - min; *realmin = full - max; } else { /* min below, max above */ *realmax = half; *realmin = ckdtree_fmin(min, full - max); } } else { /* pass though 0 */ min = -min; if(min > max) max = min; if(max > half) max = half; *realmax = max; *realmin = 0; } } static inline void interval_interval(const ckdtree * tree, const Rectangle& rect1, const Rectangle& rect2, const ckdtree_intp_t k, double *min, double *max) { /* Compute the minimum/maximum distance along dimension k between points in * two hyperrectangles. */ _interval_interval_1d(rect1.mins()[k] - rect2.maxes()[k], rect1.maxes()[k] - rect2.mins()[k], min, max, tree->raw_boxsize_data[k], tree->raw_boxsize_data[k + rect1.m]); } static inline double point_point(const ckdtree * tree, const double *x, const double *y, const ckdtree_intp_t k) { double r1; r1 = wrap_distance(x[k] - y[k], tree->raw_boxsize_data[k + tree->m], tree->raw_boxsize_data[k]); r1 = ckdtree_fabs(r1); return r1; } static inline const double wrap_position(const double x, const double boxsize) { if (boxsize <= 0) return x; const double r = std::floor(x / boxsize); double x1 = x - r * boxsize; /* ensure result is within the box. */ while(x1 >= boxsize) x1 -= boxsize; while(x1 < 0) x1 += boxsize; return x1; } static inline const double side_distance_from_min_max( const ckdtree * tree, const double x, const double min, const double max, const ckdtree_intp_t k ) { double s, t, tmin, tmax; double fb = tree->raw_boxsize_data[k]; double hb = tree->raw_boxsize_data[k + tree->m]; if (fb <= 0) { /* non-periodic dimension */ s = PlainDist1D::side_distance_from_min_max(tree, x, min, max, k); return s; } /* periodic */ s = 0; tmax = x - max; tmin = x - min; /* is the test point in this range */ if(CKDTREE_LIKELY(tmax < 0 && tmin > 0)) { /* yes. min distance is 0 */ return 0; } /* no */ tmax = ckdtree_fabs(tmax); tmin = ckdtree_fabs(tmin); /* make tmin the closer edge */ if(tmin > tmax) { t = tmin; tmin = tmax; tmax = t; } /* both edges are less than half a box. */ /* no wrapping, use the closer edge */ if(tmax < hb) return tmin; /* both edge are more than half a box. */ /* wrapping on both edge, use the * wrapped further edge */ if(tmin > hb) return fb - tmax; /* the further side is wrapped */ tmax = fb - tmax; if(tmin > tmax) return tmax; return tmin; } private: static inline double wrap_distance(const double x, const double hb, const double fb) { double x1; if (CKDTREE_UNLIKELY(x < -hb)) x1 = fb + x; else if (CKDTREE_UNLIKELY(x > hb)) x1 = x - fb; else x1 = x; #if 0 printf("ckdtree_fabs_b x : %g x1 %g\n", x, x1); #endif return x1; } }; typedef BaseMinkowskiDistPp BoxMinkowskiDistPp; typedef BaseMinkowskiDistPinf BoxMinkowskiDistPinf; typedef BaseMinkowskiDistP1 BoxMinkowskiDistP1; typedef BaseMinkowskiDistP2 BoxMinkowskiDistP2;