IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 25180


Ignore:
Timestamp:
Aug 24, 2009, 5:38:47 PM (17 years ago)
Author:
Paul Price
Message:

Adding ability to calculate great circle distances when required. This required a change to the API for psTreePlant, which I have not yet propagated. Also added function to return the indices of all points within some distance.

Location:
branches/pap_mops/psLib/src/types
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/pap_mops/psLib/src/types/psTree.c

    r18344 r25180  
    1414#include "psTree.h"
    1515
     16//#define INPUT_CHECK                   // Check inputs for functions that may be in a tight loop?
     17
    1618
    1719// XXX Upgrades:
     
    8486}
    8587
    86 psTree *psTreeAlloc(int dim, int maxLeafContents, long numNodes)
     88psTree *psTreeAlloc(int dim, int maxLeafContents, psTreeType type, long numNodes)
    8789{
    8890    psAssert(dim > 0, "Dimensionality (%d) must be positive", dim);
     
    9597    tree->dim = dim;
    9698    tree->maxLeafContents = maxLeafContents;
     99    tree->type = type;
    97100
    98101    tree->numNodes = numNodes;
     
    115118
    116119
    117 psTree *psTreePlant(int dim, int maxLeafContents, ...)
     120psTree *psTreePlant(int dim, int maxLeafContents, psTreeType type, ...)
    118121{
    119122    PS_ASSERT_INT_POSITIVE(dim, NULL);
     
    122125    // Parse coordinate list
    123126    va_list args;                       // Variable argument list
    124     va_start(args, maxLeafContents);
     127    va_start(args, type);
    125128    psArray *coords = psArrayAlloc(dim); // Array of coordinates
    126129    long numData = 0;                   // Number of data points
     
    148151    }
    149152
    150     psTree *tree = psTreeAlloc(dim, maxLeafContents, numNodes);
     153    psTree *tree = psTreeAlloc(dim, maxLeafContents, type, numNodes);
    151154    tree->data = psTreeCoordArrayAlloc(numData, dim);
    152155    tree->numData = numData;
     
    365368psTreeNode *psTreeLeaf(const psTree *tree, const psVector *coords)
    366369{
    367 #if 1 // Might be in a tight loop
     370#ifdef INPUT_CHECK // Might be in a tight loop
    368371    PS_ASSERT_TREE_NON_NULL(tree, NULL);
    369372    PS_ASSERT_VECTOR_NON_NULL(coords, NULL);
     
    403406{
    404407    int dim = tree->dim;                // Dimensionality
    405     switch (dim) {
    406       case 2:
    407         return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
    408             PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]);
    409       case 3:
    410         return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
    411             PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]) +
    412             PS_SQR(coords->data.F64[2] - tree->data->F64[index][2]);
    413       default: {
    414           double distance2 = 0.0;             // Distance of interest
    415           for (int i = 0; i < dim; i++) {
    416               distance2 += PS_SQR(coords->data.F64[i] - tree->data->F64[index][i]);
     408    switch (tree->type) {
     409      case PS_TREE_EUCLIDEAN:
     410        switch (dim) {
     411          case 2:
     412            return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
     413                PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]);
     414          case 3:
     415            return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
     416                PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]) +
     417                PS_SQR(coords->data.F64[2] - tree->data->F64[index][2]);
     418          default: {
     419              double distance2 = 0.0;             // Distance of interest
     420              for (int i = 0; i < dim; i++) {
     421                  distance2 += PS_SQR(coords->data.F64[i] - tree->data->F64[index][i]);
     422              }
     423              return distance2;
    417424          }
    418           return distance2;
    419       }
    420     }
     425        }
     426        break;
     427      case PS_TREE_SPHERICAL:
     428        switch (dim) {
     429          case 2: {
     430              double dphi = coords->data.F64[0] - tree->data->F64[index][0];
     431              double dlambda = coords->data.F64[1] - tree->data->F64[index][1];
     432              double sindphi = sin(dphi / 2.0);
     433              double sindlambda = sin(dlambda / 2.0);
     434              return PS_SQR(sindphi) +
     435                  cos(coords->data.F64[0]) * cos(coords->data.F64[0]) * PS_SQR(sindlambda);
     436          }
     437          default:
     438            psAbort("Spherical distances not supported for more than 2 dimensions");
     439        }
     440      default:
     441        psAbort("Unrecognised type: %x", tree->type);
     442    }
     443
    421444    return NAN;
    422445}
     
    430453        double minDiff = tree->min->F64[index][i] - coords->data.F64[i];
    431454        if (minDiff > 0) {
    432             distance += PS_SQR(minDiff);
     455            switch (tree->type) {
     456              case PS_TREE_EUCLIDEAN:
     457                distance += PS_SQR(minDiff);
     458                break;
     459              case PS_TREE_SPHERICAL: {
     460                  double sinDiff = sin(minDiff / 2.0);
     461                  distance += PS_SQR(sinDiff);
     462                  break;
     463              }
     464              default:
     465                psAbort("Unrecognised type: %x", tree->type);
     466            }
    433467            continue;
    434468        }
    435469        double maxDiff = coords->data.F64[i] - tree->max->F64[index][i];
    436470        if (maxDiff > 0) {
    437             distance += PS_SQR(maxDiff);
     471            switch (tree->type) {
     472              case PS_TREE_EUCLIDEAN:
     473                distance += PS_SQR(maxDiff);
     474                break;
     475              case PS_TREE_SPHERICAL: {
     476                  double sinDiff = sin(maxDiff / 2.0);
     477                  distance += PS_SQR(sinDiff);
     478                  break;
     479              }
     480              default:
     481                psAbort("Unrecognised type: %x", tree->type);
     482            }
    438483            continue;
    439484        }
     
    479524}
    480525
    481 // Return the index of the nearest neighbour to given coordinates, within some radius
     526// Return the index of the nearest neighbour to given coordinates, within some distance measure
    482527// This is the engine for psTreeNearest() and psTreeNearestWithin()
    483528static inline long treeNearestWithin(const psTree *tree, // Tree
    484529                                     const psVector *coordinates, // Coordinates of interest
    485                                      double bestDistance // Distance (radius-squared) to best point
     530                                     double bestDistance // Distance measure to best point
    486531    )
    487532{
    488 #if 1 // Might be in a tight loop
     533#ifdef INPUT_CHECK // Might be in a tight loop
    489534    PS_ASSERT_TREE_NON_NULL(tree, -1);
    490535    PS_ASSERT_VECTOR_NON_NULL(coordinates, -1);
     
    545590
    546591
     592// Convert a radius to our internal "distance measure"
     593// Often, we're given a search radius, but for efficiency reasons, we don't use that internally.
     594static double treeRadiusToDistance(const psTree *tree, double radius)
     595{
     596    switch (tree->type) {
     597      case PS_TREE_EUCLIDEAN:
     598        // Using the square of the distance as the distance measure
     599        return PS_SQR(radius);
     600      case PS_TREE_SPHERICAL: {
     601          // Using a rearrangement of the Haversine formula
     602          double sindist = sin(radius / 2.0);
     603          return PS_SQR(sindist);
     604      }
     605      default:
     606        psAbort("Unrecognised type: %x", tree->type);
     607    }
     608}
     609
     610
    547611long psTreeNearestWithin(const psTree *tree, const psVector *coords, double radius)
    548612{
    549     return treeNearestWithin(tree, coords, PS_SQR(radius));
    550 }
    551 
    552 
    553 // Search a leaf node for points within radius squared
    554 static inline long treeLeafSearchWithin(double radius2, // Radius squared to search
     613    return treeNearestWithin(tree, coords, treeRadiusToDistance(tree, radius));
     614}
     615
     616
     617// Search a leaf node for points within distance
     618static inline long treeLeafSearchWithin(double distance, // Distance to search
    555619                                        const psTree *tree, // Tree of interest
    556620                                        const psTreeNode *leaf, // Leaf to search
     
    561625    for (int i = 0; i < leaf->num; i++) {
    562626        long index = leaf->contents[i]; // Index of point
    563         double distance = treeContentDistance(tree, index, coords); // Distance to point
    564         if (distance < radius2) {
     627        if (treeContentDistance(tree, index, coords) < distance) {
    565628            num++;
    566629        }
     
    572635long psTreeWithin(const psTree *tree, const psVector *coordinates, double radius)
    573636{
    574 #if 1 // Might be in a tight loop
     637#ifdef INPUT_CHECK // Might be in a tight loop
    575638    PS_ASSERT_TREE_NON_NULL(tree, -1);
    576639    PS_ASSERT_VECTOR_NON_NULL(coordinates, -1);
     
    581644                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
    582645
    583     radius *= radius;                   // We work with the radius-squared
     646    double distance = treeRadiusToDistance(tree, radius); // Distance measure
    584647    long num = 0;                       // Number of points in circle
    585648
     
    588651    // Find the closest point in the leaf that contains the point of interest
    589652    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
    590     num += treeLeafSearchWithin(radius, tree, leaf, coords);
     653    num += treeLeafSearchWithin(distance, tree, leaf, coords);
    591654
    592655    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     
    605668            }
    606669            // Leaf node
    607             num += treeLeafSearchWithin(radius, tree, node, coords);
     670            num += treeLeafSearchWithin(distance, tree, node, coords);
    608671            work->data[workIndex] = NULL;
    609672            workIndex--;
     
    618681}
    619682
    620 // Search a leaf node for any points within radius squared
    621 static inline bool treeLeafSearchWithinAny(double radius2, // Radius squared to search
    622                                            const psTree *tree, // Tree of interest
    623                                            const psTreeNode *leaf, // Leaf to search
    624                                            const psVector *coords // Coordinates of interest
     683// Search a leaf node for points within distance
     684static inline void treeLeafSearchAllWithin(psVector *result,       // Result vector
     685                                          double distance, // Distance to search
     686                                          const psTree *tree, // Tree of interest
     687                                          const psTreeNode *leaf, // Leaf to search
     688                                          const psVector *coords // Coordinates of interest
    625689    )
    626690{
    627691    for (int i = 0; i < leaf->num; i++) {
    628692        long index = leaf->contents[i]; // Index of point
    629         double distance = treeContentDistance(tree, index, coords); // Distance to point
    630         if (distance < radius2) {
    631             return true;
    632         }
    633     }
    634     return false;
    635 }
    636 
    637 // Given an arbitrary point and a matching radius, return whether there are any points within that radius
    638 bool psTreeWithinAny(const psTree *tree, const psVector *coordinates, double radius)
    639 {
    640 #if 1 // Might be in a tight loop
    641     PS_ASSERT_TREE_NON_NULL(tree, false);
    642     PS_ASSERT_VECTOR_NON_NULL(coordinates, false);
    643     PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, false);
     693        if (treeContentDistance(tree, index, coords) < distance) {
     694            psVectorAppend(result, index);
     695        }
     696    }
     697    return;
     698}
     699
     700// Given an arbitrary point and a matching radius, return the index of all points within that radius
     701psVector *psTreeAllWithin(const psTree *tree, const psVector *coordinates, double radius)
     702{
     703#ifdef INPUT_CHECK // Might be in a tight loop
     704    PS_ASSERT_TREE_NON_NULL(tree, NULL);
     705    PS_ASSERT_VECTOR_NON_NULL(coordinates, NULL);
     706    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, NULL);
    644707#endif
    645708
     
    647710                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
    648711
    649     radius *= radius;                   // We work with the radius-squared
    650 
    651     // This is essentially the same as psTreeWithin, except we can bail as soon as we find something
     712    double distance = treeRadiusToDistance(tree, radius); // Distance measure
     713
     714    psVector *result = psVectorAllocEmpty(4, PS_TYPE_S64); // Indices of points within match radius
     715
     716    // This is essentially the same as psTreeNearest, except we're not allowed to prune
    652717
    653718    // Find the closest point in the leaf that contains the point of interest
    654719    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
    655     if (treeLeafSearchWithinAny(radius, tree, leaf, coords)) {
    656         psFree(coords);
    657         return true;
    658     }
     720    treeLeafSearchAllWithin(result, distance, tree, leaf, coords);
    659721
    660722    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     
    673735            }
    674736            // Leaf node
    675             if (treeLeafSearchWithinAny(radius, tree, node, coords)) {
     737            treeLeafSearchAllWithin(result, distance, tree, node, coords);
     738            work->data[workIndex] = NULL;
     739            workIndex--;
     740        }
     741
     742        leaf = up;
     743    }
     744    psFree(work);
     745    psFree(coords);
     746
     747    return result;
     748}
     749
     750// Search a leaf node for any points within distance measure
     751static inline bool treeLeafSearchWithinAny(double distance, // Distance to search
     752                                           const psTree *tree, // Tree of interest
     753                                           const psTreeNode *leaf, // Leaf to search
     754                                           const psVector *coords // Coordinates of interest
     755    )
     756{
     757    for (int i = 0; i < leaf->num; i++) {
     758        long index = leaf->contents[i]; // Index of point
     759        if (treeContentDistance(tree, index, coords) < distance) {
     760            return true;
     761        }
     762    }
     763    return false;
     764}
     765
     766// Given an arbitrary point and a matching radius, return whether there are any points within that radius
     767bool psTreeWithinAny(const psTree *tree, const psVector *coordinates, double radius)
     768{
     769#ifdef INPUT_CHECK // Might be in a tight loop
     770    PS_ASSERT_TREE_NON_NULL(tree, false);
     771    PS_ASSERT_VECTOR_NON_NULL(coordinates, false);
     772    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, false);
     773#endif
     774
     775    psVector *coords = (coordinates->type.type == PS_TYPE_F64 ? psMemIncrRefCounter((psVector*)coordinates) :
     776                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
     777
     778    double distance = treeRadiusToDistance(tree, radius); // Distance measure
     779
     780    // This is essentially the same as psTreeWithin, except we can bail as soon as we find something
     781
     782    // Find the closest point in the leaf that contains the point of interest
     783    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
     784    if (treeLeafSearchWithinAny(distance, tree, leaf, coords)) {
     785        psFree(coords);
     786        return true;
     787    }
     788
     789    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     790    while (leaf->up) {
     791        psTreeNode *up = leaf->up;      // Parent node
     792
     793        long workIndex = 0;
     794        work->data[workIndex] = (leaf == up->left ? up->right : up->left); // The other node
     795        while (workIndex >= 0) {
     796            psTreeNode *node = work->data[workIndex];
     797            if (node->left) {
     798                // Branch node
     799                work->data[workIndex] = node->right;
     800                work->data[++workIndex] = node->left;
     801                continue;
     802            }
     803            // Leaf node
     804            if (treeLeafSearchWithinAny(distance, tree, node, coords)) {
    676805                // Clear out the work queue
    677806                memset(work->data, 0, (workIndex + 1) * sizeof(void));
     
    695824psVector *psTreeCoords(psVector *out, const psTree *tree, long index)
    696825{
    697 #if 1 // Might be in a tight loop
     826#ifdef INPUT_CHECK // Might be in a tight loop
    698827    PS_ASSERT_TREE_NON_NULL(tree, NULL);
    699828    PS_ASSERT_INT_NONNEGATIVE(index, NULL);
  • branches/pap_mops/psLib/src/types/psTree.h

    r19539 r25180  
    1616} psTreeCoordArray;
    1717
     18/// Type of tree
     19///
     20/// Specifies how distances are measured
     21typedef enum {
     22    PS_TREE_EUCLIDEAN,                  // d^2 = dx^2 + dy^2 + ...
     23    PS_TREE_SPHERICAL,                  // sin(dist/2)^2 = sin(dphi/2)^2 + cos(phi1)cos(phi2)sin(dlambda/2)^2
     24} psTreeType;
     25
    1826/// A simple kd-tree implementation
    1927///
     
    2331    int dim;                            ///< Dimensionality
    2432    int maxLeafContents;                ///< Maximum number of points on a leaf
     33    psTreeType type;                    ///< Type of tree
    2534    long numNodes;                      ///< Number of nodes
    2635    long numData;                       ///< Number of data points
     
    6776psTree *psTreeAlloc(int dim,            ///< Dimensionality
    6877                    int maxLeafContents,///< Maximum number of points on a leaf
     78                    psTreeType type,    ///< Type of tree
    6979                    long numNodes       ///< Number of nodes in tree
    7080                    );
     
    7585psTree *psTreePlant(int dim,            ///< Dimensionality
    7686                    int maxLeafContents,///< Maximum number of points on a leaf
     87                    psTreeType type,    ///< Type of tree
    7788                    ...                 ///< psVector for each coordinate
    7889                    );
     
    108119                     );
    109120
     121/// Return the index of all points within some radius of given coordinates
     122psVector *psTreeAllWithin(const psTree *tree,          ///< Tree
     123                          const psVector *coordinates, ///< Coordinates of interest
     124                          double radius                ///< Radius of interest
     125                          );
     126
    110127/// Return the coordinates of a point in the tree, specified by its index
    111128psVector *psTreeCoords(psVector *out,   ///< Output vector, or NULL
Note: See TracChangeset for help on using the changeset viewer.