[postgis-tickets] r16371 - Apply node sorting before descent to CIRC_NODE trees for

Paul Ramsey pramsey at cleverelephant.ca
Fri Feb 2 02:23:31 PST 2018


Author: pramsey
Date: 2018-02-02 14:23:31 -0800 (Fri, 02 Feb 2018)
New Revision: 16371

Modified:
   trunk/liblwgeom/lwgeodetic_tree.c
   trunk/liblwgeom/lwgeodetic_tree.h
Log:
Apply node sorting before descent to CIRC_NODE trees for
faster calculation of geography distances.
Closes #4010


Modified: trunk/liblwgeom/lwgeodetic_tree.c
===================================================================
--- trunk/liblwgeom/lwgeodetic_tree.c	2018-02-02 21:42:12 UTC (rev 16370)
+++ trunk/liblwgeom/lwgeodetic_tree.c	2018-02-02 22:23:31 UTC (rev 16371)
@@ -601,6 +601,51 @@
 	}
 }
 
+
+/***********************************************************************
+* Internal node sorting routine to make distance calculations faster?
+*/
+
+struct sort_node {
+	CIRC_NODE *node;
+	double d;
+};
+
+static int
+circ_nodes_sort_cmp(const void *a, const void *b)
+{
+	struct sort_node *node_a = (struct sort_node *)(a);
+	struct sort_node *node_b = (struct sort_node *)(b);
+	if (node_a->d < node_b->d) return -1;
+	else if (node_a->d > node_b->d) return 1;
+	else return 0;
+}
+
+static void
+circ_internal_nodes_sort(CIRC_NODE **nodes, uint32_t num_nodes, const CIRC_NODE *target_node)
+{
+	int i;
+	struct sort_node sort_nodes[CIRC_NODE_SIZE];
+
+	/* Copy incoming nodes into sorting array and calculate */
+	/* distance to the target node */
+	for (i = 0; i < num_nodes; i++)
+	{
+		sort_nodes[i].node = nodes[i];
+		sort_nodes[i].d = sphere_distance(&(nodes[i]->center), &(target_node->center));
+	}
+
+	/* Sort the nodes and copy the result back into the input array */
+	qsort(sort_nodes, num_nodes, sizeof(struct sort_node), circ_nodes_sort_cmp);
+	for (i = 0; i < num_nodes; i++)
+	{
+		nodes[i] = sort_nodes[i].node;
+	}
+	return;
+}
+
+/***********************************************************************/
+
 static double
 circ_tree_distance_tree_internal(const CIRC_NODE* n1, const CIRC_NODE* n2, double threshold, double* min_dist, double* max_dist, GEOGRAPHIC_POINT* closest1, GEOGRAPHIC_POINT* closest2)
 {
@@ -746,6 +791,7 @@
 		/* tests above. */
 		if ( n1->geom_type && lwtype_is_collection(n1->geom_type) )
 		{
+			circ_internal_nodes_sort(n1->nodes, n1->num_nodes, n2);
 			for ( i = 0; i < n1->num_nodes; i++ )
 			{
 				d = circ_tree_distance_tree_internal(n1->nodes[i], n2, threshold, min_dist, max_dist, closest1, closest2);
@@ -754,6 +800,7 @@
 		}
 		else if ( n2->geom_type && lwtype_is_collection(n2->geom_type) )
 		{
+			circ_internal_nodes_sort(n2->nodes, n2->num_nodes, n1);
 			for ( i = 0; i < n2->num_nodes; i++ )
 			{
 				d = circ_tree_distance_tree_internal(n1, n2->nodes[i], threshold, min_dist, max_dist, closest1, closest2);
@@ -762,6 +809,7 @@
 		}
 		else if ( ! circ_node_is_leaf(n1) )
 		{
+			circ_internal_nodes_sort(n1->nodes, n1->num_nodes, n2);
 			for ( i = 0; i < n1->num_nodes; i++ )
 			{
 				d = circ_tree_distance_tree_internal(n1->nodes[i], n2, threshold, min_dist, max_dist, closest1, closest2);
@@ -770,6 +818,7 @@
 		}
 		else if ( ! circ_node_is_leaf(n2) )
 		{
+			circ_internal_nodes_sort(n2->nodes, n2->num_nodes, n1);
 			for ( i = 0; i < n2->num_nodes; i++ )
 			{
 				d = circ_tree_distance_tree_internal(n1, n2->nodes[i], threshold, min_dist, max_dist, closest1, closest2);

Modified: trunk/liblwgeom/lwgeodetic_tree.h
===================================================================
--- trunk/liblwgeom/lwgeodetic_tree.h	2018-02-02 21:42:12 UTC (rev 16370)
+++ trunk/liblwgeom/lwgeodetic_tree.h	2018-02-02 22:23:31 UTC (rev 16371)
@@ -41,6 +41,7 @@
 	struct circ_node** nodes;
 	int edge_num;
 	uint32_t geom_type;
+	double d;
 	POINT2D pt_outside;
 	POINT2D* p1;
 	POINT2D* p2;



More information about the postgis-tickets mailing list