https://github.com/cran/gstat
Tip revision: 1b2742a3d71abc7fbde73ca141b23e1375f185bf authored by Edzer Pebesma on 30 October 2011, 00:00:00 UTC
version 1.0-9
version 1.0-9
Tip revision: 1b2742a
nsearch.c
/*
This software module is copyright 1997 (c):
Steve Joyce mailto:steve.joyce@resgeom.slu.se
Remote Sensing Laboratory http://www-umea.slu.se/~fjasj/
Dept. of Forest Resource Mgmt. & Geomatics Tel: +46 90 16 69 57
Swedish University of Agricultural Sciences Fax: +46 90 14 19 15
S-901 83 Umeĺ, Sweden
Distributed freely under the terms of the GNU General Public License
as a component of:
Gstat, a program for geostatistical modelling, prediction and simulation
Copyright 1992-2009 (C) Edzer J. Pebesma
Edzer J. Pebesma (E.Pebesma@geo.uu.nl)
Landscape and environmental research group
Faculty of geographical sciences
University of Amsterdam
Nieuwe Prinsengracht 130
1018 VZ Amsterdam -- The Netherlands
*/
/*
* qtree.c: quick neighbourhood selection routines for gstat
*/
/*
* Edzer's CHANGE LOG from Steve's original contribution:
* converted most float to double;
* bbox size initialization -1.0
* added some ErrMsg() error message checks
* changed qtree_quick_select() call (DPOINTX disappeared)
* made is_leaf(node) a macro; removed max_ppnode -> Q_SPLIT_AT
* added flexible 1/2/3d tree support: detect from data->mode;
* added bbox.mode field;
* modified routines like in_bbox, sub_bbox to detect tree dimension
* qtree_free(): node->n_node should be N_NODES(node)
* init_qtree is now called from qtree_quick_select()
* added bbox_from_* routines
* added get_index macro: searching is not required
* added qtree_print() functions
* might have missed some.
* (after 2.0:)
* Q_SPLIT_AT -> gl_split
* implemented the priority queue mechanism, see PR bucket quad trees
* demonstrated at http://www.cs.umd.edu/~brabec/quadtree/index.html.
* (this enables efficient search when only max is defined, i.e. without
* a radius -- especially in case of simulation this seems really
* efficient)
* removed min_bbox -->> this became obsolete with the priority queue
*
* I guess many of my modifications assume you have sufficient memory,
* and that you want to use it to speed things up.
*/
#include <stdio.h>
#include <stdlib.h> /* qsort() */
#include <math.h> /* sqrt() */
#include <float.h> /* DBL_MAX */
#include <limits.h> /* INT_MAX */
#include "defs.h"
#include "userio.h"
#include "debug.h"
#include "data.h"
#include "utils.h"
#include "glvars.h" /* get_method(), name_identifier() */
#include "mapio.h"
#include "predict.h" /* get_mask0() */
#include "nsearch.h"
#include "pqueue.h" /* include _after_ search.h! */
#define N_NODES(x) (x==NULL?0:(-((x)->n_node)))
/* a negative n_node means it's not a leaf */
/*
* this is a 'tuning' parameter defining the number of points in
* a quad before it is split into 4
* #define Q_SPLIT_AT 4
*/
/*
* another tuning parameter defining the minimum quad size allowed.
* (multiplied by d->sel_rad)
#define Q_STOP_AT 0.5 (now obsolete)
*/
#define is_leaf(node) (((node) == NULL) || (((node)->n_node) >= 0))
#define is_qtree_search(d) (d->qtree_root != NULL)
#define get_index(pt, bb) \
((pt->x >= bb.x + 0.5 * bb.size) | \
(((bb.mode & Y_BIT_SET) && (pt->y >= bb.y + 0.5 * bb.size)) << 1) | \
(((bb.mode & Z_BIT_SET) && (pt->z >= bb.z + 0.5 * bb.size)) << 2))
static void init_qtree(DATA *d);
static void init_qnode(QTREE_NODE **p_node, int is_leaf, BBOX bb);
static void qtree_push(DPOINT *p, QTREE_NODE **p_node, int recursion_depth);
static BBOX sub_bbox(const BBOX bb, int i);
static int in_bbox(const DPOINT *p, BBOX bb);
static void qtree_split_node(QTREE_NODE *node, BBOX bb, int rec_level);
static QTREE_NODE *qtree_expand(const DPOINT *p, QTREE_NODE *root);
static QTREE_NODE **qtree_find_node(const DPOINT *p, QTREE_NODE **p_node,
BBOX *bbox);
void qtree_print(DATA *d);
static void logprint_qtree(QTREE_NODE *node, int depth);
static BBOX bbox_from_grid(const GRIDMAP *gt, const DATA_GRIDMAP *dg);
static BBOX bbox_from_data(DATA *d);
static void qtree_zero_all_leaves(QTREE_NODE *node);
static int CDECL node_cmp(const QUEUE_NODE *a, const QUEUE_NODE *b);
void logprint_queue(QUEUE *queue);
static void init_qtree(DATA *d) {
/*
* Initialize the root of the search tree:
* Since this is called from qtree_quick_select(), we know allready
* quite a lot. This helps choosing sensible values for the
* top level bbox origin and size.
*/
const GRIDMAP *gt = NULL;
DATA *simlocs = NULL;
int i, mode;
BBOX bbox;
if (is_simulation(get_method())) {
/*
* sequential simulation: the simulation path (through DATA or GRIDMAP)
* will make up for (most of) the search locations:
*/
gt = (const GRIDMAP *) get_mask0();
simlocs = get_dataval();
/* in case of simulation one of them will be non-NULL */
}
/* get initial estimate for top level bbox: */
if (gt != NULL)
bbox = bbox_from_grid(gt, NULL);
else if (simlocs != NULL) {
bbox = bbox_from_data(simlocs);
if (bbox.size <= 0.0)
bbox = bbox_from_data(d);
} else
bbox = bbox_from_data(d);
init_qnode(&(d->qtree_root), d->n_list < gl_split, bbox); /* ML1 */
mode = bbox.mode;
for (i = 0; i < d->n_list; i++)
qtree_push_point(d, d->list[i]); /* now they won't be rejected */ /* ML2 */
if (DEBUG_DUMP) {
printlog("top level search tree statistics for data(%s):\n",
name_identifier(d->id));
printlog("bounding box origin [");
if (mode & X_BIT_SET)
printlog("%g", d->qtree_root->bb.x);
if (mode & Y_BIT_SET)
printlog(",%g", d->qtree_root->bb.y);
if (mode & Z_BIT_SET)
printlog(",%g", d->qtree_root->bb.z);
printlog("]; dimension %g\n", d->qtree_root->bb.size);
}
/* qtree_print(d); */
return;
}
static void init_qnode(QTREE_NODE **p_node, int isleaf, BBOX bb) {
/*
* initialize a node in the search tree.
* bb.mode tells the dimension of the tree (1D/2D/3D)
*/
int i;
if (*p_node == NULL) {
*p_node = (QTREE_NODE *) emalloc(sizeof(QTREE_NODE)); /* ML1 */
(*p_node)->bb = bb;
}
if (isleaf)
(*p_node)->n_node = 0;
else {
if (bb.mode & Z_BIT_SET) /* 3D: oct-tree */
(*p_node)->n_node = -8;
else if (bb.mode & Y_BIT_SET) /* 2D: quad-tree */
(*p_node)->n_node = -4;
else if (bb.mode & X_BIT_SET) /* 1D: binary tree */
(*p_node)->n_node = -2;
else /* no x/y/z bit set...??? */
ErrMsg(ER_IMPOSVAL, "init_qnode: invalid mode");
(*p_node)->u.node = (QTREE_NODE **)
emalloc(N_NODES(*p_node) * sizeof(QTREE_NODE *));
for (i = 0; i < N_NODES(*p_node); i++)
(*p_node)->u.node[i] = NULL;
}
return;
}
void qtree_push_point(DATA *d, DPOINT *where) {
/* add a single point to the search tree structure in d->qtree_root */
/*
* do not do this while reading the data: suppose we'll never need
* a neighbourhood selection after all!
*/
if (! is_qtree_search(d))
return;
/* min_bbox = d->sel_rad * Q_STOP_AT; */
/*
* if this point is outside the current search tree,
* we need to add another level to the top and try again:
*/
while (! in_bbox(where, d->qtree_root->bb))
d->qtree_root = qtree_expand(where, d->qtree_root);
/*
* finally push the point onto the tree:
*/
qtree_push(where, &(d->qtree_root), 0);
return;
}
static void qtree_push(DPOINT *where, QTREE_NODE **p_node,
int recursion_depth) {
/* add a data point to the quad tree starting at the node specified. */
QTREE_NODE **p_leaf, *node;
BBOX bb;
bb = (*p_node)->bb;
recursion_depth += 1;
/* printf("recursion_depth: %d, max %d\n", recursion_depth, MAX_RECURSION_DEPTH); */
/* find the leaf node where this point belongs */
p_leaf = qtree_find_node(where, p_node, &bb);
if (*p_leaf == NULL)
init_qnode(p_leaf, 1, bb); /* leaf == 1: sets ->n_node to 0 */
node = *p_leaf;
/* If it is already full, split it into another level and try again: */
if (node->n_node == gl_split && recursion_depth < MAX_RECURSION_DEPTH) {
qtree_split_node(node, (*p_node)->bb, recursion_depth);
qtree_push(where, &node, recursion_depth);
return;
}
/* XXX */
if (node->n_node == 0)
node->u.list = (DPOINT **) emalloc(sizeof(DPOINT *));
else
node->u.list = (DPOINT **) erealloc(node->u.list,
(node->n_node + 1) * sizeof(DPOINT *)); /* ML2 */
node->u.list[node->n_node] = where;
node->n_node++;
return;
}
void qtree_pop_point(DPOINT *where, DATA *d) {
int i;
QTREE_NODE *node, **p_node;
/* delete a point from the search tree */
if (! is_qtree_search(d)) /* don't bother */
return;
p_node = qtree_find_node(where, &(d->qtree_root), NULL);
if (*p_node == NULL)
ErrMsg(ER_IMPOSVAL, "qtree_pop_point(): could not find node");
node = *p_node;
for (i = 0; i < node->n_node; i++) {
if (where == node->u.list[i]) {
/* don't preserve order: copy last to this one: */
node->u.list[i] = node->u.list[node->n_node - 1];
break; /* from for loop */
}
}
node->n_node--;
/* free memory if empty list: */
if (node->n_node == 0) {
efree(node->u.list);
efree(node);
*p_node = NULL;
}
return;
}
void qtree_free(QTREE_NODE *node) {
/*
* If a push or search fails, you might want to consider getting rid of
* whole tree and default to exhaustive search. (SJ)
* [If you ever get so far, exhaustive search will take
* a nearly infinite amount of time. Instead, tweek gl_split. --EJP]
*/
int i;
if (node == NULL)
return;
if (!is_leaf(node)) {
for (i = 0; i < N_NODES(node); i++)
qtree_free(node->u.node[i]);
efree(node->u.node);
} else
efree(node->u.list);
efree(node);
return;
}
static void qtree_split_node(QTREE_NODE *node, BBOX bbox, int rec_level) {
/*
* split the quadtree at 'node' and redistribute its points
*/
DPOINT **list;
int i, n;
/* first copy the points to a temporary location and free the pointers */
n = node->n_node;
list = node->u.list; /* save temporary copy */
/* make a node from this leaf, overwrite u: */
init_qnode(&node, 0, bbox);
/* redistribute the points into the child nodes where they belong */
for (i = 0; i < n; i++)
qtree_push(list[i], &node, rec_level);
efree(list);
return;
}
static QTREE_NODE *qtree_expand(const DPOINT *where, QTREE_NODE *root) {
/*
* expand the top level of the search tree
*/
QTREE_NODE *new_top = NULL;
DPOINT old_centre;
BBOX old_bb, new_bb;
int i;
old_bb = root->bb;
old_centre.x = old_centre.y = old_centre.z = 0.0;
if (old_bb.mode & X_BIT_SET)
old_centre.x = old_bb.x + old_bb.size / 2.0;
if (old_bb.mode & Y_BIT_SET)
old_centre.y = old_bb.y + old_bb.size / 2.0;
if (old_bb.mode & Z_BIT_SET)
old_centre.z = old_bb.z + old_bb.size / 2.0;
new_bb = old_bb;
/*
* set the new bounding box: Steve, could you check this?
* (I didn't grasp your original bbox setting here:)
*
* set the root bbox to the new_top bbox:
*/
if ((old_bb.mode & X_BIT_SET) && (where->x < old_bb.x))
new_bb.x -= old_bb.size;
if ((old_bb.mode & Y_BIT_SET) && (where->y < old_bb.y))
new_bb.y -= old_bb.size;
if ((old_bb.mode & Z_BIT_SET) && (where->z < old_bb.z))
new_bb.z -= old_bb.size;
new_bb.size *= 2.0;
/* link the old root node to the proper spot in new_top: */
init_qnode(&new_top, 0, old_bb);
i = get_index((&old_centre), new_bb);
new_top->u.node[i] = root;
new_top->bb = new_bb;
/* make this one the new root */
return new_top;
}
static QTREE_NODE **qtree_find_node(const DPOINT *where, QTREE_NODE **p_node,
BBOX *bb) {
/*
* find the deepest leaf (end node) in the tree that bounds this point's
* coordinates.
* It's bounding box is saved in the location pointed to by p_bbox
*/
int i;
if (is_leaf(*p_node))
return p_node;
/* find in which node we are: */
i = get_index(where, (*p_node)->bb);
if (bb != NULL)
*bb = sub_bbox(*bb, i);
/* recurse into this node: */
return qtree_find_node(where, &((*p_node)->u.node[i]), bb);
}
static BBOX sub_bbox(const BBOX bbox, int index) {
/*
* return the bounding box of a quad-tree child node based on the index
* layout of octree index:
*
* | dz <= 0 dz > 0
* --------|--------------------
* dy > 0 | 2 3 6 7
* dy <= 0 | 0 1 4 5
* |
* dx ? 0 | <= > <= >
*/
double size;
BBOX b;
b = bbox;
b.size = size = bbox.size / 2.0;
if (index & X_BIT_SET) /* 1, 3, 5, 7 */
b.x += size;
if (index & Y_BIT_SET) /* 2, 3, 6, 7 */
b.y += size;
if (index & Z_BIT_SET) /* 4, 5, 6, 7 */
b.z += size;
return b;
}
static int in_bbox(const DPOINT *where, BBOX bbox) {
/*
* check if where is inside the bounding box:
* _on_ the left/lower/downside boundary or is inside the box
*/
if ((bbox.mode & X_BIT_SET) &&
((where->x < bbox.x) || (where->x >= bbox.x + bbox.size)))
return 0;
if ((bbox.mode & Y_BIT_SET) &&
((where->y < bbox.y) || (where->y >= bbox.y + bbox.size)))
return 0;
if ((bbox.mode & Z_BIT_SET) &&
((where->z < bbox.z) || (where->z >= bbox.z + bbox.size)))
return 0;
/* so, where apparently in ... */
return 1;
}
/*
* pb_norm2_?D() functions:
* calculate shortest (squared) euclidian distance from a point to a BBOX,
* for ? being 1, 2 or 3 dimensions
*/
double pb_norm_1D(const DPOINT *where, BBOX bbox) {
double x, dx;
x = where->x;
if (x < bbox.x) {
dx = bbox.x - x;
return dx * dx;
}
bbox.x += bbox.size;
if (x > bbox.x) {
dx = x - bbox.x;
return dx * dx;
}
return 0.0; /* inside box */
}
double pb_norm_2D(const DPOINT *where, BBOX bbox) {
double x, y, dx = 0.0, dy = 0.0;
x = where->x;
y = where->y;
if (x < bbox.x)
dx = bbox.x - x;
else {
bbox.x += bbox.size;
if (x > bbox.x)
dx = x - bbox.x;
}
if (y < bbox.y)
dy = bbox.y - y;
else {
bbox.y += bbox.size;
if (y > bbox.y)
dy = y - bbox.y;
}
return dx * dx + dy * dy;
}
double pb_norm_3D(const DPOINT *where, BBOX bbox) {
double x, y, z, dx = 0.0, dy = 0.0, dz = 0;
x = where->x;
y = where->y;
z = where->z;
if (x < bbox.x)
dx = bbox.x - x;
else {
bbox.x += bbox.size;
if (x > bbox.x)
dx = x - bbox.x;
}
if (y < bbox.y)
dy = bbox.y - y;
else {
bbox.y += bbox.size;
if (y > bbox.y)
dy = y - bbox.y;
}
if (z < bbox.z)
dz = bbox.z - z;
else {
bbox.z += bbox.size;
if (z > bbox.z)
dz = z - bbox.z;
}
return dx * dx + dy * dy + dz * dz;
}
void qtree_print(DATA *d) {
/*
* plot the full tree (2D), in a format that can be read by jgraph, found
* at netlib or at http://kenner.cs.utk.edu/~plank/plank/jgraph/jgraph.html
*/
printlog("newgraph\nxaxis size 3\nyaxis size 3\n");
printlog("title : %s [n = %d]\n",
name_identifier(d->id), d->n_list);
logprint_qtree(d->qtree_root, 0);
return;
}
static void logprint_qtree(QTREE_NODE *node, int depth) {
BBOX b;
int i;
if (node == NULL)
return;
b = node->bb;
if (!is_leaf(node)) {
printlog("newline linethickness 0.3 pts %g %g %g %g %g %g %g %g %g %g\n",
b.x, b.y, b.x+b.size, b.y, b.x+b.size,
b.y+b.size, b.x, b.y+b.size, b.x, b.y);
for (i = 0; i < N_NODES(node); i++)
logprint_qtree(node->u.node[i], depth+1);
} else {
printlog("newline pts %g %g %g %g %g %g %g %g %g %g\n",
b.x, b.y, b.x+b.size, b.y, b.x+b.size,
b.y+b.size, b.x, b.y+b.size, b.x, b.y);
/*
if (node == NULL)
printlog("newcurve marktype circle fill 1 pts %g %g\n",
b.x+0.5*b.size, b.y+0.5*b.size);
*/
if (node->n_node > 0) {
printlog("newcurve marktype cross pts");
for (i = 0; i < node->n_node; i++)
printlog(" %g %g", node->u.list[i]->x, node->u.list[i]->y);
printlog("\n");
}
}
}
static BBOX bbox_from_grid(const GRIDMAP *gt, const DATA_GRIDMAP *dg) {
/* derive a sensible top level bounding box from grid map topology */
double sizex, sizey;
BBOX bbox;
if (gt) {
sizex = gt->cols * gt->cellsizex;
sizey = gt->rows * gt->cellsizey;
bbox.x = gt->x_ul;
bbox.y = gt->y_ul - sizey;
/*
* bbox.size should be set to such a value that the smallest
* leaf fits exactly over 4 grid map cells
*/
bbox.size = MIN(gt->cellsizex, gt->cellsizey);
} else {
sizex = dg->cols * dg->cellsizex;
sizey = dg->rows * dg->cellsizey;
bbox.x = dg->x_ul;
bbox.y = dg->y_ul - sizey;
bbox.size = MIN(dg->cellsizex, dg->cellsizey);
}
bbox.z = DBL_MAX;
while (bbox.size < MAX(sizex, sizey))
bbox.size *= 2;
bbox.mode = (X_BIT_SET | Y_BIT_SET); /* i.e. 3 */
return bbox;
}
static BBOX bbox_from_data(DATA *d) {
/* derive a sensible top level bounding box from a data var */
double maxspan, dy, dz;
BBOX bbox;
if (d->grid)
return bbox_from_grid(NULL, d->grid);
bbox.x = d->minX;
bbox.y = d->minY;
bbox.z = d->minZ;
bbox.mode = d->mode; /* ??? */
/*
bbox.mode = d->mode & (X_BIT_SET|Y_BIT_SET|Z_BIT_SET);
maxspan = MAX((d->maxX-d->minX), MAX((d->maxY-d->minY),(d->maxZ-d->minZ)));
*/
maxspan = fabs(d->maxX - d->minX);
dy = fabs(d->maxY - d->minY);
if (dy > maxspan)
maxspan = dy;
dz = fabs(d->maxZ - d->minZ);
if (dz > maxspan)
maxspan = dz;
/* with d->grid_size entered by user:
if (d->grid_size > 0.0) {
bbox.x -= 0.5 * d->grid_size;
bbox.y -= 0.5 * d->grid_size;
bbox.z -= 0.5 * d->grid_size;
bbox.size = d->grid_size;
do {
bbox.size *= 2;
} while (bbox.size < (maxspan + d->grid_size));
}
*/
bbox.size = maxspan * 1.01;
return bbox;
}
static void qtree_zero_all_leaves(QTREE_NODE *node) {
int i;
if (!is_leaf(node)) {
for (i = 0; i < N_NODES(node); i++)
qtree_zero_all_leaves(node->u.node[i]);
} else if (node != NULL)
node->n_node = 0;
return;
}
void qtree_rebuild(DATA *d) {
/* rebuild tree */
int i;
QTREE_NODE **p_leaf, *leaf;
if (d->n_list <= 0 || d->qtree_root == NULL)
return;
qtree_zero_all_leaves(d->qtree_root);
for (i = 0; i < d->n_list; i++) {
p_leaf = qtree_find_node(d->list[i], &(d->qtree_root), NULL);
leaf = *p_leaf;
leaf->u.list[leaf->n_node] = d->list[i];
leaf->n_node++;
}
return;
}
static DPOINT *get_nearest_point(QUEUE *q, DPOINT *where, DATA *d) {
/*
* returns the first (closest) DPOINT in the priority queue q, after all
* unwinding necessary (which is effectively recursion into the tree).
*
* this and the following functions: Copyright (GPL) 1998 Edzer J. Pebesma
*/
QUEUE_NODE head, *el = NULL /* temporary storage */ ;
QTREE_NODE *node;
int i, n;
while (q->length > 0) { /* try: */
/* logprint_queue(q); */
head = dequeue(q);
if (! head.is_node) { /* nearest element is a point: */
if (el != NULL)
efree(el);
return head.u.p;
}
node = head.u.n;
if (is_leaf(node)) { /* ah, the node dequeued is a leaf: */
/* printf("node->n_node: %d\n", node->n_node); */
if (node->n_node > 0)
el = (QUEUE_NODE *) erealloc(el, node->n_node * sizeof(QUEUE_NODE));
for (i = 0; i < node->n_node; i++) { /* enqueue it's DPOINT's: */
el[i].is_node = 0;
el[i].u.p = node->u.list[i];
el[i].dist2 = node->u.list[i]->u.dist2 =
d->pp_norm2(where, node->u.list[i]);
}
n = node->n_node;
} else { /* nope, but enqueue its sub-nodes: */
if (N_NODES(node) > 0)
el = (QUEUE_NODE *) erealloc(el, N_NODES(node) * sizeof(QUEUE_NODE));
for (i = n = 0; i < N_NODES(node); i++) {
if (node->u.node[i] != NULL) {
el[n].is_node = 1;
el[n].u.n = node->u.node[i];
el[n].dist2 = d->pb_norm2(where, node->u.node[i]->bb);
n++;
}
}
}
if (n > 0)
enqueue(q, el, n);
}
/* the while-loop terminates when the queue is empty */
if (el != NULL)
efree(el);
return NULL;
}
void logprint_queue(QUEUE *queue) {
Q_ELEMENT *q;
QUEUE_NODE *e;
printlog("current priority queue size: %d\n", queue->length);
for (q = queue->head; q != NULL; q = q->next) {
e = &(q->el);
printlog("%s %12.6g", e->is_node ?
"Node at " : "Point at", sqrt(e->dist2));
if (e->is_node)
printlog(" [xll=%g,yll=%g,size=%g] (with %d %s)\n",
e->u.n->bb.x, e->u.n->bb.y,
e->u.n->bb.size, ABS(e->u.n->n_node),
e->u.n->n_node < 0 ? "nodes" : "points");
else
printlog(" [index %d, value %g]\n",
GET_INDEX(e->u.p), e->u.p->attr);
}
}
static int CDECL node_cmp(const QUEUE_NODE *a, const QUEUE_NODE *b) {
/* ANSI qsort() conformant comparison function */
if (a->dist2 < b->dist2)
return -1;
if (a->dist2 > b->dist2)
return 1;
/* equal distances: prefer DPOINT over a node to speed up things */
if (a->is_node != b->is_node)
return (a->is_node ? 1 : -1);
return 0;
}
int qtree_select(DPOINT *where, DATA *d) {
DPOINT *p;
static QUEUE *q = NULL;
static QUEUE_NODE root;
int sel_max;
double rad2;
/* if this is the first time calling with this d: */
if (d->qtree_root == NULL)
init_qtree(d);
root.is_node = 1;
root.u.n = d->qtree_root;
root.dist2 = 0.0;
q = init_queue(q, node_cmp);
enqueue(q, &root, 1);
if (d->sel_rad >= DBL_MAX) {
/*
* simply get the d->sel_max nearest:
*/
for (d->n_sel = 0; d->n_sel < d->sel_max; d->n_sel++)
d->sel[d->n_sel] = get_nearest_point(q, where, d);
} else {
/*
* also consider a maximum distance to where
*/
if (d->vdist) /* select everything within sel_rad; cut later on */
sel_max = INT_MAX;
else
sel_max = d->sel_max;
rad2 = d->sel_rad * d->sel_rad;
d->n_sel = 0;
while (d->n_sel < sel_max) {
p = get_nearest_point(q, where, d);
if (p != NULL && p->u.dist2 <= rad2) { /* accept this point */
d->sel[d->n_sel] = p;
d->n_sel++;
} else
break; /* reject, and break while loop */
}
if (d->n_sel < d->sel_min) {
/*
* d->sel_min was set: consider points beyond radius
*/
if (d->force) /* proceed beyond d->sel_max */
for ( ; d->n_sel < d->sel_min; d->n_sel++)
d->sel[d->n_sel] = get_nearest_point(q, where, d);
else /* stop: a zero d->n_sel will result in a missing value */
d->n_sel = 0;
}
}
return d->n_sel;
}