2010-10-31 02:31:34 +00:00
|
|
|
#include "liblwgeom_internal.h"
|
2009-11-30 20:52:16 +00:00
|
|
|
#include "lwtree.h"
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal nodes have their point references set to NULL.
|
|
|
|
*/
|
|
|
|
static int rect_node_is_leaf(const RECT_NODE *node)
|
|
|
|
{
|
|
|
|
return (node->p1 != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2010-02-01 17:35:55 +00:00
|
|
|
* Recurse from top of node tree and free all children.
|
2009-11-30 20:52:16 +00:00
|
|
|
* does not free underlying point array.
|
|
|
|
*/
|
|
|
|
void rect_tree_free(RECT_NODE *node)
|
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( node->left_node )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
rect_tree_free(node->left_node);
|
|
|
|
node->left_node = 0;
|
|
|
|
}
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( node->right_node )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
rect_tree_free(node->right_node);
|
|
|
|
node->right_node = 0;
|
|
|
|
}
|
|
|
|
lwfree(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 0 => no containment */
|
|
|
|
int rect_tree_contains_point(const RECT_NODE *node, const POINT2D *pt, int *on_boundary)
|
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( FP_CONTAINS_INCL(node->ymin, pt->y, node->ymax) )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( rect_node_is_leaf(node) )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
double side = lw_segment_side(node->p1, node->p2, pt);
|
|
|
|
if ( side == 0.0 )
|
|
|
|
*on_boundary = LW_TRUE;
|
|
|
|
return (side < 0.0 ? -1 : 1 );
|
|
|
|
}
|
2010-02-01 17:35:55 +00:00
|
|
|
else
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
return rect_tree_contains_point(node->left_node, pt, on_boundary) +
|
|
|
|
rect_tree_contains_point(node->right_node, pt, on_boundary);
|
|
|
|
}
|
|
|
|
}
|
2009-12-20 17:42:44 +00:00
|
|
|
/* printf("NOT in measure range\n"); */
|
2009-11-30 20:52:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rect_tree_intersects_tree(const RECT_NODE *n1, const RECT_NODE *n2)
|
|
|
|
{
|
2009-11-30 22:08:12 +00:00
|
|
|
LWDEBUGF(4,"n1 (%.9g %.9g,%.9g %.9g) vs n2 (%.9g %.9g,%.9g %.9g)",n1->xmin,n1->ymin,n1->xmax,n1->ymax,n2->xmin,n2->ymin,n2->xmax,n2->ymax);
|
2009-11-30 20:52:16 +00:00
|
|
|
/* There can only be an edge intersection if the rectangles overlap */
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( ! ( FP_GT(n1->xmin, n2->xmax) || FP_GT(n2->xmin, n1->xmax) || FP_GT(n1->ymin, n2->ymax) || FP_GT(n2->ymin, n1->ymax) ) )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
2009-11-30 22:08:12 +00:00
|
|
|
LWDEBUG(4," interaction found");
|
2009-11-30 20:52:16 +00:00
|
|
|
/* We can only test for a true intersection if the nodes are both leaf nodes */
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( rect_node_is_leaf(n1) && rect_node_is_leaf(n2) )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
2009-11-30 22:08:12 +00:00
|
|
|
LWDEBUG(4," leaf node test");
|
2009-11-30 20:52:16 +00:00
|
|
|
/* Check for true intersection */
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( lw_segment_intersects(n1->p1, n1->p2, n2->p1, n2->p2) )
|
2009-11-30 20:52:16 +00:00
|
|
|
return LW_TRUE;
|
|
|
|
else
|
|
|
|
return LW_FALSE;
|
|
|
|
}
|
2010-02-01 17:35:55 +00:00
|
|
|
else
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
2009-11-30 22:08:12 +00:00
|
|
|
LWDEBUG(4," internal node found, recursing");
|
2009-11-30 20:52:16 +00:00
|
|
|
/* Recurse to children */
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( rect_node_is_leaf(n1) )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( rect_tree_intersects_tree(n2->left_node, n1) || rect_tree_intersects_tree(n2->right_node, n1) )
|
2009-11-30 20:52:16 +00:00
|
|
|
return LW_TRUE;
|
|
|
|
else
|
|
|
|
return LW_FALSE;
|
|
|
|
}
|
2010-02-01 17:35:55 +00:00
|
|
|
else
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( rect_tree_intersects_tree(n1->left_node, n2) || rect_tree_intersects_tree(n1->right_node, n2) )
|
2009-11-30 20:52:16 +00:00
|
|
|
return LW_TRUE;
|
|
|
|
else
|
|
|
|
return LW_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-11-30 22:08:12 +00:00
|
|
|
LWDEBUG(4," no interaction found");
|
2009-11-30 20:52:16 +00:00
|
|
|
return LW_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new leaf node, calculating a measure value for each point on the
|
|
|
|
* edge and storing pointers back to the end points for later.
|
|
|
|
*/
|
|
|
|
RECT_NODE* rect_node_leaf_new(const POINTARRAY *pa, int i)
|
|
|
|
{
|
|
|
|
POINT2D *p1, *p2;
|
|
|
|
RECT_NODE *node;
|
|
|
|
|
|
|
|
p1 = (POINT2D*)getPoint_internal(pa, i);
|
|
|
|
p2 = (POINT2D*)getPoint_internal(pa, i+1);
|
|
|
|
|
|
|
|
/* Zero length edge, doesn't get a node */
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( FP_EQUALS(p1->x, p2->x) && FP_EQUALS(p1->y, p2->y) )
|
2009-11-30 20:52:16 +00:00
|
|
|
return NULL;
|
2010-02-01 17:35:55 +00:00
|
|
|
|
2009-11-30 20:52:16 +00:00
|
|
|
node = lwalloc(sizeof(RECT_NODE));
|
|
|
|
node->p1 = p1;
|
|
|
|
node->p2 = p2;
|
|
|
|
node->xmin = FP_MIN(p1->x,p2->x);
|
|
|
|
node->xmax = FP_MAX(p1->x,p2->x);
|
|
|
|
node->ymin = FP_MIN(p1->y,p2->y);
|
|
|
|
node->ymax = FP_MAX(p1->y,p2->y);
|
|
|
|
node->left_node = NULL;
|
|
|
|
node->right_node = NULL;
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new internal node, calculating the new measure range for the node,
|
|
|
|
* and storing pointers to the child nodes.
|
|
|
|
*/
|
|
|
|
RECT_NODE* rect_node_internal_new(RECT_NODE *left_node, RECT_NODE *right_node)
|
|
|
|
{
|
|
|
|
RECT_NODE *node = lwalloc(sizeof(RECT_NODE));
|
|
|
|
node->p1 = NULL;
|
|
|
|
node->p2 = NULL;
|
|
|
|
node->xmin = FP_MIN(left_node->xmin, right_node->xmin);
|
2010-02-01 17:35:55 +00:00
|
|
|
node->xmax = FP_MAX(left_node->xmax, right_node->xmax);
|
2009-11-30 20:52:16 +00:00
|
|
|
node->ymin = FP_MIN(left_node->ymin, right_node->ymin);
|
2010-02-01 17:35:55 +00:00
|
|
|
node->ymax = FP_MAX(left_node->ymax, right_node->ymax);
|
2009-11-30 20:52:16 +00:00
|
|
|
node->left_node = left_node;
|
|
|
|
node->right_node = right_node;
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a tree of nodes from a point array, one node per edge, and each
|
|
|
|
* with an associated measure range along a one-dimensional space. We
|
|
|
|
* can then search that space as a range tree.
|
|
|
|
*/
|
|
|
|
RECT_NODE* rect_tree_new(const POINTARRAY *pa)
|
|
|
|
{
|
|
|
|
int num_edges, num_children, num_parents;
|
|
|
|
int i, j;
|
|
|
|
RECT_NODE **nodes;
|
|
|
|
RECT_NODE *node;
|
|
|
|
RECT_NODE *tree;
|
2010-02-01 17:35:55 +00:00
|
|
|
|
|
|
|
if ( pa->npoints < 2 )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-02-01 17:35:55 +00:00
|
|
|
|
|
|
|
/*
|
2009-11-30 20:52:16 +00:00
|
|
|
** First create a flat list of nodes, one per edge.
|
|
|
|
** For each vertex, transform into our one-dimensional measure.
|
|
|
|
** Hopefully, when projected, the points turn into a fairly
|
|
|
|
** uniformly distributed collection of measures.
|
|
|
|
*/
|
|
|
|
num_edges = pa->npoints - 1;
|
|
|
|
nodes = lwalloc(sizeof(RECT_NODE*) * pa->npoints);
|
|
|
|
j = 0;
|
2010-02-01 17:35:55 +00:00
|
|
|
for ( i = 0; i < num_edges; i++ )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
node = rect_node_leaf_new(pa, i);
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( node ) /* Not zero length? */
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
nodes[j] = node;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
2010-02-01 17:35:55 +00:00
|
|
|
|
2009-11-30 20:52:16 +00:00
|
|
|
/*
|
|
|
|
** If we sort the nodelist first, we'll get a more balanced tree
|
|
|
|
** in the end, but at the cost of sorting. For now, we just
|
2010-02-01 17:35:55 +00:00
|
|
|
** build the tree knowing that point arrays tend to have a
|
2009-11-30 20:52:16 +00:00
|
|
|
** reasonable amount of sorting already.
|
|
|
|
*/
|
2010-02-01 17:35:55 +00:00
|
|
|
|
2009-11-30 20:52:16 +00:00
|
|
|
num_children = j;
|
|
|
|
num_parents = num_children / 2;
|
2010-02-01 17:35:55 +00:00
|
|
|
while ( num_parents > 0 )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
j = 0;
|
2010-02-01 17:35:55 +00:00
|
|
|
while ( j < num_parents )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
/*
|
2009-11-30 20:52:16 +00:00
|
|
|
** Each new parent includes pointers to the children, so even though
|
|
|
|
** we are over-writing their place in the list, we still have references
|
|
|
|
** to them via the tree.
|
|
|
|
*/
|
|
|
|
nodes[j] = rect_node_internal_new(nodes[2*j], nodes[(2*j)+1]);
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
/* Odd number of children, just copy the last node up a level */
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( num_children % 2 )
|
2009-11-30 20:52:16 +00:00
|
|
|
{
|
|
|
|
nodes[j] = nodes[num_children - 1];
|
|
|
|
num_parents++;
|
|
|
|
}
|
|
|
|
num_children = num_parents;
|
|
|
|
num_parents = num_children / 2;
|
2010-02-01 17:35:55 +00:00
|
|
|
}
|
2009-11-30 20:52:16 +00:00
|
|
|
|
|
|
|
/* Take a reference to the head of the tree*/
|
|
|
|
tree = nodes[0];
|
2010-02-01 17:35:55 +00:00
|
|
|
|
2009-11-30 20:52:16 +00:00
|
|
|
/* Free the old list structure, leaving the tree in place */
|
|
|
|
lwfree(nodes);
|
2010-02-01 17:35:55 +00:00
|
|
|
|
2009-11-30 20:52:16 +00:00
|
|
|
return tree;
|
2010-02-01 17:35:55 +00:00
|
|
|
|
2009-11-30 20:52:16 +00:00
|
|
|
}
|
|
|
|
|