1/*
2 Copyright (c) 2002, 2013, Oracle and/or its affiliates.
3 Copyright (c) 2011, 2013, Monty Program Ab.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "mariadb.h"
19#include "sql_priv.h"
20#include "spatial.h"
21#include "gstream.h" // Gis_read_stream
22#include "sql_string.h" // String
23
24/* This is from item_func.h. Didn't want to #include the whole file. */
25double my_double_round(double value, longlong dec, bool dec_unsigned,
26 bool truncate);
27
28#ifdef HAVE_SPATIAL
29
30/*
31 exponential notation :
32 1 sign
33 1 number before the decimal point
34 1 decimal point
35 14 number of significant digits (see String::qs_append(double))
36 1 'e' sign
37 1 exponent sign
38 3 exponent digits
39 ==
40 22
41
42 "f" notation :
43 1 optional 0
44 1 sign
45 14 number significant digits (see String::qs_append(double) )
46 1 decimal point
47 ==
48 17
49*/
50
51#define MAX_DIGITS_IN_DOUBLE MY_GCVT_MAX_FIELD_WIDTH
52
53/***************************** Gis_class_info *******************************/
54
55String Geometry::bad_geometry_data("Bad object", &my_charset_bin);
56
57Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_last+1]=
58{
59 NULL, NULL, NULL, NULL, NULL, NULL, NULL
60};
61
62static Geometry::Class_info **ci_collection_end=
63 Geometry::ci_collection+Geometry::wkb_last + 1;
64
65Geometry::Class_info::Class_info(const char *name, const char *geojson_name,
66 int type_id, create_geom_t create_func):
67 m_type_id(type_id), m_create_func(create_func)
68{
69 m_name.str= (char *) name;
70 m_name.length= strlen(name);
71 m_geojson_name.str= (char *) geojson_name;
72 m_geojson_name.length= strlen(geojson_name);
73
74 ci_collection[type_id]= this;
75}
76
77static Geometry *create_point(char *buffer)
78{
79 return new (buffer) Gis_point;
80}
81
82static Geometry *create_linestring(char *buffer)
83{
84 return new (buffer) Gis_line_string;
85}
86
87static Geometry *create_polygon(char *buffer)
88{
89 return new (buffer) Gis_polygon;
90}
91
92static Geometry *create_multipoint(char *buffer)
93{
94 return new (buffer) Gis_multi_point;
95}
96
97static Geometry *create_multipolygon(char *buffer)
98{
99 return new (buffer) Gis_multi_polygon;
100}
101
102static Geometry *create_multilinestring(char *buffer)
103{
104 return new (buffer) Gis_multi_line_string;
105}
106
107static Geometry *create_geometrycollection(char *buffer)
108{
109 return new (buffer) Gis_geometry_collection;
110}
111
112
113
114static Geometry::Class_info point_class("POINT", "Point",
115 Geometry::wkb_point, create_point);
116
117static Geometry::Class_info linestring_class("LINESTRING", "LineString",
118 Geometry::wkb_linestring,
119 create_linestring);
120static Geometry::Class_info polygon_class("POLYGON", "Polygon",
121 Geometry::wkb_polygon,
122 create_polygon);
123static Geometry::Class_info multipoint_class("MULTIPOINT", "MultiPoint",
124 Geometry::wkb_multipoint,
125 create_multipoint);
126static Geometry::Class_info
127multilinestring_class("MULTILINESTRING", "MultiLineString",
128 Geometry::wkb_multilinestring, create_multilinestring);
129static Geometry::Class_info multipolygon_class("MULTIPOLYGON", "MultiPolygon",
130 Geometry::wkb_multipolygon,
131 create_multipolygon);
132static Geometry::Class_info
133geometrycollection_class("GEOMETRYCOLLECTION", "GeometryCollection",
134 Geometry::wkb_geometrycollection,
135 create_geometrycollection);
136
137static void get_point(double *x, double *y, const char *data)
138{
139 float8get(*x, data);
140 float8get(*y, data + SIZEOF_STORED_DOUBLE);
141}
142
143/***************************** Geometry *******************************/
144
145Geometry::Class_info *Geometry::find_class(const char *name, size_t len)
146{
147 for (Class_info **cur_rt= ci_collection;
148 cur_rt < ci_collection_end; cur_rt++)
149 {
150 if (*cur_rt &&
151 ((*cur_rt)->m_name.length == len) &&
152 (my_strnncoll(&my_charset_latin1,
153 (const uchar*) (*cur_rt)->m_name.str, len,
154 (const uchar*) name, len) == 0))
155 return *cur_rt;
156 }
157 return 0;
158}
159
160
161Geometry *Geometry::create_by_typeid(Geometry_buffer *buffer, int type_id)
162{
163 Class_info *ci;
164 if (!(ci= find_class(type_id)))
165 return NULL;
166 return (*ci->m_create_func)(buffer->data);
167}
168
169
170Geometry *Geometry::construct(Geometry_buffer *buffer,
171 const char *data, uint32 data_len)
172{
173 uint32 geom_type;
174 Geometry *result;
175
176 if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4)
177 return NULL;
178 /* + 1 to skip the byte order (stored in position SRID_SIZE). */
179 geom_type= uint4korr(data + SRID_SIZE + 1);
180 if (!(result= create_by_typeid(buffer, (int) geom_type)))
181 return NULL;
182 result->m_data= data+ SRID_SIZE + WKB_HEADER_SIZE;
183 result->m_data_end= data + data_len;
184 return result;
185}
186
187
188Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
189 Gis_read_stream *trs, String *wkt,
190 bool init_stream)
191{
192 LEX_STRING name;
193 Class_info *ci;
194 char next_sym;
195
196 if (trs->get_next_word(&name))
197 {
198 trs->set_error_msg("Geometry name expected");
199 return NULL;
200 }
201 if (!(ci= find_class(name.str, name.length)) ||
202 wkt->reserve(1 + 4, 512))
203 return NULL;
204 Geometry *result= (*ci->m_create_func)(buffer->data);
205 wkt->q_append((char) wkb_ndr);
206 wkt->q_append((uint32) result->get_class_info()->m_type_id);
207 if (!(next_sym= trs->next_symbol()))
208 return NULL;
209 if (!(next_sym= trs->next_symbol()))
210 return NULL;
211 if ((next_sym == '(' && trs->check_next_symbol('(')) ||
212 result->init_from_wkt(trs, wkt) ||
213 (next_sym == '(' && trs->check_next_symbol(')')))
214 return NULL;
215 if (init_stream)
216 {
217 result->set_data_ptr(wkt->ptr(), wkt->length());
218 result->shift_wkb_header();
219 }
220 return result;
221}
222
223
224int Geometry::as_wkt(String *wkt, const char **end)
225{
226 uint32 len= (uint) get_class_info()->m_name.length;
227 if (wkt->reserve(len + 2, 512))
228 return 1;
229 wkt->qs_append(get_class_info()->m_name.str, len);
230 if (get_class_info() != &geometrycollection_class)
231 wkt->qs_append('(');
232 if (get_data_as_wkt(wkt, end))
233 return 1;
234 if (get_class_info() != &geometrycollection_class)
235 wkt->qs_append(')');
236 return 0;
237}
238
239
240static const uchar type_keyname[]= "type";
241static const int type_keyname_len= 4;
242static const uchar coord_keyname[]= "coordinates";
243static const int coord_keyname_len= 11;
244static const uchar geometries_keyname[]= "geometries";
245static const int geometries_keyname_len= 10;
246static const uchar features_keyname[]= "features";
247static const int features_keyname_len= 8;
248static const uchar geometry_keyname[]= "geometry";
249static const int geometry_keyname_len= 8;
250
251static const int max_keyname_len= 11; /*'coordinates' keyname is the longest.*/
252
253static const uchar feature_type[]= "feature";
254static const int feature_type_len= 7;
255static const uchar feature_coll_type[]= "featurecollection";
256static const int feature_coll_type_len= 17;
257static const uchar bbox_keyname[]= "bbox";
258static const int bbox_keyname_len= 4;
259
260
261int Geometry::as_json(String *wkt, uint max_dec_digits, const char **end)
262{
263 uint32 len= (uint) get_class_info()->m_geojson_name.length;
264 if (wkt->reserve(4 + type_keyname_len + 2 + len + 2 + 2 +
265 coord_keyname_len + 4, 512))
266 return 1;
267 wkt->qs_append("\"", 1);
268 wkt->qs_append((const char *) type_keyname, type_keyname_len);
269 wkt->qs_append("\": \"", 4);
270 wkt->qs_append(get_class_info()->m_geojson_name.str, len);
271 wkt->qs_append("\", \"", 4);
272 if (get_class_info() == &geometrycollection_class)
273 wkt->qs_append((const char *) geometries_keyname, geometries_keyname_len);
274 else
275 wkt->qs_append((const char *) coord_keyname, coord_keyname_len);
276
277 wkt->qs_append("\": ", 3);
278 if (get_data_as_json(wkt, max_dec_digits, end))
279 return 1;
280
281 return 0;
282}
283
284
285int Geometry::bbox_as_json(String *wkt)
286{
287 MBR mbr;
288 const char *end;
289 if (wkt->reserve(5 + bbox_keyname_len + (FLOATING_POINT_DECIMALS+2)*4, 512))
290 return 1;
291 wkt->qs_append("\"", 1);
292 wkt->qs_append((const char *) bbox_keyname, bbox_keyname_len);
293 wkt->qs_append("\": [", 4);
294
295 if (get_mbr(&mbr, &end))
296 return 1;
297
298 wkt->qs_append(mbr.xmin);
299 wkt->qs_append(", ", 2);
300 wkt->qs_append(mbr.ymin);
301 wkt->qs_append(", ", 2);
302 wkt->qs_append(mbr.xmax);
303 wkt->qs_append(", ", 2);
304 wkt->qs_append(mbr.ymax);
305 wkt->qs_append("]", 1);
306
307 return 0;
308}
309
310
311static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
312{
313 double res;
314 if (bo != Geometry::wkb_xdr)
315 {
316 float8get(res, ptr);
317 }
318 else
319 {
320 char inv_array[8];
321 inv_array[0]= ptr[7];
322 inv_array[1]= ptr[6];
323 inv_array[2]= ptr[5];
324 inv_array[3]= ptr[4];
325 inv_array[4]= ptr[3];
326 inv_array[5]= ptr[2];
327 inv_array[6]= ptr[1];
328 inv_array[7]= ptr[0];
329 float8get(res, inv_array);
330 }
331 return res;
332}
333
334
335static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
336{
337 if (bo != Geometry::wkb_xdr)
338 return uint4korr(ptr);
339 /* else */
340 {
341 char inv_array[4];
342 inv_array[0]= ptr[3];
343 inv_array[1]= ptr[2];
344 inv_array[2]= ptr[1];
345 inv_array[3]= ptr[0];
346 return uint4korr(inv_array);
347 }
348}
349
350
351Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
352 const char *wkb, uint32 len, String *res)
353{
354 uint32 geom_type;
355 Geometry *geom;
356
357 if (len < WKB_HEADER_SIZE)
358 return NULL;
359 geom_type= wkb_get_uint(wkb+1, (wkbByteOrder)wkb[0]);
360 if (!(geom= create_by_typeid(buffer, (int) geom_type)) ||
361 res->reserve(WKB_HEADER_SIZE, 512))
362 return NULL;
363
364 res->q_append((char) wkb_ndr);
365 res->q_append(geom_type);
366
367 return geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
368 (wkbByteOrder) wkb[0], res) ? geom : NULL;
369}
370
371
372Geometry *Geometry::create_from_json(Geometry_buffer *buffer,
373 json_engine_t *je, bool er_on_3D, String *res)
374{
375 Class_info *ci= NULL;
376 const uchar *coord_start= NULL, *geom_start= NULL,
377 *features_start= NULL, *geometry_start= NULL;
378 Geometry *result;
379 uchar key_buf[max_keyname_len];
380 uint key_len;
381 int fcoll_type_found= 0, feature_type_found= 0;
382
383
384 if (json_read_value(je))
385 goto err_return;
386
387 if (je->value_type != JSON_VALUE_OBJECT)
388 {
389 je->s.error= GEOJ_INCORRECT_GEOJSON;
390 goto err_return;
391 }
392
393 while (json_scan_next(je) == 0 && je->state != JST_OBJ_END)
394 {
395 DBUG_ASSERT(je->state == JST_KEY);
396
397 key_len=0;
398 while (json_read_keyname_chr(je) == 0)
399 {
400 if (je->s.c_next > 127 || key_len >= max_keyname_len)
401 {
402 /* Symbol out of range, or keyname too long. No need to compare.. */
403 key_len=0;
404 break;
405 }
406 key_buf[key_len++]= (uchar)je->s.c_next | 0x20; /* make it lowercase. */
407 }
408
409 if (unlikely(je->s.error))
410 goto err_return;
411
412 if (key_len == type_keyname_len &&
413 memcmp(key_buf, type_keyname, type_keyname_len) == 0)
414 {
415 /*
416 Found the "type" key. Let's check it's a string and remember
417 the feature's type.
418 */
419 if (json_read_value(je))
420 goto err_return;
421
422 if (je->value_type == JSON_VALUE_STRING)
423 {
424 if ((ci= find_class((const char *) je->value, je->value_len)))
425 {
426 if ((coord_start=
427 (ci == &geometrycollection_class) ? geom_start : coord_start))
428 goto create_geom;
429 }
430 else if (je->value_len == feature_coll_type_len &&
431 my_strnncoll(&my_charset_latin1, je->value, je->value_len,
432 feature_coll_type, feature_coll_type_len) == 0)
433 {
434 /*
435 'FeatureCollection' type found. Handle the 'Featurecollection'/'features'
436 GeoJSON construction.
437 */
438 if (features_start)
439 goto handle_feature_collection;
440 fcoll_type_found= 1;
441 }
442 else if (je->value_len == feature_type_len &&
443 my_strnncoll(&my_charset_latin1, je->value, je->value_len,
444 feature_type, feature_type_len) == 0)
445 {
446 if (geometry_start)
447 goto handle_geometry_key;
448 feature_type_found= 1;
449 }
450 }
451 }
452 else if (key_len == coord_keyname_len &&
453 memcmp(key_buf, coord_keyname, coord_keyname_len) == 0)
454 {
455 /*
456 Found the "coordinates" key. Let's check it's an array
457 and remember where it starts.
458 */
459 if (json_read_value(je))
460 goto err_return;
461
462 if (je->value_type == JSON_VALUE_ARRAY)
463 {
464 coord_start= je->value_begin;
465 if (ci && ci != &geometrycollection_class)
466 goto create_geom;
467 }
468 }
469 else if (key_len == geometries_keyname_len &&
470 memcmp(key_buf, geometries_keyname, geometries_keyname_len) == 0)
471 {
472 /*
473 Found the "geometries" key. Let's check it's an array
474 and remember where it starts.
475 */
476 if (json_read_value(je))
477 goto err_return;
478
479 if (je->value_type == JSON_VALUE_ARRAY)
480 {
481 geom_start= je->value_begin;
482 if (ci == &geometrycollection_class)
483 {
484 coord_start= geom_start;
485 goto create_geom;
486 }
487 }
488 }
489 else if (key_len == features_keyname_len &&
490 memcmp(key_buf, features_keyname, features_keyname_len) == 0)
491 {
492 /*
493 'features' key found. Handle the 'Featurecollection'/'features'
494 GeoJSON construction.
495 */
496 if (json_read_value(je))
497 goto err_return;
498 if (je->value_type == JSON_VALUE_ARRAY)
499 {
500 features_start= je->value_begin;
501 if (fcoll_type_found)
502 goto handle_feature_collection;
503 }
504 }
505 else if (key_len == geometry_keyname_len &&
506 memcmp(key_buf, geometry_keyname, geometry_keyname_len) == 0)
507 {
508 if (json_read_value(je))
509 goto err_return;
510 if (je->value_type == JSON_VALUE_OBJECT)
511 {
512 geometry_start= je->value_begin;
513 if (feature_type_found)
514 goto handle_geometry_key;
515 }
516 }
517 else
518 {
519 if (json_skip_key(je))
520 goto err_return;
521 }
522 }
523
524 if (je->s.error == 0)
525 {
526 /*
527 We didn't find all the required keys. That are "type" and "coordinates"
528 or "geometries" for GeometryCollection.
529 */
530 je->s.error= GEOJ_INCORRECT_GEOJSON;
531 }
532 goto err_return;
533
534handle_feature_collection:
535 ci= &geometrycollection_class;
536 coord_start= features_start;
537
538create_geom:
539
540 json_scan_start(je, je->s.cs, coord_start, je->s.str_end);
541
542 if (res->reserve(1 + 4, 512))
543 goto err_return;
544
545 result= (*ci->m_create_func)(buffer->data);
546 res->q_append((char) wkb_ndr);
547 res->q_append((uint32) result->get_class_info()->m_type_id);
548 if (result->init_from_json(je, er_on_3D, res))
549 goto err_return;
550
551 return result;
552
553handle_geometry_key:
554 json_scan_start(je, je->s.cs, geometry_start, je->s.str_end);
555 return create_from_json(buffer, je, er_on_3D, res);
556
557err_return:
558 return NULL;
559}
560
561
562Geometry *Geometry::create_from_opresult(Geometry_buffer *g_buf,
563 String *res, Gcalc_result_receiver &rr)
564{
565 uint32 geom_type= rr.get_result_typeid();
566 Geometry *obj= create_by_typeid(g_buf, geom_type);
567
568 if (!obj || res->reserve(WKB_HEADER_SIZE, 512))
569 return NULL;
570
571 res->q_append((char) wkb_ndr);
572 res->q_append(geom_type);
573 return obj->init_from_opresult(res, rr.result(), rr.length()) ? obj : NULL;
574}
575
576
577bool Geometry::envelope(String *result) const
578{
579 MBR mbr;
580 const char *end;
581
582 if (get_mbr(&mbr, &end))
583 return 1;
584
585 if (!mbr.valid())
586 {
587 /* Empty geometry */
588 if (result->reserve(1 + 4*2))
589 return 1;
590 result->q_append((char) wkb_ndr);
591 result->q_append((uint32) wkb_geometrycollection);
592 result->q_append((uint32) 0);
593 return 0;
594 }
595 if (result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10))
596 return 1;
597
598 result->q_append((char) wkb_ndr);
599 result->q_append((uint32) wkb_polygon);
600 result->q_append((uint32) 1);
601 result->q_append((uint32) 5);
602 result->q_append(mbr.xmin);
603 result->q_append(mbr.ymin);
604 result->q_append(mbr.xmax);
605 result->q_append(mbr.ymin);
606 result->q_append(mbr.xmax);
607 result->q_append(mbr.ymax);
608 result->q_append(mbr.xmin);
609 result->q_append(mbr.ymax);
610 result->q_append(mbr.xmin);
611 result->q_append(mbr.ymin);
612
613 return 0;
614}
615
616
617/*
618 Create a point from data.
619
620 SYNPOSIS
621 create_point()
622 result Put result here
623 data Data for point is here.
624
625 RETURN
626 0 ok
627 1 Can't reallocate 'result'
628*/
629
630bool Geometry::create_point(String *result, const char *data) const
631{
632 if (no_data(data, POINT_DATA_SIZE) ||
633 result->reserve(1 + 4 + POINT_DATA_SIZE))
634 return 1;
635 result->q_append((char) wkb_ndr);
636 result->q_append((uint32) wkb_point);
637 /* Copy two double in same format */
638 result->q_append(data, POINT_DATA_SIZE);
639 return 0;
640}
641
642/*
643 Create a point from coordinates.
644
645 SYNPOSIS
646 create_point()
647 result Put result here
648 x x coordinate for point
649 y y coordinate for point
650
651 RETURN
652 0 ok
653 1 Can't reallocate 'result'
654*/
655
656bool Geometry::create_point(String *result, double x, double y)
657{
658 if (result->reserve(1 + 4 + POINT_DATA_SIZE))
659 return 1;
660
661 result->q_append((char) wkb_ndr);
662 result->q_append((uint32) wkb_point);
663 result->q_append(x);
664 result->q_append(y);
665 return 0;
666}
667
668/*
669 Append N points from packed format to text
670
671 SYNOPSIS
672 append_points()
673 txt Append points here
674 n_points Number of points
675 data Packed data
676 offset Offset between points
677
678 RETURN
679 # end of data
680*/
681
682const char *Geometry::append_points(String *txt, uint32 n_points,
683 const char *data, uint32 offset) const
684{
685 while (n_points--)
686 {
687 double x,y;
688 data+= offset;
689 get_point(&x, &y, data);
690 data+= POINT_DATA_SIZE;
691 txt->qs_append(x);
692 txt->qs_append(' ');
693 txt->qs_append(y);
694 txt->qs_append(',');
695 }
696 return data;
697}
698
699
700static void append_json_point(String *txt, uint max_dec, const char *data)
701{
702 double x,y;
703 get_point(&x, &y, data);
704 if (max_dec < FLOATING_POINT_DECIMALS)
705 {
706 x= my_double_round(x, max_dec, FALSE, FALSE);
707 y= my_double_round(y, max_dec, FALSE, FALSE);
708 }
709 txt->qs_append('[');
710 txt->qs_append(x);
711 txt->qs_append(", ", 2);
712 txt->qs_append(y);
713 txt->qs_append(']');
714}
715
716
717/*
718 Append N points from packed format to json
719
720 SYNOPSIS
721 append_json_points()
722 txt Append points here
723 n_points Number of points
724 data Packed data
725 offset Offset between points
726
727 RETURN
728 # end of data
729*/
730
731static const char *append_json_points(String *txt, uint max_dec,
732 uint32 n_points, const char *data, uint32 offset)
733{
734 txt->qs_append('[');
735 while (n_points--)
736 {
737 data+= offset;
738 append_json_point(txt, max_dec, data);
739 data+= POINT_DATA_SIZE;
740 txt->qs_append(", ", 2);
741 }
742 txt->length(txt->length() - 2);// Remove ending ', '
743 txt->qs_append(']');
744 return data;
745}
746/*
747 Get most bounding rectangle (mbr) for X points
748
749 SYNOPSIS
750 get_mbr_for_points()
751 mbr MBR (store rectangle here)
752 points Number of points
753 data Packed data
754 offset Offset between points
755
756 RETURN
757 0 Wrong data
758 # end of data
759*/
760
761const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
762 uint offset) const
763{
764 uint32 points;
765 /* read number of points */
766 if (no_data(data, 4))
767 return 0;
768 points= uint4korr(data);
769 data+= 4;
770
771 if (not_enough_points(data, points, offset))
772 return 0;
773
774 /* Calculate MBR for points */
775 while (points--)
776 {
777 data+= offset;
778 mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE);
779 data+= POINT_DATA_SIZE;
780 }
781 return data;
782}
783
784
785/***************************** Point *******************************/
786
787uint32 Gis_point::get_data_size() const
788{
789 return POINT_DATA_SIZE;
790}
791
792
793bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
794{
795 double x, y;
796 if (trs->get_next_number(&x) || trs->get_next_number(&y) ||
797 wkb->reserve(POINT_DATA_SIZE, 512))
798 return 1;
799 wkb->q_append(x);
800 wkb->q_append(y);
801 return 0;
802}
803
804
805uint Gis_point::init_from_wkb(const char *wkb, uint len,
806 wkbByteOrder bo, String *res)
807{
808 double x, y;
809 if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE))
810 return 0;
811 x= wkb_get_double(wkb, bo);
812 y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
813 res->q_append(x);
814 res->q_append(y);
815 return POINT_DATA_SIZE;
816}
817
818
819static int read_point_from_json(json_engine_t *je, bool er_on_3D,
820 double *x, double *y)
821{
822 int n_coord= 0, err;
823 double tmp, *d;
824 char *endptr;
825
826 while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
827 {
828 DBUG_ASSERT(je->state == JST_VALUE);
829 if (json_read_value(je))
830 return 1;
831
832 if (je->value_type != JSON_VALUE_NUMBER)
833 goto bad_coordinates;
834
835 d= (n_coord == 0) ? x : ((n_coord == 1) ? y : &tmp);
836 *d= my_strntod(je->s.cs, (char *) je->value,
837 je->value_len, &endptr, &err);
838 if (err)
839 goto bad_coordinates;
840 n_coord++;
841 }
842
843 if (n_coord <= 2 || !er_on_3D)
844 return 0;
845 je->s.error= Geometry::GEOJ_DIMENSION_NOT_SUPPORTED;
846 return 1;
847bad_coordinates:
848 je->s.error= Geometry::GEOJ_INCORRECT_GEOJSON;
849 return 1;
850}
851
852
853bool Gis_point::init_from_json(json_engine_t *je, bool er_on_3D, String *wkb)
854{
855 double x, y;
856 if (json_read_value(je))
857 return TRUE;
858
859 if (je->value_type != JSON_VALUE_ARRAY)
860 {
861 je->s.error= GEOJ_INCORRECT_GEOJSON;
862 return TRUE;
863 }
864
865 if (read_point_from_json(je, er_on_3D, &x, &y) ||
866 wkb->reserve(POINT_DATA_SIZE))
867 return TRUE;
868
869 wkb->q_append(x);
870 wkb->q_append(y);
871 return FALSE;
872}
873
874
875bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
876{
877 double x, y;
878 if (get_xy(&x, &y))
879 return 1;
880 if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
881 return 1;
882 txt->qs_append(x);
883 txt->qs_append(' ');
884 txt->qs_append(y);
885 *end= m_data+ POINT_DATA_SIZE;
886 return 0;
887}
888
889
890bool Gis_point::get_data_as_json(String *txt, uint max_dec_digits,
891 const char **end) const
892{
893 if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 4))
894 return 1;
895 append_json_point(txt, max_dec_digits, m_data);
896 *end= m_data+ POINT_DATA_SIZE;
897 return 0;
898}
899
900
901bool Gis_point::get_mbr(MBR *mbr, const char **end) const
902{
903 double x, y;
904 if (get_xy(&x, &y))
905 return 1;
906 mbr->add_xy(x, y);
907 *end= m_data+ POINT_DATA_SIZE;
908 return 0;
909}
910
911
912int Gis_point::area(double *ar, const char **end) const
913{
914 *ar= 0;
915 *end= m_data+ POINT_DATA_SIZE;
916 return 0;
917}
918
919
920int Gis_point::geom_length(double *len, const char **end) const
921{
922 *len= 0;
923 *end= m_data+ POINT_DATA_SIZE;
924 return 0;
925}
926
927
928int Gis_point::store_shapes(Gcalc_shape_transporter *trn) const
929{
930 double x, y;
931
932 return get_xy(&x, &y) || trn->single_point(x, y);
933}
934
935
936const Geometry::Class_info *Gis_point::get_class_info() const
937{
938 return &point_class;
939}
940
941
942/***************************** LineString *******************************/
943
944uint32 Gis_line_string::get_data_size() const
945{
946 uint32 n_points;
947 if (no_data(m_data, 4))
948 return GET_SIZE_ERROR;
949
950 n_points= uint4korr(m_data);
951
952 if (not_enough_points(m_data + 4, n_points))
953 return GET_SIZE_ERROR;
954
955 return 4 + n_points * POINT_DATA_SIZE;
956}
957
958
959bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
960{
961 uint32 n_points= 0;
962 uint32 np_pos= wkb->length();
963 Gis_point p;
964
965 if (wkb->reserve(4, 512))
966 return 1;
967 wkb->length(wkb->length()+4); // Reserve space for points
968
969 for (;;)
970 {
971 if (p.init_from_wkt(trs, wkb))
972 return 1;
973 n_points++;
974 if (trs->skip_char(',')) // Didn't find ','
975 break;
976 }
977 if (n_points < 1)
978 {
979 trs->set_error_msg("Too few points in LINESTRING");
980 return 1;
981 }
982 wkb->write_at_position(np_pos, n_points);
983 return 0;
984}
985
986
987uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
988 wkbByteOrder bo, String *res)
989{
990 uint32 n_points, proper_length;
991 const char *wkb_end;
992 Gis_point p;
993
994 if (len < 4 || (n_points= wkb_get_uint(wkb, bo)) < 1 ||
995 ((len - 4) / POINT_DATA_SIZE) < n_points)
996 return 0;
997 proper_length= 4 + n_points * POINT_DATA_SIZE;
998
999 if (len < proper_length || res->reserve(proper_length))
1000 return 0;
1001
1002 res->q_append(n_points);
1003 wkb_end= wkb + proper_length;
1004 for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE)
1005 {
1006 if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res))
1007 return 0;
1008 }
1009
1010 return proper_length;
1011}
1012
1013
1014bool Gis_line_string::init_from_json(json_engine_t *je, bool er_on_3D,
1015 String *wkb)
1016{
1017 uint32 n_points= 0;
1018 uint32 np_pos= wkb->length();
1019 Gis_point p;
1020
1021 if (json_read_value(je))
1022 return TRUE;
1023
1024 if (je->value_type != JSON_VALUE_ARRAY)
1025 {
1026 je->s.error= GEOJ_INCORRECT_GEOJSON;
1027 return TRUE;
1028 }
1029
1030 if (wkb->reserve(4, 512))
1031 return TRUE;
1032 wkb->length(wkb->length()+4); // Reserve space for n_points
1033
1034 while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
1035 {
1036 DBUG_ASSERT(je->state == JST_VALUE);
1037
1038 if (p.init_from_json(je, er_on_3D, wkb))
1039 return TRUE;
1040 n_points++;
1041 }
1042 if (n_points < 1)
1043 {
1044 je->s.error= Geometry::GEOJ_TOO_FEW_POINTS;
1045 return TRUE;
1046 }
1047 wkb->write_at_position(np_pos, n_points);
1048 return FALSE;
1049}
1050
1051
1052bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
1053{
1054 uint32 n_points;
1055 const char *data= m_data;
1056
1057 if (no_data(data, 4))
1058 return 1;
1059 n_points= uint4korr(data);
1060 data += 4;
1061
1062 if (n_points < 1 ||
1063 not_enough_points(data, n_points) ||
1064 txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
1065 return 1;
1066
1067 while (n_points--)
1068 {
1069 double x, y;
1070 get_point(&x, &y, data);
1071 data+= POINT_DATA_SIZE;
1072 txt->qs_append(x);
1073 txt->qs_append(' ');
1074 txt->qs_append(y);
1075 txt->qs_append(',');
1076 }
1077 txt->length(txt->length() - 1); // Remove end ','
1078 *end= data;
1079 return 0;
1080}
1081
1082
1083bool Gis_line_string::get_data_as_json(String *txt, uint max_dec_digits,
1084 const char **end) const
1085{
1086 uint32 n_points;
1087 const char *data= m_data;
1088
1089 if (no_data(data, 4))
1090 return 1;
1091 n_points= uint4korr(data);
1092 data += 4;
1093
1094 if (n_points < 1 ||
1095 not_enough_points(data, n_points) ||
1096 txt->reserve((MAX_DIGITS_IN_DOUBLE*2 + 6) * n_points + 2))
1097 return 1;
1098
1099 *end= append_json_points(txt, max_dec_digits, n_points, data, 0);
1100
1101 return 0;
1102}
1103
1104
1105bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
1106{
1107 return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0;
1108}
1109
1110
1111int Gis_line_string::geom_length(double *len, const char **end) const
1112{
1113 uint32 n_points;
1114 double prev_x, prev_y;
1115 const char *data= m_data;
1116
1117 *len= 0; // In case of errors
1118 if (no_data(data, 4))
1119 return 1;
1120 n_points= uint4korr(data);
1121 data+= 4;
1122 if (n_points < 1 || not_enough_points(data, n_points))
1123 return 1;
1124
1125 get_point(&prev_x, &prev_y, data);
1126 data+= POINT_DATA_SIZE;
1127 while (--n_points)
1128 {
1129 double x, y;
1130 get_point(&x, &y, data);
1131 data+= POINT_DATA_SIZE;
1132 *len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
1133 prev_x= x;
1134 prev_y= y;
1135 }
1136 *end= data;
1137 return 0;
1138}
1139
1140
1141int Gis_line_string::area(double *ar, const char **end) const
1142{
1143 uint32 n_points;
1144 *ar= 0.0;
1145
1146 /* read number of points */
1147 if (no_data(m_data, 4))
1148 return 1;
1149 n_points= uint4korr(m_data);
1150 *end= m_data + 4 + POINT_DATA_SIZE * n_points;
1151 return 0;
1152}
1153
1154
1155int Gis_line_string::is_closed(int *closed) const
1156{
1157 uint32 n_points;
1158 double x1, y1, x2, y2;
1159 const char *data= m_data;
1160
1161 if (no_data(data, 4))
1162 return 1;
1163 n_points= uint4korr(data);
1164 if (n_points == 1)
1165 {
1166 *closed=1;
1167 return 0;
1168 }
1169 data+= 4;
1170 if (n_points == 0 || not_enough_points(data, n_points))
1171 return 1;
1172
1173 /* Get first point */
1174 get_point(&x1, &y1, data);
1175
1176 /* get last point */
1177 data+= POINT_DATA_SIZE + (n_points-2)*POINT_DATA_SIZE;
1178 get_point(&x2, &y2, data);
1179
1180 *closed= (x1==x2) && (y1==y2);
1181 return 0;
1182}
1183
1184
1185int Gis_line_string::num_points(uint32 *n_points) const
1186{
1187 *n_points= uint4korr(m_data);
1188 return 0;
1189}
1190
1191
1192int Gis_line_string::start_point(String *result) const
1193{
1194 /* +4 is for skipping over number of points */
1195 return create_point(result, m_data + 4);
1196}
1197
1198
1199int Gis_line_string::end_point(String *result) const
1200{
1201 uint32 n_points;
1202 if (no_data(m_data, 4))
1203 return 1;
1204 n_points= uint4korr(m_data);
1205 if (n_points == 0 || not_enough_points(m_data+4, n_points))
1206 return 1;
1207 return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE);
1208}
1209
1210
1211int Gis_line_string::point_n(uint32 num, String *result) const
1212{
1213 uint32 n_points;
1214 if (no_data(m_data, 4))
1215 return 1;
1216 num--;
1217 n_points= uint4korr(m_data);
1218 if (num >= n_points || not_enough_points(m_data+4, n_points))
1219 return 1;
1220
1221 return create_point(result, m_data + 4 + num*POINT_DATA_SIZE);
1222}
1223
1224
1225int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const
1226{
1227 uint32 n_points;
1228 double x, y;
1229 double UNINIT_VAR(prev_x), UNINIT_VAR(prev_y);
1230 int first_point= 1;
1231 const char *data= m_data;
1232
1233 if (no_data(m_data, 4))
1234 return 1;
1235 n_points= uint4korr(data);
1236 data+= 4;
1237 if (n_points < 1 || not_enough_points(data, n_points))
1238 return 1;
1239
1240 trn->start_line();
1241
1242 while (n_points--)
1243 {
1244 get_point(&x, &y, data);
1245 data+= POINT_DATA_SIZE;
1246 if (!first_point && x == prev_x && y == prev_y)
1247 continue;
1248 if (trn->add_point(x, y))
1249 return 1;
1250 first_point= 0;
1251 prev_x= x;
1252 prev_y= y;
1253 }
1254
1255 return trn->complete_line();
1256}
1257
1258const Geometry::Class_info *Gis_line_string::get_class_info() const
1259{
1260 return &linestring_class;
1261}
1262
1263
1264/***************************** Polygon *******************************/
1265
1266uint32 Gis_polygon::get_data_size() const
1267{
1268 uint32 n_linear_rings;
1269 uint32 n_points;
1270 const char *data= m_data;
1271
1272 if (no_data(data, 4))
1273 return GET_SIZE_ERROR;
1274 n_linear_rings= uint4korr(data);
1275 data+= 4;
1276
1277 while (n_linear_rings--)
1278 {
1279 if (no_data(data, 4) ||
1280 not_enough_points(data+4, n_points= uint4korr(data)))
1281 return GET_SIZE_ERROR;
1282 data+= 4 + n_points*POINT_DATA_SIZE;
1283 }
1284 if (no_data(data, 0))
1285 return GET_SIZE_ERROR;
1286 return (uint32) (data - m_data);
1287}
1288
1289
1290bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
1291{
1292 uint32 n_linear_rings= 0;
1293 uint32 lr_pos= wkb->length();
1294 int closed;
1295
1296 if (wkb->reserve(4, 512))
1297 return 1;
1298 wkb->length(wkb->length()+4); // Reserve space for n_rings
1299 for (;;)
1300 {
1301 Gis_line_string ls;
1302 uint32 ls_pos=wkb->length();
1303 if (trs->check_next_symbol('(') ||
1304 ls.init_from_wkt(trs, wkb) ||
1305 trs->check_next_symbol(')'))
1306 return 1;
1307
1308 ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
1309 if (ls.is_closed(&closed) || !closed)
1310 {
1311 trs->set_error_msg("POLYGON's linear ring isn't closed");
1312 return 1;
1313 }
1314 n_linear_rings++;
1315 if (trs->skip_char(',')) // Didn't find ','
1316 break;
1317 }
1318 wkb->write_at_position(lr_pos, n_linear_rings);
1319 return 0;
1320}
1321
1322
1323uint Gis_polygon::init_from_opresult(String *bin,
1324 const char *opres, uint res_len)
1325{
1326 const char *opres_orig= opres;
1327 uint32 position= bin->length();
1328 uint32 poly_shapes= 0;
1329
1330 if (bin->reserve(4, 512))
1331 return 0;
1332 bin->q_append(poly_shapes);
1333
1334 while (opres_orig + res_len > opres)
1335 {
1336 uint32 n_points, proper_length;
1337 const char *op_end, *p1_position;
1338 Gis_point p;
1339 Gcalc_function::shape_type st;
1340
1341 st= (Gcalc_function::shape_type) uint4korr(opres);
1342 if (poly_shapes && st != Gcalc_function::shape_hole)
1343 break;
1344 poly_shapes++;
1345 n_points= uint4korr(opres + 4) + 1; /* skip shape type id */
1346 proper_length= 4 + n_points * POINT_DATA_SIZE;
1347
1348 if (bin->reserve(proper_length, 512))
1349 return 0;
1350
1351 bin->q_append(n_points);
1352 op_end= opres + 8 + (n_points-1) * 8 * 2;
1353 p1_position= (opres+= 8);
1354 for (; opres<op_end; opres+= POINT_DATA_SIZE)
1355 {
1356 if (!p.init_from_wkb(opres, POINT_DATA_SIZE, wkb_ndr, bin))
1357 return 0;
1358 }
1359 if (!p.init_from_wkb(p1_position, POINT_DATA_SIZE, wkb_ndr, bin))
1360 return 0;
1361 }
1362
1363 bin->write_at_position(position, poly_shapes);
1364
1365 return (uint) (opres - opres_orig);
1366}
1367
1368
1369uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
1370 String *res)
1371{
1372 uint32 n_linear_rings;
1373 const char *wkb_orig= wkb;
1374
1375 if (len < 4)
1376 return 0;
1377
1378 if (!(n_linear_rings= wkb_get_uint(wkb, bo)))
1379 return 0;
1380
1381 if (res->reserve(4, 512))
1382 return 0;
1383 wkb+= 4;
1384 len-= 4;
1385 res->q_append(n_linear_rings);
1386
1387 while (n_linear_rings--)
1388 {
1389 Gis_line_string ls;
1390 uint32 ls_pos= res->length();
1391 int ls_len;
1392 int closed;
1393
1394 if (!(ls_len= ls.init_from_wkb(wkb, len, bo, res)))
1395 return 0;
1396
1397 ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos);
1398
1399 if (ls.is_closed(&closed) || !closed)
1400 return 0;
1401 wkb+= ls_len;
1402 }
1403
1404 return (uint) (wkb - wkb_orig);
1405}
1406
1407
1408bool Gis_polygon::init_from_json(json_engine_t *je, bool er_on_3D, String *wkb)
1409{
1410 uint32 n_linear_rings= 0;
1411 uint32 lr_pos= wkb->length();
1412 int closed;
1413
1414 if (json_read_value(je))
1415 return TRUE;
1416
1417 if (je->value_type != JSON_VALUE_ARRAY)
1418 {
1419 je->s.error= GEOJ_INCORRECT_GEOJSON;
1420 return TRUE;
1421 }
1422
1423 if (wkb->reserve(4, 512))
1424 return TRUE;
1425 wkb->length(wkb->length()+4); // Reserve space for n_rings
1426
1427 while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
1428 {
1429 Gis_line_string ls;
1430 DBUG_ASSERT(je->state == JST_VALUE);
1431
1432 uint32 ls_pos=wkb->length();
1433 if (ls.init_from_json(je, er_on_3D, wkb))
1434 return TRUE;
1435 ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
1436 if (ls.is_closed(&closed) || !closed)
1437 {
1438 je->s.error= GEOJ_POLYGON_NOT_CLOSED;
1439 return TRUE;
1440 }
1441 n_linear_rings++;
1442 }
1443
1444 if (je->s.error)
1445 return TRUE;
1446
1447 if (n_linear_rings == 0)
1448 {
1449 je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
1450 return TRUE;
1451 }
1452 wkb->write_at_position(lr_pos, n_linear_rings);
1453 return FALSE;
1454}
1455
1456
1457bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
1458{
1459 uint32 n_linear_rings;
1460 const char *data= m_data;
1461
1462 if (no_data(data, 4))
1463 return 1;
1464
1465 n_linear_rings= uint4korr(data);
1466 data+= 4;
1467
1468 while (n_linear_rings--)
1469 {
1470 uint32 n_points;
1471 if (no_data(data, 4))
1472 return 1;
1473 n_points= uint4korr(data);
1474 data+= 4;
1475 if (not_enough_points(data, n_points) ||
1476 txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
1477 return 1;
1478 txt->qs_append('(');
1479 data= append_points(txt, n_points, data, 0);
1480 (*txt) [txt->length() - 1]= ')'; // Replace end ','
1481 txt->qs_append(',');
1482 }
1483 txt->length(txt->length() - 1); // Remove end ','
1484 *end= data;
1485 return 0;
1486}
1487
1488
1489bool Gis_polygon::get_data_as_json(String *txt, uint max_dec_digits,
1490 const char **end) const
1491{
1492 uint32 n_linear_rings;
1493 const char *data= m_data;
1494
1495 if (no_data(data, 4) || txt->reserve(1, 512))
1496 return 1;
1497
1498 n_linear_rings= uint4korr(data);
1499 data+= 4;
1500
1501 txt->qs_append('[');
1502 while (n_linear_rings--)
1503 {
1504 uint32 n_points;
1505 if (no_data(data, 4))
1506 return 1;
1507 n_points= uint4korr(data);
1508 data+= 4;
1509 if (not_enough_points(data, n_points) ||
1510 txt->reserve(4 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points))
1511 return 1;
1512 data= append_json_points(txt, max_dec_digits, n_points, data, 0);
1513 txt->qs_append(", ", 2);
1514 }
1515 txt->length(txt->length() - 2);// Remove ending ', '
1516 txt->qs_append(']');
1517 *end= data;
1518 return 0;
1519}
1520
1521
1522bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const
1523{
1524 uint32 n_linear_rings;
1525 const char *data= m_data;
1526
1527 if (no_data(data, 4))
1528 return 1;
1529 n_linear_rings= uint4korr(data);
1530 data+= 4;
1531
1532 while (n_linear_rings--)
1533 {
1534 if (!(data= get_mbr_for_points(mbr, data, 0)))
1535 return 1;
1536 }
1537 *end= data;
1538 return 0;
1539}
1540
1541
1542int Gis_polygon::area(double *ar, const char **end_of_data) const
1543{
1544 uint32 n_linear_rings;
1545 double result= -1.0;
1546 const char *data= m_data;
1547
1548 if (no_data(data, 4))
1549 return 1;
1550 n_linear_rings= uint4korr(data);
1551 data+= 4;
1552
1553 while (n_linear_rings--)
1554 {
1555 double prev_x, prev_y;
1556 double lr_area= 0;
1557 uint32 n_points;
1558
1559 if (no_data(data, 4))
1560 return 1;
1561 n_points= uint4korr(data);
1562 if (n_points == 0 ||
1563 not_enough_points(data, n_points))
1564 return 1;
1565 get_point(&prev_x, &prev_y, data+4);
1566 data+= (4+POINT_DATA_SIZE);
1567
1568 while (--n_points) // One point is already read
1569 {
1570 double x, y;
1571 get_point(&x, &y, data);
1572 data+= POINT_DATA_SIZE;
1573 lr_area+= (prev_x + x)* (prev_y - y);
1574 prev_x= x;
1575 prev_y= y;
1576 }
1577 lr_area= fabs(lr_area)/2;
1578 if (result == -1.0)
1579 result= lr_area;
1580 else
1581 result-= lr_area;
1582 }
1583 *ar= fabs(result);
1584 *end_of_data= data;
1585 return 0;
1586}
1587
1588
1589int Gis_polygon::exterior_ring(String *result) const
1590{
1591 uint32 n_points, length;
1592 const char *data= m_data + 4; // skip n_linerings
1593
1594 if (no_data(data, 4))
1595 return 1;
1596 n_points= uint4korr(data);
1597 data+= 4;
1598 length= n_points * POINT_DATA_SIZE;
1599 if (not_enough_points(data, n_points) || result->reserve(1+4+4+ length))
1600 return 1;
1601
1602 result->q_append((char) wkb_ndr);
1603 result->q_append((uint32) wkb_linestring);
1604 result->q_append(n_points);
1605 result->q_append(data, n_points * POINT_DATA_SIZE);
1606 return 0;
1607}
1608
1609
1610int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const
1611{
1612 if (no_data(m_data, 4))
1613 return 1;
1614 *n_int_rings= uint4korr(m_data)-1;
1615 return 0;
1616}
1617
1618
1619int Gis_polygon::interior_ring_n(uint32 num, String *result) const
1620{
1621 const char *data= m_data;
1622 uint32 n_linear_rings;
1623 uint32 n_points;
1624 uint32 points_size;
1625
1626 if (no_data(data, 4))
1627 return 1;
1628 n_linear_rings= uint4korr(data);
1629 data+= 4;
1630
1631 if (num >= n_linear_rings || num < 1)
1632 return 1;
1633
1634 while (num--)
1635 {
1636 if (no_data(data, 4))
1637 return 1;
1638 data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
1639 }
1640 if (no_data(data, 4))
1641 return 1;
1642 n_points= uint4korr(data);
1643 points_size= n_points * POINT_DATA_SIZE;
1644 data+= 4;
1645 if (not_enough_points(data, n_points) || result->reserve(1+4+4+ points_size))
1646 return 1;
1647
1648 result->q_append((char) wkb_ndr);
1649 result->q_append((uint32) wkb_linestring);
1650 result->q_append(n_points);
1651 result->q_append(data, points_size);
1652
1653 return 0;
1654}
1655
1656
1657int Gis_polygon::centroid_xy(double *x, double *y) const
1658{
1659 uint32 n_linear_rings;
1660 double UNINIT_VAR(res_area);
1661 double UNINIT_VAR(res_cx), UNINIT_VAR(res_cy);
1662 const char *data= m_data;
1663 bool first_loop= 1;
1664
1665 if (no_data(data, 4) ||
1666 (n_linear_rings= uint4korr(data)) == 0)
1667 return 1;
1668 data+= 4;
1669
1670 while (n_linear_rings--)
1671 {
1672 uint32 n_points, org_n_points;
1673 double prev_x, prev_y;
1674 double cur_area= 0;
1675 double cur_cx= 0, cur_cy= 0;
1676 double sum_cx= 0, sum_cy= 0;
1677
1678 if (no_data(data, 4))
1679 return 1;
1680 org_n_points= n_points= uint4korr(data);
1681 data+= 4;
1682 if (n_points == 0 || not_enough_points(data, n_points))
1683 return 1;
1684 get_point(&prev_x, &prev_y, data);
1685 data+= POINT_DATA_SIZE;
1686
1687 while (--n_points) // One point is already read
1688 {
1689 double tmp_x, tmp_y;
1690 double loc_area;
1691 get_point(&tmp_x, &tmp_y, data);
1692 data+= POINT_DATA_SIZE;
1693 loc_area= prev_x * tmp_y - tmp_x * prev_y;
1694 cur_area+= loc_area;
1695 cur_cx+= tmp_x;
1696 cur_cy+= tmp_y;
1697 sum_cx+= (prev_x + tmp_x) * loc_area;
1698 sum_cy+= (prev_y + tmp_y) * loc_area;
1699
1700 prev_x= tmp_x;
1701 prev_y= tmp_y;
1702 }
1703
1704 if (fabs(cur_area) > 1e-10)
1705 {
1706 cur_cx= sum_cx / cur_area / 3.0;
1707 cur_cy= sum_cy / cur_area / 3.0;
1708 }
1709 else
1710 {
1711 cur_cx= cur_cx / (org_n_points - 1);
1712 cur_cy= cur_cy / (org_n_points - 1);
1713 }
1714
1715 cur_area= fabs(cur_area);
1716
1717 if (!first_loop)
1718 {
1719 double d_area= fabs(res_area - cur_area);
1720 res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area;
1721 res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area;
1722 }
1723 else
1724 {
1725 first_loop= 0;
1726 res_area= cur_area;
1727 res_cx= cur_cx;
1728 res_cy= cur_cy;
1729 }
1730 }
1731
1732 *x= res_cx;
1733 *y= res_cy;
1734 return 0;
1735}
1736
1737
1738int Gis_polygon::centroid(String *result) const
1739{
1740 double x, y;
1741 if (centroid_xy(&x, &y))
1742 return 1;
1743 return create_point(result, x, y);
1744}
1745
1746
1747int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const
1748{
1749 uint32 n_linear_rings;
1750 const char *data= m_data;
1751 double first_x, first_y;
1752 double prev_x, prev_y;
1753 int was_equal_first= 0;
1754
1755 if (trn->start_poly())
1756 return 1;
1757
1758 if (no_data(data, 4))
1759 return 1;
1760 n_linear_rings= uint4korr(data);
1761 data+= 4;
1762
1763 while (n_linear_rings--)
1764 {
1765 uint32 n_points;
1766
1767 if (no_data(data, 4))
1768 return 1;
1769 n_points= uint4korr(data);
1770 data+= 4;
1771 if (!n_points || not_enough_points(data, n_points))
1772 return 1;
1773
1774 trn->start_ring();
1775 get_point(&first_x, &first_y, data);
1776 data+= POINT_DATA_SIZE;
1777
1778 prev_x= first_x;
1779 prev_y= first_y;
1780 if (trn->add_point(first_x, first_y))
1781 return 1;
1782
1783 if (--n_points == 0)
1784 goto single_point_ring;
1785
1786 while (--n_points)
1787 {
1788 double x, y;
1789 get_point(&x, &y, data);
1790 data+= POINT_DATA_SIZE;
1791 if (x == prev_x && y == prev_y)
1792 continue;
1793 prev_x= x;
1794 prev_y= y;
1795 if (was_equal_first)
1796 {
1797 if (trn->add_point(first_x, first_y))
1798 return 1;
1799 was_equal_first= 0;
1800 }
1801 if (x == first_x && y == first_y)
1802 {
1803 was_equal_first= 1;
1804 continue;
1805 }
1806 if (trn->add_point(x, y))
1807 return 1;
1808 }
1809 data+= POINT_DATA_SIZE;
1810
1811single_point_ring:
1812 trn->complete_ring();
1813 }
1814
1815 trn->complete_poly();
1816 return 0;
1817}
1818
1819
1820const Geometry::Class_info *Gis_polygon::get_class_info() const
1821{
1822 return &polygon_class;
1823}
1824
1825
1826/***************************** MultiPoint *******************************/
1827
1828uint32 Gis_multi_point::get_data_size() const
1829{
1830 uint32 n_points;
1831
1832 if (no_data(m_data, 4) ||
1833 not_enough_points(m_data+4, (n_points= uint4korr(m_data)),
1834 WKB_HEADER_SIZE))
1835 return GET_SIZE_ERROR;
1836 return 4 + n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE);
1837}
1838
1839
1840bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
1841{
1842 uint32 n_points= 0;
1843 uint32 np_pos= wkb->length();
1844 Gis_point p;
1845
1846 if (wkb->reserve(4, 512))
1847 return 1;
1848 wkb->length(wkb->length()+4); // Reserve space for points
1849
1850 for (;;)
1851 {
1852 if (wkb->reserve(1 + 4, 512))
1853 return 1;
1854 wkb->q_append((char) wkb_ndr);
1855 wkb->q_append((uint32) wkb_point);
1856 if (p.init_from_wkt(trs, wkb))
1857 return 1;
1858 n_points++;
1859 if (trs->skip_char(',')) // Didn't find ','
1860 break;
1861 }
1862 wkb->write_at_position(np_pos, n_points); // Store number of found points
1863 return 0;
1864}
1865
1866
1867uint Gis_multi_point::init_from_opresult(String *bin,
1868 const char *opres, uint res_len)
1869{
1870 uint bin_size, n_points;
1871 Gis_point p;
1872 const char *opres_end;
1873
1874 n_points= res_len/(4+8*2);
1875 bin_size= n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE) + 4;
1876
1877 if (bin->reserve(bin_size, 512))
1878 return 0;
1879
1880 bin->q_append(n_points);
1881 opres_end= opres + res_len;
1882 for (; opres < opres_end; opres+= (4 + 8*2))
1883 {
1884 bin->q_append((char)wkb_ndr);
1885 bin->q_append((uint32)wkb_point);
1886 if (!p.init_from_wkb(opres + 4, POINT_DATA_SIZE, wkb_ndr, bin))
1887 return 0;
1888 }
1889 return res_len;
1890}
1891
1892
1893uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
1894 String *res)
1895{
1896 uint32 n_points;
1897 uint proper_size;
1898 Gis_point p;
1899 const char *wkb_end;
1900
1901 if (len < 4 ||
1902 (n_points= wkb_get_uint(wkb, bo)) > max_n_points)
1903 return 0;
1904 proper_size= 4 + n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
1905
1906 if (len < proper_size || res->reserve(proper_size))
1907 return 0;
1908
1909 res->q_append(n_points);
1910 wkb_end= wkb + proper_size;
1911 for (wkb+=4; wkb < wkb_end; wkb+= (WKB_HEADER_SIZE + POINT_DATA_SIZE))
1912 {
1913 res->q_append((char)wkb_ndr);
1914 res->q_append((uint32)wkb_point);
1915 if (!p.init_from_wkb(wkb + WKB_HEADER_SIZE,
1916 POINT_DATA_SIZE, (wkbByteOrder) wkb[0], res))
1917 return 0;
1918 }
1919 return proper_size;
1920}
1921
1922
1923bool Gis_multi_point::init_from_json(json_engine_t *je, bool er_on_3D,
1924 String *wkb)
1925{
1926 uint32 n_points= 0;
1927 uint32 np_pos= wkb->length();
1928 Gis_point p;
1929
1930 if (json_read_value(je))
1931 return TRUE;
1932
1933 if (je->value_type != JSON_VALUE_ARRAY)
1934 {
1935 je->s.error= GEOJ_INCORRECT_GEOJSON;
1936 return TRUE;
1937 }
1938
1939 if (wkb->reserve(4, 512))
1940 return TRUE;
1941 wkb->length(wkb->length()+4); // Reserve space for n_points
1942
1943 while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
1944 {
1945 DBUG_ASSERT(je->state == JST_VALUE);
1946
1947 if (wkb->reserve(1 + 4, 512))
1948 return TRUE;
1949 wkb->q_append((char) wkb_ndr);
1950 wkb->q_append((uint32) wkb_point);
1951
1952 if (p.init_from_json(je, er_on_3D, wkb))
1953 return TRUE;
1954 n_points++;
1955 }
1956
1957 if (je->s.error)
1958 return TRUE;
1959
1960 if (n_points == 0)
1961 {
1962 je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
1963 return TRUE;
1964 }
1965
1966 wkb->write_at_position(np_pos, n_points);
1967 return FALSE;
1968}
1969
1970
1971bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
1972{
1973 uint32 n_points;
1974 if (no_data(m_data, 4))
1975 return 1;
1976
1977 n_points= uint4korr(m_data);
1978 if (n_points > max_n_points ||
1979 not_enough_points(m_data+4, n_points, WKB_HEADER_SIZE) ||
1980 txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
1981 return 1;
1982 *end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE);
1983 txt->length(txt->length()-1); // Remove end ','
1984 return 0;
1985}
1986
1987
1988bool Gis_multi_point::get_data_as_json(String *txt, uint max_dec_digits,
1989 const char **end) const
1990{
1991 uint32 n_points;
1992 if (no_data(m_data, 4))
1993 return 1;
1994
1995 n_points= uint4korr(m_data);
1996 if (n_points > max_n_points ||
1997 not_enough_points(m_data+4, n_points, WKB_HEADER_SIZE) ||
1998 txt->reserve((MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points + 2))
1999 return 1;
2000 *end= append_json_points(txt, max_dec_digits, n_points, m_data+4,
2001 WKB_HEADER_SIZE);
2002 return 0;
2003}
2004
2005
2006bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const
2007{
2008 return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0;
2009}
2010
2011
2012int Gis_multi_point::num_geometries(uint32 *num) const
2013{
2014 *num= uint4korr(m_data);
2015 return 0;
2016}
2017
2018
2019int Gis_multi_point::geometry_n(uint32 num, String *result) const
2020{
2021 const char *data= m_data;
2022 uint32 n_points;
2023
2024 if (no_data(data, 4))
2025 return 1;
2026 n_points= uint4korr(data);
2027 data+= 4+ (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
2028
2029 if (num > n_points || num < 1 ||
2030 no_data(data, WKB_HEADER_SIZE + POINT_DATA_SIZE) ||
2031 result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE))
2032 return 1;
2033
2034 result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE);
2035 return 0;
2036}
2037
2038
2039int Gis_multi_point::store_shapes(Gcalc_shape_transporter *trn) const
2040{
2041 uint32 n_points;
2042 Gis_point pt;
2043 const char *data= m_data;
2044
2045 if (no_data(data, 4))
2046 return 1;
2047 n_points= uint4korr(data);
2048 data+= 4;
2049
2050 if (trn->start_collection(n_points))
2051 return 1;
2052
2053 while (n_points--)
2054 {
2055 if (no_data(data, WKB_HEADER_SIZE))
2056 return 1;
2057 data+= WKB_HEADER_SIZE;
2058 pt.set_data_ptr(data, (uint32) (m_data_end - data));
2059 if (pt.store_shapes(trn))
2060 return 1;
2061 data+= pt.get_data_size();
2062 }
2063 return 0;
2064}
2065
2066
2067const Geometry::Class_info *Gis_multi_point::get_class_info() const
2068{
2069 return &multipoint_class;
2070}
2071
2072
2073/***************************** MultiLineString *******************************/
2074
2075uint32 Gis_multi_line_string::get_data_size() const
2076{
2077 uint32 n_line_strings;
2078 uint32 n_points;
2079 const char *data= m_data;
2080
2081 if (no_data(data, 4))
2082 return GET_SIZE_ERROR;
2083 n_line_strings= uint4korr(data);
2084 data+= 4;
2085
2086 while (n_line_strings--)
2087 {
2088 if (no_data(data, WKB_HEADER_SIZE + 4) ||
2089 not_enough_points(data + WKB_HEADER_SIZE+4,
2090 (n_points= uint4korr(data + WKB_HEADER_SIZE))))
2091 return GET_SIZE_ERROR;
2092 data+= (WKB_HEADER_SIZE + 4 + n_points*POINT_DATA_SIZE);
2093 }
2094 if (no_data(data, 0))
2095 return GET_SIZE_ERROR;
2096 return (uint32) (data - m_data);
2097}
2098
2099
2100bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
2101{
2102 uint32 n_line_strings= 0;
2103 uint32 ls_pos= wkb->length();
2104
2105 if (wkb->reserve(4, 512))
2106 return 1;
2107 wkb->length(wkb->length()+4); // Reserve space for points
2108
2109 for (;;)
2110 {
2111 Gis_line_string ls;
2112
2113 if (wkb->reserve(1 + 4, 512))
2114 return 1;
2115 wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_linestring);
2116
2117 if (trs->check_next_symbol('(') ||
2118 ls.init_from_wkt(trs, wkb) ||
2119 trs->check_next_symbol(')'))
2120 return 1;
2121 n_line_strings++;
2122 if (trs->skip_char(',')) // Didn't find ','
2123 break;
2124 }
2125 wkb->write_at_position(ls_pos, n_line_strings);
2126 return 0;
2127}
2128
2129
2130uint Gis_multi_line_string::init_from_opresult(String *bin,
2131 const char *opres, uint res_len)
2132{
2133 const char *opres_orig= opres;
2134 int ns_pos= bin->length();
2135 uint n_linestring= 0;
2136
2137 if (bin->reserve(4, 512))
2138 return 0;
2139 bin->q_append(n_linestring);
2140
2141 while (res_len)
2142 {
2143 Gis_line_string ls;
2144 int ls_len;
2145
2146 if (bin->reserve(WKB_HEADER_SIZE, 512))
2147 return 0;
2148
2149 bin->q_append((char) wkb_ndr);
2150 bin->q_append((uint32) wkb_linestring);
2151
2152 if (!(ls_len= ls.init_from_opresult(bin, opres, res_len)))
2153 return 0;
2154 opres+= ls_len;
2155 res_len-= ls_len;
2156 n_linestring++;
2157 }
2158 bin->write_at_position(ns_pos, n_linestring);
2159 return (uint) (opres - opres_orig);
2160}
2161
2162
2163uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
2164 wkbByteOrder bo, String *res)
2165{
2166 uint32 n_line_strings;
2167 const char *wkb_orig= wkb;
2168
2169 if (len < 4 ||
2170 (n_line_strings= wkb_get_uint(wkb, bo))< 1)
2171 return 0;
2172
2173 if (res->reserve(4, 512))
2174 return 0;
2175 res->q_append(n_line_strings);
2176
2177 wkb+= 4;
2178 while (n_line_strings--)
2179 {
2180 Gis_line_string ls;
2181 int ls_len;
2182
2183 if ((len < WKB_HEADER_SIZE) ||
2184 res->reserve(WKB_HEADER_SIZE, 512))
2185 return 0;
2186
2187 res->q_append((char) wkb_ndr);
2188 res->q_append((uint32) wkb_linestring);
2189
2190 if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
2191 (wkbByteOrder) wkb[0], res)))
2192 return 0;
2193 ls_len+= WKB_HEADER_SIZE;;
2194 wkb+= ls_len;
2195 len-= ls_len;
2196 }
2197 return (uint) (wkb - wkb_orig);
2198}
2199
2200
2201bool Gis_multi_line_string::init_from_json(json_engine_t *je, bool er_on_3D,
2202 String *wkb)
2203{
2204 uint32 n_line_strings= 0;
2205 uint32 ls_pos= wkb->length();
2206
2207 if (json_read_value(je))
2208 return TRUE;
2209
2210 if (je->value_type != JSON_VALUE_ARRAY)
2211 {
2212 je->s.error= GEOJ_INCORRECT_GEOJSON;
2213 return TRUE;
2214 }
2215
2216 if (wkb->reserve(4, 512))
2217 return TRUE;
2218 wkb->length(wkb->length()+4); // Reserve space for n_rings
2219
2220 while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
2221 {
2222 Gis_line_string ls;
2223 DBUG_ASSERT(je->state == JST_VALUE);
2224
2225 if (wkb->reserve(1 + 4, 512))
2226 return TRUE;
2227 wkb->q_append((char) wkb_ndr);
2228 wkb->q_append((uint32) wkb_linestring);
2229
2230 if (ls.init_from_json(je, er_on_3D, wkb))
2231 return TRUE;
2232
2233 n_line_strings++;
2234 }
2235
2236 if (je->s.error)
2237 return TRUE;
2238
2239 if (n_line_strings == 0)
2240 {
2241 je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
2242 return TRUE;
2243 }
2244
2245 wkb->write_at_position(ls_pos, n_line_strings);
2246 return FALSE;
2247}
2248
2249
2250bool Gis_multi_line_string::get_data_as_wkt(String *txt,
2251 const char **end) const
2252{
2253 uint32 n_line_strings;
2254 const char *data= m_data;
2255
2256 if (no_data(data, 4))
2257 return 1;
2258 n_line_strings= uint4korr(data);
2259 data+= 4;
2260
2261 while (n_line_strings--)
2262 {
2263 uint32 n_points;
2264 if (no_data(data, (WKB_HEADER_SIZE + 4)))
2265 return 1;
2266 n_points= uint4korr(data + WKB_HEADER_SIZE);
2267 data+= WKB_HEADER_SIZE + 4;
2268 if (not_enough_points(data, n_points) ||
2269 txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
2270 return 1;
2271 txt->qs_append('(');
2272 data= append_points(txt, n_points, data, 0);
2273 (*txt) [txt->length() - 1]= ')';
2274 txt->qs_append(',');
2275 }
2276 txt->length(txt->length() - 1);
2277 *end= data;
2278 return 0;
2279}
2280
2281
2282bool Gis_multi_line_string::get_data_as_json(String *txt, uint max_dec_digits,
2283 const char **end) const
2284{
2285 uint32 n_line_strings;
2286 const char *data= m_data;
2287
2288 if (no_data(data, 4) || txt->reserve(1, 512))
2289 return 1;
2290 n_line_strings= uint4korr(data);
2291 data+= 4;
2292
2293 txt->qs_append('[');
2294 while (n_line_strings--)
2295 {
2296 uint32 n_points;
2297 if (no_data(data, (WKB_HEADER_SIZE + 4)))
2298 return 1;
2299 n_points= uint4korr(data + WKB_HEADER_SIZE);
2300 data+= WKB_HEADER_SIZE + 4;
2301 if (not_enough_points(data, n_points) ||
2302 txt->reserve(2 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points))
2303 return 1;
2304 data= append_json_points(txt, max_dec_digits, n_points, data, 0);
2305 txt->qs_append(", ", 2);
2306 }
2307 txt->length(txt->length() - 2);
2308 txt->qs_append(']');
2309 *end= data;
2310 return 0;
2311}
2312
2313
2314bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const
2315{
2316 uint32 n_line_strings;
2317 const char *data= m_data;
2318
2319 if (no_data(data, 4))
2320 return 1;
2321 n_line_strings= uint4korr(data);
2322 data+= 4;
2323
2324 while (n_line_strings--)
2325 {
2326 data+= WKB_HEADER_SIZE;
2327 if (!(data= get_mbr_for_points(mbr, data, 0)))
2328 return 1;
2329 }
2330 *end= data;
2331 return 0;
2332}
2333
2334
2335int Gis_multi_line_string::num_geometries(uint32 *num) const
2336{
2337 *num= uint4korr(m_data);
2338 return 0;
2339}
2340
2341
2342int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
2343{
2344 uint32 n_line_strings, n_points, length;
2345 const char *data= m_data;
2346
2347 if (no_data(data, 4))
2348 return 1;
2349 n_line_strings= uint4korr(data);
2350 data+= 4;
2351
2352 if ((num > n_line_strings) || (num < 1))
2353 return 1;
2354
2355 for (;;)
2356 {
2357 if (no_data(data, WKB_HEADER_SIZE + 4))
2358 return 1;
2359 n_points= uint4korr(data + WKB_HEADER_SIZE);
2360 length= WKB_HEADER_SIZE + 4+ POINT_DATA_SIZE * n_points;
2361 if (not_enough_points(data+WKB_HEADER_SIZE+4, n_points))
2362 return 1;
2363 if (!--num)
2364 break;
2365 data+= length;
2366 }
2367 return result->append(data, length, (uint32) 0);
2368}
2369
2370
2371int Gis_multi_line_string::geom_length(double *len, const char **end) const
2372{
2373 uint32 n_line_strings;
2374 const char *data= m_data;
2375 const char *line_end;
2376
2377 if (no_data(data, 4))
2378 return 1;
2379 n_line_strings= uint4korr(data);
2380 data+= 4;
2381
2382 *len=0;
2383 while (n_line_strings--)
2384 {
2385 double ls_len;
2386 Gis_line_string ls;
2387 data+= WKB_HEADER_SIZE;
2388 ls.set_data_ptr(data, (uint32) (m_data_end - data));
2389 if (ls.geom_length(&ls_len, &line_end))
2390 return 1;
2391 *len+= ls_len;
2392 /*
2393 We know here that ls was ok, so we can call the trivial function
2394 Gis_line_string::get_data_size without error checking
2395 */
2396 data+= ls.get_data_size();
2397 }
2398 *end= data;
2399 return 0;
2400}
2401
2402
2403int Gis_multi_line_string::is_closed(int *closed) const
2404{
2405 uint32 n_line_strings;
2406 const char *data= m_data;
2407
2408 if (no_data(data, 4 + WKB_HEADER_SIZE))
2409 return 1;
2410 n_line_strings= uint4korr(data);
2411 data+= 4 + WKB_HEADER_SIZE;
2412
2413 while (n_line_strings--)
2414 {
2415 Gis_line_string ls;
2416 if (no_data(data, 0))
2417 return 1;
2418 ls.set_data_ptr(data, (uint32) (m_data_end - data));
2419 if (ls.is_closed(closed))
2420 return 1;
2421 if (!*closed)
2422 return 0;
2423 /*
2424 We know here that ls was ok, so we can call the trivial function
2425 Gis_line_string::get_data_size without error checking
2426 */
2427 data+= ls.get_data_size() + WKB_HEADER_SIZE;
2428 }
2429 return 0;
2430}
2431
2432
2433int Gis_multi_line_string::store_shapes(Gcalc_shape_transporter *trn) const
2434{
2435 uint32 n_lines;
2436 Gis_line_string ls;
2437 const char *data= m_data;
2438
2439 if (no_data(data, 4))
2440 return 1;
2441 n_lines= uint4korr(data);
2442 data+= 4;
2443
2444 if (trn->start_collection(n_lines))
2445 return 1;
2446
2447 while (n_lines--)
2448 {
2449 if (no_data(data, WKB_HEADER_SIZE))
2450 return 1;
2451 data+= WKB_HEADER_SIZE;
2452 ls.set_data_ptr(data, (uint32) (m_data_end - data));
2453 if (ls.store_shapes(trn))
2454 return 1;
2455 data+= ls.get_data_size();
2456 }
2457 return 0;
2458}
2459
2460
2461const Geometry::Class_info *Gis_multi_line_string::get_class_info() const
2462{
2463 return &multilinestring_class;
2464}
2465
2466
2467/***************************** MultiPolygon *******************************/
2468
2469uint32 Gis_multi_polygon::get_data_size() const
2470{
2471 uint32 n_polygons;
2472 uint32 n_points;
2473 const char *data= m_data;
2474
2475 if (no_data(data, 4))
2476 return GET_SIZE_ERROR;
2477 n_polygons= uint4korr(data);
2478 data+= 4;
2479
2480 while (n_polygons--)
2481 {
2482 uint32 n_linear_rings;
2483 if (no_data(data, 4 + WKB_HEADER_SIZE))
2484 return GET_SIZE_ERROR;
2485
2486 n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
2487 data+= 4 + WKB_HEADER_SIZE;
2488
2489 while (n_linear_rings--)
2490 {
2491 if (no_data(data, 4) ||
2492 not_enough_points(data+4, (n_points= uint4korr(data))))
2493 return GET_SIZE_ERROR;
2494 data+= 4 + n_points * POINT_DATA_SIZE;
2495 }
2496 }
2497 if (no_data(data, 0))
2498 return GET_SIZE_ERROR;
2499 return (uint32) (data - m_data);
2500}
2501
2502
2503bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
2504{
2505 uint32 n_polygons= 0;
2506 int np_pos= wkb->length();
2507 Gis_polygon p;
2508
2509 if (wkb->reserve(4, 512))
2510 return 1;
2511 wkb->length(wkb->length()+4); // Reserve space for points
2512
2513 for (;;)
2514 {
2515 if (wkb->reserve(1 + 4, 512))
2516 return 1;
2517 wkb->q_append((char) wkb_ndr);
2518 wkb->q_append((uint32) wkb_polygon);
2519
2520 if (trs->check_next_symbol('(') ||
2521 p.init_from_wkt(trs, wkb) ||
2522 trs->check_next_symbol(')'))
2523 return 1;
2524 n_polygons++;
2525 if (trs->skip_char(',')) // Didn't find ','
2526 break;
2527 }
2528 wkb->write_at_position(np_pos, n_polygons);
2529 return 0;
2530}
2531
2532
2533uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
2534 wkbByteOrder bo, String *res)
2535{
2536 uint32 n_poly;
2537 const char *wkb_orig= wkb;
2538
2539 if (len < 4)
2540 return 0;
2541 n_poly= wkb_get_uint(wkb, bo);
2542
2543 if (res->reserve(4, 512))
2544 return 0;
2545 res->q_append(n_poly);
2546
2547 wkb+=4;
2548 while (n_poly--)
2549 {
2550 Gis_polygon p;
2551 int p_len;
2552
2553 if (len < WKB_HEADER_SIZE ||
2554 res->reserve(WKB_HEADER_SIZE, 512))
2555 return 0;
2556 res->q_append((char) wkb_ndr);
2557 res->q_append((uint32) wkb_polygon);
2558
2559 if (!(p_len= p.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
2560 (wkbByteOrder) wkb[0], res)))
2561 return 0;
2562 p_len+= WKB_HEADER_SIZE;
2563 wkb+= p_len;
2564 len-= p_len;
2565 }
2566 return (uint) (wkb - wkb_orig);
2567}
2568
2569
2570uint Gis_multi_polygon::init_from_opresult(String *bin,
2571 const char *opres, uint res_len)
2572{
2573 Gis_polygon p;
2574 const char *opres_orig= opres;
2575 uint p_len;
2576 uint32 n_poly= 0;
2577 uint32 np_pos= bin->length();
2578
2579 if (bin->reserve(4, 512))
2580 return 0;
2581
2582 bin->q_append(n_poly);
2583 while (res_len)
2584 {
2585 if (bin->reserve(1 + 4, 512))
2586 return 0;
2587 bin->q_append((char)wkb_ndr);
2588 bin->q_append((uint32)wkb_polygon);
2589 if (!(p_len= p.init_from_opresult(bin, opres, res_len)))
2590 return 0;
2591 opres+= p_len;
2592 res_len-= p_len;
2593 n_poly++;
2594 }
2595 bin->write_at_position(np_pos, n_poly);
2596 return (uint)(opres - opres_orig);
2597}
2598
2599
2600bool Gis_multi_polygon::init_from_json(json_engine_t *je, bool er_on_3D,
2601 String *wkb)
2602{
2603 uint32 n_polygons= 0;
2604 int np_pos= wkb->length();
2605 Gis_polygon p;
2606
2607 if (json_read_value(je))
2608 return TRUE;
2609
2610 if (je->value_type != JSON_VALUE_ARRAY)
2611 {
2612 je->s.error= GEOJ_INCORRECT_GEOJSON;
2613 return TRUE;
2614 }
2615
2616 if (wkb->reserve(4, 512))
2617 return TRUE;
2618 wkb->length(wkb->length()+4); // Reserve space for n_rings
2619
2620 while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
2621 {
2622 DBUG_ASSERT(je->state == JST_VALUE);
2623
2624 if (wkb->reserve(1 + 4, 512))
2625 return TRUE;
2626 wkb->q_append((char) wkb_ndr);
2627 wkb->q_append((uint32) wkb_polygon);
2628
2629 if (p.init_from_json(je, er_on_3D, wkb))
2630 return TRUE;
2631
2632 n_polygons++;
2633 }
2634
2635 if (je->s.error)
2636 return TRUE;
2637
2638 if (n_polygons == 0)
2639 {
2640 je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
2641 return TRUE;
2642 }
2643 wkb->write_at_position(np_pos, n_polygons);
2644 return FALSE;
2645}
2646
2647
2648bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
2649{
2650 uint32 n_polygons;
2651 const char *data= m_data;
2652
2653 if (no_data(data, 4))
2654 return 1;
2655 n_polygons= uint4korr(data);
2656 data+= 4;
2657
2658 while (n_polygons--)
2659 {
2660 uint32 n_linear_rings;
2661 if (no_data(data, 4 + WKB_HEADER_SIZE) ||
2662 txt->reserve(1, 512))
2663 return 1;
2664 n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
2665 data+= 4 + WKB_HEADER_SIZE;
2666 txt->q_append('(');
2667
2668 while (n_linear_rings--)
2669 {
2670 if (no_data(data, 4))
2671 return 1;
2672 uint32 n_points= uint4korr(data);
2673 data+= 4;
2674 if (not_enough_points(data, n_points) ||
2675 txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
2676 512))
2677 return 1;
2678 txt->qs_append('(');
2679 data= append_points(txt, n_points, data, 0);
2680 (*txt) [txt->length() - 1]= ')';
2681 txt->qs_append(',');
2682 }
2683 (*txt) [txt->length() - 1]= ')';
2684 txt->qs_append(',');
2685 }
2686 txt->length(txt->length() - 1);
2687 *end= data;
2688 return 0;
2689}
2690
2691
2692bool Gis_multi_polygon::get_data_as_json(String *txt, uint max_dec_digits,
2693 const char **end) const
2694{
2695 uint32 n_polygons;
2696 const char *data= m_data;
2697
2698 if (no_data(data, 4) || txt->reserve(1, 512))
2699 return 1;
2700 n_polygons= uint4korr(data);
2701 data+= 4;
2702
2703 txt->q_append('[');
2704 while (n_polygons--)
2705 {
2706 uint32 n_linear_rings;
2707 if (no_data(data, 4 + WKB_HEADER_SIZE) ||
2708 txt->reserve(1, 512))
2709 return 1;
2710 n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
2711 data+= 4 + WKB_HEADER_SIZE;
2712 txt->q_append('[');
2713
2714 while (n_linear_rings--)
2715 {
2716 if (no_data(data, 4))
2717 return 1;
2718 uint32 n_points= uint4korr(data);
2719 data+= 4;
2720 if (not_enough_points(data, n_points) ||
2721 txt->reserve(2 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points,
2722 512))
2723 return 1;
2724 data= append_json_points(txt, max_dec_digits, n_points, data, 0);
2725 txt->qs_append(", ", 2);
2726 }
2727 txt->length(txt->length() - 2);
2728 txt->qs_append("], ", 3);
2729 }
2730 txt->length(txt->length() - 2);
2731 txt->q_append(']');
2732 *end= data;
2733 return 0;
2734}
2735
2736
2737bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const
2738{
2739 uint32 n_polygons;
2740 const char *data= m_data;
2741
2742 if (no_data(data, 4))
2743 return 1;
2744 n_polygons= uint4korr(data);
2745 data+= 4;
2746
2747 while (n_polygons--)
2748 {
2749 uint32 n_linear_rings;
2750 if (no_data(data, 4+WKB_HEADER_SIZE))
2751 return 1;
2752 n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
2753 data+= WKB_HEADER_SIZE + 4;
2754
2755 while (n_linear_rings--)
2756 {
2757 if (!(data= get_mbr_for_points(mbr, data, 0)))
2758 return 1;
2759 }
2760 }
2761 *end= data;
2762 return 0;
2763}
2764
2765
2766int Gis_multi_polygon::num_geometries(uint32 *num) const
2767{
2768 *num= uint4korr(m_data);
2769 return 0;
2770}
2771
2772
2773int Gis_multi_polygon::geometry_n(uint32 num, String *result) const
2774{
2775 uint32 n_polygons;
2776 const char *data= m_data, *start_of_polygon;
2777
2778 if (no_data(data, 4))
2779 return 1;
2780 n_polygons= uint4korr(data);
2781 data+= 4;
2782
2783 if (num > n_polygons || num < 1)
2784 return -1;
2785
2786 do
2787 {
2788 uint32 n_linear_rings;
2789 start_of_polygon= data;
2790
2791 if (no_data(data, WKB_HEADER_SIZE + 4))
2792 return 1;
2793 n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
2794 data+= WKB_HEADER_SIZE + 4;
2795
2796 while (n_linear_rings--)
2797 {
2798 uint32 n_points;
2799 if (no_data(data, 4))
2800 return 1;
2801 n_points= uint4korr(data);
2802 if (not_enough_points(data + 4, n_points))
2803 return 1;
2804 data+= 4 + POINT_DATA_SIZE * n_points;
2805 }
2806 } while (--num);
2807 if (no_data(data, 0)) // We must check last segment
2808 return 1;
2809 return result->append(start_of_polygon, (uint32) (data - start_of_polygon),
2810 (uint32) 0);
2811}
2812
2813
2814int Gis_multi_polygon::area(double *ar, const char **end_of_data) const
2815{
2816 uint32 n_polygons;
2817 const char *data= m_data;
2818 double result= 0;
2819
2820 if (no_data(data, 4))
2821 return 1;
2822 n_polygons= uint4korr(data);
2823 data+= 4;
2824
2825 while (n_polygons--)
2826 {
2827 double p_area;
2828 Gis_polygon p;
2829
2830 data+= WKB_HEADER_SIZE;
2831 p.set_data_ptr(data, (uint32) (m_data_end - data));
2832 if (p.area(&p_area, &data))
2833 return 1;
2834 result+= p_area;
2835 }
2836 *ar= result;
2837 *end_of_data= data;
2838 return 0;
2839}
2840
2841
2842int Gis_multi_polygon::centroid(String *result) const
2843{
2844 uint32 n_polygons;
2845 Gis_polygon p;
2846 double res_area= 0.0, res_cx= 0.0, res_cy= 0.0;
2847 double cur_area, cur_cx, cur_cy;
2848 const char *data= m_data;
2849
2850 if (no_data(data, 4))
2851 return 1;
2852 n_polygons= uint4korr(data);
2853 data+= 4;
2854
2855 while (n_polygons--)
2856 {
2857 data+= WKB_HEADER_SIZE;
2858 p.set_data_ptr(data, (uint32) (m_data_end - data));
2859 if (p.area(&cur_area, &data) ||
2860 p.centroid_xy(&cur_cx, &cur_cy))
2861 return 1;
2862
2863 res_area+= cur_area;
2864 res_cx+= cur_area * cur_cx;
2865 res_cy+= cur_area * cur_cy;
2866 }
2867
2868 res_cx/= res_area;
2869 res_cy/= res_area;
2870
2871 return create_point(result, res_cx, res_cy);
2872}
2873
2874
2875int Gis_multi_polygon::store_shapes(Gcalc_shape_transporter *trn) const
2876{
2877 uint32 n_polygons;
2878 Gis_polygon p;
2879 const char *data= m_data;
2880
2881 if (no_data(data, 4))
2882 return 1;
2883 n_polygons= uint4korr(data);
2884 data+= 4;
2885
2886 if (trn->start_collection(n_polygons))
2887 return 1;
2888
2889 while (n_polygons--)
2890 {
2891 if (no_data(data, WKB_HEADER_SIZE))
2892 return 1;
2893 data+= WKB_HEADER_SIZE;
2894 p.set_data_ptr(data, (uint32) (m_data_end - data));
2895 if (p.store_shapes(trn))
2896 return 1;
2897 data+= p.get_data_size();
2898 }
2899 return 0;
2900}
2901
2902
2903const Geometry::Class_info *Gis_multi_polygon::get_class_info() const
2904{
2905 return &multipolygon_class;
2906}
2907
2908
2909/************************* GeometryCollection ****************************/
2910
2911uint32 Gis_geometry_collection::get_data_size() const
2912{
2913 uint32 n_objects;
2914 const char *data= m_data;
2915 Geometry_buffer buffer;
2916 Geometry *geom;
2917
2918 if (no_data(data, 4))
2919 return GET_SIZE_ERROR;
2920 n_objects= uint4korr(data);
2921 data+= 4;
2922
2923 while (n_objects--)
2924 {
2925 uint32 wkb_type,object_size;
2926
2927 if (no_data(data, WKB_HEADER_SIZE))
2928 return GET_SIZE_ERROR;
2929 wkb_type= uint4korr(data + 1);
2930 data+= WKB_HEADER_SIZE;
2931
2932 if (!(geom= create_by_typeid(&buffer, wkb_type)))
2933 return GET_SIZE_ERROR;
2934 geom->set_data_ptr(data, (uint) (m_data_end - data));
2935 if ((object_size= geom->get_data_size()) == GET_SIZE_ERROR)
2936 return GET_SIZE_ERROR;
2937 data+= object_size;
2938 }
2939 return (uint32) (data - m_data);
2940}
2941
2942
2943bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
2944{
2945 uint32 n_objects= 0;
2946 uint32 no_pos= wkb->length();
2947 Geometry_buffer buffer;
2948 Geometry *g;
2949 char next_sym;
2950
2951 if (wkb->reserve(4, 512))
2952 return 1;
2953 wkb->length(wkb->length()+4); // Reserve space for points
2954
2955 if (!(next_sym= trs->next_symbol()))
2956 return 1;
2957
2958 if (next_sym != ')')
2959 {
2960 LEX_STRING next_word;
2961 if (trs->lookup_next_word(&next_word))
2962 return 1;
2963
2964 if (next_word.length != 5 ||
2965 (my_strnncoll(&my_charset_latin1,
2966 (const uchar*) "empty", 5,
2967 (const uchar*) next_word.str, 5) != 0))
2968 {
2969 for (;;)
2970 {
2971 if (!(g= create_from_wkt(&buffer, trs, wkb)))
2972 return 1;
2973
2974 if (g->get_class_info()->m_type_id == wkb_geometrycollection)
2975 {
2976 trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
2977 return 1;
2978 }
2979 n_objects++;
2980 if (trs->skip_char(',')) // Didn't find ','
2981 break;
2982 }
2983 }
2984 }
2985
2986 wkb->write_at_position(no_pos, n_objects);
2987 return 0;
2988}
2989
2990
2991uint Gis_geometry_collection::init_from_opresult(String *bin,
2992 const char *opres,
2993 uint res_len)
2994{
2995 const char *opres_orig= opres;
2996 Geometry_buffer buffer;
2997 Geometry *geom;
2998 int g_len;
2999 uint32 wkb_type;
3000 int no_pos= bin->length();
3001 uint32 n_objects= 0;
3002
3003 if (bin->reserve(4, 512))
3004 return 0;
3005 bin->q_append(n_objects);
3006
3007 if (res_len == 0)
3008 {
3009 /* Special case of GEOMETRYCOLLECTION EMPTY. */
3010 opres+= 1;
3011 goto empty_geom;
3012 }
3013
3014 while (res_len)
3015 {
3016 switch ((Gcalc_function::shape_type) uint4korr(opres))
3017 {
3018 case Gcalc_function::shape_point: wkb_type= wkb_point; break;
3019 case Gcalc_function::shape_line: wkb_type= wkb_linestring; break;
3020 case Gcalc_function::shape_polygon: wkb_type= wkb_polygon; break;
3021 default: wkb_type= 0; DBUG_ASSERT(FALSE);
3022 };
3023
3024 if (bin->reserve(WKB_HEADER_SIZE, 512))
3025 return 0;
3026
3027 bin->q_append((char) wkb_ndr);
3028 bin->q_append(wkb_type);
3029
3030 if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
3031 !(g_len= geom->init_from_opresult(bin, opres, res_len)))
3032 return 0;
3033 opres+= g_len;
3034 res_len-= g_len;
3035 n_objects++;
3036 }
3037empty_geom:
3038 bin->write_at_position(no_pos, n_objects);
3039 return (uint) (opres - opres_orig);
3040}
3041
3042
3043uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
3044 wkbByteOrder bo, String *res)
3045{
3046 uint32 n_geom;
3047 const char *wkb_orig= wkb;
3048
3049 if (len < 4)
3050 return 0;
3051 n_geom= wkb_get_uint(wkb, bo);
3052
3053 if (res->reserve(4, 512))
3054 return 0;
3055 res->q_append(n_geom);
3056
3057 wkb+= 4;
3058 while (n_geom--)
3059 {
3060 Geometry_buffer buffer;
3061 Geometry *geom;
3062 int g_len;
3063 uint32 wkb_type;
3064
3065 if (len < WKB_HEADER_SIZE ||
3066 res->reserve(WKB_HEADER_SIZE, 512))
3067 return 0;
3068
3069 res->q_append((char) wkb_ndr);
3070 wkb_type= wkb_get_uint(wkb+1, (wkbByteOrder) wkb[0]);
3071 res->q_append(wkb_type);
3072
3073 if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
3074 !(g_len= geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len,
3075 (wkbByteOrder) wkb[0], res)))
3076 return 0;
3077 g_len+= WKB_HEADER_SIZE;
3078 wkb+= g_len;
3079 len-= g_len;
3080 }
3081 return (uint) (wkb - wkb_orig);
3082}
3083
3084
3085bool Gis_geometry_collection::init_from_json(json_engine_t *je, bool er_on_3D,
3086 String *wkb)
3087{
3088 uint32 n_objects= 0;
3089 uint32 no_pos= wkb->length();
3090 Geometry_buffer buffer;
3091 Geometry *g;
3092
3093 if (json_read_value(je))
3094 return TRUE;
3095
3096 if (je->value_type != JSON_VALUE_ARRAY)
3097 {
3098 je->s.error= GEOJ_INCORRECT_GEOJSON;
3099 return TRUE;
3100 }
3101
3102 if (wkb->reserve(4, 512))
3103 return TRUE;
3104 wkb->length(wkb->length()+4); // Reserve space for n_objects
3105
3106 while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
3107 {
3108 json_engine_t sav_je= *je;
3109
3110 DBUG_ASSERT(je->state == JST_VALUE);
3111
3112 if (!(g= create_from_json(&buffer, je, er_on_3D, wkb)))
3113 return TRUE;
3114
3115 *je= sav_je;
3116 if (json_skip_array_item(je))
3117 return TRUE;
3118
3119 n_objects++;
3120 }
3121
3122 wkb->write_at_position(no_pos, n_objects);
3123 return FALSE;
3124}
3125
3126
3127bool Gis_geometry_collection::get_data_as_wkt(String *txt,
3128 const char **end) const
3129{
3130 uint32 n_objects;
3131 Geometry_buffer buffer;
3132 Geometry *geom;
3133 const char *data= m_data;
3134
3135 if (no_data(data, 4))
3136 return 1;
3137 n_objects= uint4korr(data);
3138 data+= 4;
3139
3140 if (n_objects == 0)
3141 {
3142 txt->append(STRING_WITH_LEN(" EMPTY"), 512);
3143 goto exit;
3144 }
3145
3146 txt->qs_append('(');
3147 while (n_objects--)
3148 {
3149 uint32 wkb_type;
3150
3151 if (no_data(data, WKB_HEADER_SIZE))
3152 return 1;
3153 wkb_type= uint4korr(data + 1);
3154 data+= WKB_HEADER_SIZE;
3155
3156 if (!(geom= create_by_typeid(&buffer, wkb_type)))
3157 return 1;
3158 geom->set_data_ptr(data, (uint) (m_data_end - data));
3159 if (geom->as_wkt(txt, &data))
3160 return 1;
3161 if (n_objects && txt->append(STRING_WITH_LEN(","), 512))
3162 return 1;
3163 }
3164 txt->qs_append(')');
3165exit:
3166 *end= data;
3167 return 0;
3168}
3169
3170
3171bool Gis_geometry_collection::get_data_as_json(String *txt, uint max_dec_digits,
3172 const char **end) const
3173{
3174 uint32 n_objects;
3175 Geometry_buffer buffer;
3176 Geometry *geom;
3177 const char *data= m_data;
3178
3179 if (no_data(data, 4) || txt->reserve(1, 512))
3180 return 1;
3181 n_objects= uint4korr(data);
3182 data+= 4;
3183
3184 txt->qs_append('[');
3185 while (n_objects--)
3186 {
3187 uint32 wkb_type;
3188
3189 if (no_data(data, WKB_HEADER_SIZE))
3190 return 1;
3191 wkb_type= uint4korr(data + 1);
3192 data+= WKB_HEADER_SIZE;
3193
3194 if (!(geom= create_by_typeid(&buffer, wkb_type)))
3195 return 1;
3196 geom->set_data_ptr(data, (uint) (m_data_end - data));
3197 if (txt->append("{", 1) ||
3198 geom->as_json(txt, max_dec_digits, &data) ||
3199 txt->append(STRING_WITH_LEN("}, "), 512))
3200 return 1;
3201 }
3202 txt->length(txt->length() - 2);
3203 if (txt->append("]", 1))
3204 return 1;
3205
3206 *end= data;
3207 return 0;
3208}
3209
3210
3211bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
3212{
3213 uint32 n_objects;
3214 const char *data= m_data;
3215 Geometry_buffer buffer;
3216 Geometry *geom;
3217
3218 if (no_data(data, 4))
3219 return 1;
3220 n_objects= uint4korr(data);
3221 data+= 4;
3222 if (n_objects == 0)
3223 goto exit;
3224
3225 while (n_objects--)
3226 {
3227 uint32 wkb_type;
3228
3229 if (no_data(data, WKB_HEADER_SIZE))
3230 return 1;
3231 wkb_type= uint4korr(data + 1);
3232 data+= WKB_HEADER_SIZE;
3233
3234 if (!(geom= create_by_typeid(&buffer, wkb_type)))
3235 return 1;
3236 geom->set_data_ptr(data, (uint32) (m_data_end - data));
3237 if (geom->get_mbr(mbr, &data))
3238 return 1;
3239 }
3240exit:
3241 *end= data;
3242 return 0;
3243}
3244
3245
3246int Gis_geometry_collection::area(double *ar, const char **end) const
3247{
3248 uint32 n_objects;
3249 const char *data= m_data;
3250 Geometry_buffer buffer;
3251 Geometry *geom;
3252 double result;
3253
3254 if (no_data(data, 4))
3255 return 1;
3256 n_objects= uint4korr(data);
3257 data+= 4;
3258
3259 result= 0.0;
3260 if (n_objects == 0)
3261 goto exit;
3262
3263 while (n_objects--)
3264 {
3265 uint32 wkb_type;
3266
3267 if (no_data(data, WKB_HEADER_SIZE))
3268 return 1;
3269 wkb_type= uint4korr(data + 1);
3270 data+= WKB_HEADER_SIZE;
3271
3272 if (!(geom= create_by_typeid(&buffer, wkb_type)))
3273 return 1;
3274 geom->set_data_ptr(data, (uint32) (m_data_end - data));
3275 if (geom->area(ar, &data))
3276 return 1;
3277 result+= *ar;
3278 }
3279exit:
3280 *end= data;
3281 *ar= result;
3282 return 0;
3283}
3284
3285
3286int Gis_geometry_collection::geom_length(double *len, const char **end) const
3287{
3288 uint32 n_objects;
3289 const char *data= m_data;
3290 Geometry_buffer buffer;
3291 Geometry *geom;
3292 double result;
3293
3294 if (no_data(data, 4))
3295 return 1;
3296 n_objects= uint4korr(data);
3297 data+= 4;
3298 result= 0.0;
3299
3300 if (n_objects == 0)
3301 goto exit;
3302
3303 while (n_objects--)
3304 {
3305 uint32 wkb_type;
3306
3307 if (no_data(data, WKB_HEADER_SIZE))
3308 return 1;
3309 wkb_type= uint4korr(data + 1);
3310 data+= WKB_HEADER_SIZE;
3311
3312 if (!(geom= create_by_typeid(&buffer, wkb_type)))
3313 return 1;
3314 geom->set_data_ptr(data, (uint32) (m_data_end - data));
3315 if (geom->geom_length(len, &data))
3316 return 1;
3317 result+= *len;
3318 }
3319
3320exit:
3321 *end= data;
3322 *len= result;
3323 return 0;
3324}
3325
3326
3327int Gis_geometry_collection::num_geometries(uint32 *num) const
3328{
3329 if (no_data(m_data, 4))
3330 return 1;
3331 *num= uint4korr(m_data);
3332 return 0;
3333}
3334
3335
3336int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
3337{
3338 uint32 n_objects, wkb_type, length;
3339 const char *data= m_data;
3340 Geometry_buffer buffer;
3341 Geometry *geom;
3342
3343 if (no_data(data, 4))
3344 return 1;
3345 n_objects= uint4korr(data);
3346 data+= 4;
3347 if (num > n_objects || num < 1)
3348 return 1;
3349
3350 do
3351 {
3352 if (no_data(data, WKB_HEADER_SIZE))
3353 return 1;
3354 wkb_type= uint4korr(data + 1);
3355 data+= WKB_HEADER_SIZE;
3356
3357 if (!(geom= create_by_typeid(&buffer, wkb_type)))
3358 return 1;
3359 geom->set_data_ptr(data, (uint) (m_data_end - data));
3360 if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
3361 return 1;
3362 data+= length;
3363 } while (--num);
3364
3365 /* Copy found object to result */
3366 if (result->reserve(1 + 4 + length))
3367 return 1;
3368 result->q_append((char) wkb_ndr);
3369 result->q_append((uint32) wkb_type);
3370 result->q_append(data-length, length); // data-length = start_of_data
3371 return 0;
3372}
3373
3374
3375/*
3376 Return dimension for object
3377
3378 SYNOPSIS
3379 dimension()
3380 res_dim Result dimension
3381 end End of object will be stored here. May be 0 for
3382 simple objects!
3383 RETURN
3384 0 ok
3385 1 error
3386*/
3387
3388bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
3389{
3390 uint32 n_objects;
3391 const char *data= m_data;
3392 Geometry_buffer buffer;
3393 Geometry *geom;
3394
3395 if (no_data(data, 4))
3396 return 1;
3397 n_objects= uint4korr(data);
3398 data+= 4;
3399
3400 *res_dim= 0;
3401 while (n_objects--)
3402 {
3403 uint32 wkb_type, length, dim;
3404 const char *end_data;
3405
3406 if (no_data(data, WKB_HEADER_SIZE))
3407 return 1;
3408 wkb_type= uint4korr(data + 1);
3409 data+= WKB_HEADER_SIZE;
3410 if (!(geom= create_by_typeid(&buffer, wkb_type)))
3411 return 1;
3412 geom->set_data_ptr(data, (uint32) (m_data_end - data));
3413 if (geom->dimension(&dim, &end_data))
3414 return 1;
3415 set_if_bigger(*res_dim, dim);
3416 if (end_data) // Complex object
3417 data= end_data;
3418 else if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
3419 return 1;
3420 else
3421 data+= length;
3422 }
3423 *end= data;
3424 return 0;
3425}
3426
3427
3428int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn) const
3429{
3430 uint32 n_objects;
3431 const char *data= m_data;
3432 Geometry_buffer buffer;
3433 Geometry *geom;
3434
3435 if (no_data(data, 4))
3436 return 1;
3437 n_objects= uint4korr(data);
3438 data+= 4;
3439
3440 if (!n_objects)
3441 {
3442 trn->empty_shape();
3443 return 0;
3444 }
3445
3446 if (trn->start_collection(n_objects))
3447 return 1;
3448
3449 while (n_objects--)
3450 {
3451 uint32 wkb_type;
3452
3453 if (no_data(data, WKB_HEADER_SIZE))
3454 return 1;
3455 wkb_type= uint4korr(data + 1);
3456 data+= WKB_HEADER_SIZE;
3457 if (!(geom= create_by_typeid(&buffer, wkb_type)))
3458 return 1;
3459 geom->set_data_ptr(data, (uint32) (m_data_end - data));
3460 if (geom->store_shapes(trn))
3461 return 1;
3462
3463 data+= geom->get_data_size();
3464 }
3465 return 0;
3466}
3467
3468
3469const Geometry::Class_info *Gis_geometry_collection::get_class_info() const
3470{
3471 return &geometrycollection_class;
3472}
3473
3474#endif /*HAVE_SPATIAL*/
3475