PostGIS  2.5.7dev-r@@SVN_REVISION@@
lwgeom_rectree.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2018 Paul Ramsey
22  *
23  **********************************************************************/
24 
25 
26 #include "postgres.h"
27 #include "funcapi.h"
28 #include "fmgr.h"
29 #include "liblwgeom.h"
30 #include "liblwgeom_internal.h" /* For FP comparators. */
31 #include "lwgeom_pg.h"
32 #include "lwtree.h"
33 #include "lwgeom_cache.h"
34 
35 
36 /* Prototypes */
37 Datum ST_DistanceRectTree(PG_FUNCTION_ARGS);
38 Datum ST_DistanceRectTreeCached(PG_FUNCTION_ARGS);
39 
40 
41 /**********************************************************************
42 * RectTree Caching support
43 **********************************************************************/
44 
45 /*
46 * Specific tree types include all the generic slots and
47 * their own slots for their trees. We put the implementation
48 * for the RectTreeGeomCache here because we can't shove
49 * the PgSQL specific bits of the code (fcinfo) back into
50 * liblwgeom/lwtree.c, where most of the rect_tree logic lives.
51 */
52 typedef struct {
53  GeomCache gcache;
56 
57 
61 static int
62 RectTreeBuilder(const LWGEOM *lwgeom, GeomCache *cache)
63 {
64  RectTreeGeomCache *rect_cache = (RectTreeGeomCache*)cache;
65  RECT_NODE *tree = rect_tree_from_lwgeom(lwgeom);
66 
67  if ( rect_cache->index )
68  {
69  rect_tree_free(rect_cache->index);
70  rect_cache->index = 0;
71  }
72  if ( ! tree )
73  return LW_FAILURE;
74 
75  rect_cache->index = tree;
76  return LW_SUCCESS;
77 }
78 
79 static int
80 RectTreeFreer(GeomCache *cache)
81 {
82  RectTreeGeomCache *rect_cache = (RectTreeGeomCache*)cache;
83  if ( rect_cache->index )
84  {
85  rect_tree_free(rect_cache->index);
86  rect_cache->index = 0;
87  rect_cache->gcache.argnum = 0;
88  }
89  return LW_SUCCESS;
90 }
91 
92 static GeomCache *
94 {
95  RectTreeGeomCache *cache = palloc(sizeof(RectTreeGeomCache));
96  memset(cache, 0, sizeof(RectTreeGeomCache));
97  return (GeomCache*)cache;
98 }
99 
100 static GeomCacheMethods RectTreeCacheMethods =
101 {
102  RECT_CACHE_ENTRY,
106 };
107 
108 static RectTreeGeomCache *
109 GetRectTreeGeomCache(FunctionCallInfo fcinfo, const GSERIALIZED *g1, const GSERIALIZED *g2)
110 {
111  return (RectTreeGeomCache*)GetGeomCache(fcinfo, &RectTreeCacheMethods, g1, g2);
112 }
113 
114 
115 /**********************************************************************
116 * ST_DistanceRectTree
117 **********************************************************************/
118 
120 Datum ST_DistanceRectTree(PG_FUNCTION_ARGS)
121 {
122  GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
123  GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
124  LWGEOM *lwg1, *lwg2;
125  RECT_NODE *n1, *n2;
126 
127  /* Return NULL on empty arguments. */
129  {
130  PG_FREE_IF_COPY(g1, 0);
131  PG_FREE_IF_COPY(g2, 1);
132  PG_RETURN_NULL();
133  }
134 
135  lwg1 = lwgeom_from_gserialized(g1);
136  lwg2 = lwgeom_from_gserialized(g2);
137 
138  /* Two points? Get outa here... */
139  if (lwg1->type == POINTTYPE && lwg2->type == POINTTYPE)
140  PG_RETURN_FLOAT8(lwgeom_mindistance2d(lwg1, lwg2));
141 
142 
143  n1 = rect_tree_from_lwgeom(lwg1);
144  n2 = rect_tree_from_lwgeom(lwg2);
145  PG_RETURN_FLOAT8(rect_tree_distance_tree(n1, n2, 0.0));
146 }
147 
149 Datum ST_DistanceRectTreeCached(PG_FUNCTION_ARGS)
150 {
151  RectTreeGeomCache *tree_cache = NULL;
152  GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
153  GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
154  LWGEOM *lwg1, *lwg2;
155 
156  /* Return NULL on empty arguments. */
158  {
159  PG_FREE_IF_COPY(g1, 0);
160  PG_FREE_IF_COPY(g2, 1);
161  PG_RETURN_NULL();
162  }
163 
164  lwg1 = lwgeom_from_gserialized(g1);
165  lwg2 = lwgeom_from_gserialized(g2);
166 
167  /* Two points? Get outa here... */
168  if (lwg1->type == POINTTYPE && lwg2->type == POINTTYPE)
169  PG_RETURN_FLOAT8(lwgeom_mindistance2d(lwg1, lwg2));
170 
171  /* Fetch/build our cache, if appropriate, etc... */
172  tree_cache = GetRectTreeGeomCache(fcinfo, g1, g2);
173 
174  if (tree_cache && tree_cache->gcache.argnum)
175  {
176  RECT_NODE *n;
177  RECT_NODE *n_cached = tree_cache->index;;
178  if (tree_cache->gcache.argnum == 1)
179  {
180  n = rect_tree_from_lwgeom(lwg2);
181  }
182  else if (tree_cache->gcache.argnum == 2)
183  {
184  n = rect_tree_from_lwgeom(lwg1);
185  }
186  else
187  {
188  elog(ERROR, "reached unreachable block in %s", __func__);
189  }
190  PG_RETURN_FLOAT8(rect_tree_distance_tree(n, n_cached, 0.0));
191  }
192  else
193  {
194  PG_RETURN_FLOAT8(lwgeom_mindistance2d(lwg1, lwg2));
195  }
196 
197  PG_RETURN_NULL();
198 }
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: g_serialized.c:179
#define LW_FAILURE
Definition: liblwgeom.h:79
#define LW_SUCCESS
Definition: liblwgeom.h:80
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
Definition: measures.c:202
This library is the generic geometry handling section of PostGIS.
static int RectTreeBuilder(const LWGEOM *lwgeom, GeomCache *cache)
Builder, freeer and public accessor for cached RECT_NODE trees.
static GeomCacheMethods RectTreeCacheMethods
Datum ST_DistanceRectTree(PG_FUNCTION_ARGS)
static int RectTreeFreer(GeomCache *cache)
static GeomCache * RectTreeAllocator(void)
PG_FUNCTION_INFO_V1(ST_DistanceRectTree)
Datum ST_DistanceRectTreeCached(PG_FUNCTION_ARGS)
static RectTreeGeomCache * GetRectTreeGeomCache(FunctionCallInfo fcinfo, const GSERIALIZED *g1, const GSERIALIZED *g2)
RECT_NODE * rect_tree_from_lwgeom(const LWGEOM *lwgeom)
Create a tree index on top an LWGEOM.
Definition: lwtree.c:861
void rect_tree_free(RECT_NODE *node)
Recurse from top of node tree and free all children.
Definition: lwtree.c:69
double rect_tree_distance_tree(RECT_NODE *n1, RECT_NODE *n2, double threshold)
Return the distance between two RECT_NODE trees.
Definition: lwtree.c:1354
uint8_t type
Definition: liblwgeom.h:399
RECT_NODE * index