1/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "myisamdef.h"
17
18#ifdef HAVE_SPATIAL
19
20#include "sp_defs.h"
21
22static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
23 uchar byte_order, double *mbr);
24static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
25 uchar byte_order, double *mbr);
26static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
27 uchar byte_order, double *mbr);
28static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
29 uchar byte_order, double *mbr);
30static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
31 double *mbr, int top);
32static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr);
33
34uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key,
35 const uchar *record, my_off_t filepos)
36{
37 HA_KEYSEG *keyseg;
38 MI_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
39 uint len = 0;
40 uchar *pos;
41 uint dlen;
42 uchar *dptr;
43 double mbr[SPDIMS * 2];
44 uint i;
45
46 keyseg = &keyinfo->seg[-1];
47 pos = (uchar*)record + keyseg->start;
48
49 dlen = _mi_calc_blob_length(keyseg->bit_start, pos);
50 memcpy(&dptr, pos + keyseg->bit_start, sizeof(char*));
51 if (!dptr)
52 {
53 my_errno= HA_ERR_NULL_IN_SPATIAL;
54 return 0;
55 }
56 sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr); /* SRID */
57
58 for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
59 {
60 uint length = keyseg->length, start= keyseg->start;
61 double val;
62
63 DBUG_ASSERT(length == sizeof(double));
64 DBUG_ASSERT(!(start % sizeof(double)));
65 DBUG_ASSERT(start < sizeof(mbr));
66 DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE);
67
68 val= mbr[start / sizeof (double)];
69#ifdef HAVE_ISNAN
70 if (isnan(val))
71 {
72 bzero(key, length);
73 key+= length;
74 len+= length;
75 continue;
76 }
77#endif
78
79 if (keyseg->flag & HA_SWAP_KEY)
80 {
81 uchar buf[sizeof(double)];
82
83 float8store(buf, val);
84 pos= &buf[length];
85 while (pos > buf)
86 *key++ = *--pos;
87 }
88 else
89 {
90 float8store((uchar *)key, val);
91 key += length;
92 }
93 len+= length;
94 }
95 _mi_dpointer(info, key, filepos);
96 return len;
97}
98
99/*
100Calculate minimal bounding rectangle (mbr) of the spatial object
101stored in "well-known binary representation" (wkb) format.
102*/
103static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr)
104{
105 uint i;
106
107 for (i=0; i < n_dims; ++i)
108 {
109 mbr[i * 2] = DBL_MAX;
110 mbr[i * 2 + 1] = -DBL_MAX;
111 }
112
113 return sp_get_geometry_mbr(&wkb, wkb + size, n_dims, mbr, 1);
114}
115
116/*
117 Add one point stored in wkb to mbr
118*/
119
120static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
121 uchar byte_order __attribute__((unused)),
122 double *mbr)
123{
124 double ord;
125 double *mbr_end= mbr + n_dims * 2;
126
127 while (mbr < mbr_end)
128 {
129 if ((*wkb) > end - 8)
130 return -1;
131 float8get(ord, (const uchar*) *wkb);
132 (*wkb)+= 8;
133 if (ord < *mbr)
134 *mbr= ord;
135 mbr++;
136 if (ord > *mbr)
137 *mbr= ord;
138 mbr++;
139 }
140 return 0;
141}
142
143
144static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
145 uchar byte_order, double *mbr)
146{
147 return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr);
148}
149
150
151static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
152 uchar byte_order, double *mbr)
153{
154 uint n_points;
155
156 n_points = uint4korr(*wkb);
157 (*wkb) += 4;
158 for (; n_points > 0; --n_points)
159 {
160 /* Add next point to mbr */
161 if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
162 return -1;
163 }
164 return 0;
165}
166
167
168static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
169 uchar byte_order, double *mbr)
170{
171 uint n_linear_rings;
172 uint n_points;
173
174 n_linear_rings = uint4korr((*wkb));
175 (*wkb) += 4;
176
177 for (; n_linear_rings > 0; --n_linear_rings)
178 {
179 n_points = uint4korr((*wkb));
180 (*wkb) += 4;
181 for (; n_points > 0; --n_points)
182 {
183 /* Add next point to mbr */
184 if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
185 return -1;
186 }
187 }
188 return 0;
189}
190
191static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
192 double *mbr, int top)
193{
194 int res;
195 uchar byte_order;
196 uint wkb_type;
197
198 byte_order = *(*wkb);
199 ++(*wkb);
200
201 wkb_type = uint4korr((*wkb));
202 (*wkb) += 4;
203
204 switch ((enum wkbType) wkb_type)
205 {
206 case wkbPoint:
207 res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr);
208 break;
209 case wkbLineString:
210 res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr);
211 break;
212 case wkbPolygon:
213 res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr);
214 break;
215 case wkbMultiPoint:
216 {
217 uint n_items;
218 n_items = uint4korr((*wkb));
219 (*wkb) += 4;
220 for (; n_items > 0; --n_items)
221 {
222 byte_order = *(*wkb);
223 ++(*wkb);
224 (*wkb) += 4;
225 if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr))
226 return -1;
227 }
228 res = 0;
229 break;
230 }
231 case wkbMultiLineString:
232 {
233 uint n_items;
234 n_items = uint4korr((*wkb));
235 (*wkb) += 4;
236 for (; n_items > 0; --n_items)
237 {
238 byte_order = *(*wkb);
239 ++(*wkb);
240 (*wkb) += 4;
241 if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr))
242 return -1;
243 }
244 res = 0;
245 break;
246 }
247 case wkbMultiPolygon:
248 {
249 uint n_items;
250 n_items = uint4korr((*wkb));
251 (*wkb) += 4;
252 for (; n_items > 0; --n_items)
253 {
254 byte_order = *(*wkb);
255 ++(*wkb);
256 (*wkb) += 4;
257 if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr))
258 return -1;
259 }
260 res = 0;
261 break;
262 }
263 case wkbGeometryCollection:
264 {
265 uint n_items;
266
267 if (!top)
268 return -1;
269
270 n_items = uint4korr((*wkb));
271 (*wkb) += 4;
272 for (; n_items > 0; --n_items)
273 {
274 if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0))
275 return -1;
276 }
277 res = 0;
278 break;
279 }
280 default:
281 res = -1;
282 }
283 return res;
284}
285
286#endif /*HAVE_SPATIAL*/
287