1
/* Copyright (C) 2004 MySQL AB
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include "mysql_priv.h"
21
exponential notation :
23
1 number before the decimal point
25
14 number of significant digits (see String::qs_append(double))
35
14 number significant digits (see String::qs_append(double) )
41
#define MAX_DIGITS_IN_DOUBLE 22
43
/***************************** Gis_class_info *******************************/
45
String Geometry::bad_geometry_data("Bad object", &my_charset_bin);
47
Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_last+1]=
49
NULL, NULL, NULL, NULL, NULL, NULL, NULL
52
static Geometry::Class_info **ci_collection_end=
53
Geometry::ci_collection+Geometry::wkb_last + 1;
55
Geometry::Class_info::Class_info(const char *name, int type_id,
56
void(*create_func)(void *)):
57
m_type_id(type_id), m_create_func(create_func)
59
m_name.str= (char *) name;
60
m_name.length= strlen(name);
62
ci_collection[type_id]= this;
65
static void create_point(void *buffer)
67
new(buffer) Gis_point;
70
static void create_linestring(void *buffer)
72
new(buffer) Gis_line_string;
75
static void create_polygon(void *buffer)
77
new(buffer) Gis_polygon;
80
static void create_multipoint(void *buffer)
82
new(buffer) Gis_multi_point;
85
static void create_multipolygon(void *buffer)
87
new(buffer) Gis_multi_polygon;
90
static void create_multilinestring(void *buffer)
92
new(buffer) Gis_multi_line_string;
95
static void create_geometrycollection(void *buffer)
97
new(buffer) Gis_geometry_collection;
102
static Geometry::Class_info point_class("POINT",
103
Geometry::wkb_point, create_point);
105
static Geometry::Class_info linestring_class("LINESTRING",
106
Geometry::wkb_linestring,
108
static Geometry::Class_info polygon_class("POLYGON",
109
Geometry::wkb_polygon,
111
static Geometry::Class_info multipoint_class("MULTIPOINT",
112
Geometry::wkb_multipoint,
114
static Geometry::Class_info
115
multilinestring_class("MULTILINESTRING",
116
Geometry::wkb_multilinestring, create_multilinestring);
117
static Geometry::Class_info multipolygon_class("MULTIPOLYGON",
118
Geometry::wkb_multipolygon,
119
create_multipolygon);
120
static Geometry::Class_info
121
geometrycollection_class("GEOMETRYCOLLECTION",Geometry::wkb_geometrycollection,
122
create_geometrycollection);
124
static void get_point(double *x, double *y, const char *data)
127
float8get(*y, data + SIZEOF_STORED_DOUBLE);
130
/***************************** Geometry *******************************/
132
Geometry::Class_info *Geometry::find_class(const char *name, uint32 len)
134
for (Class_info **cur_rt= ci_collection;
135
cur_rt < ci_collection_end; cur_rt++)
138
((*cur_rt)->m_name.length == len) &&
139
(my_strnncoll(&my_charset_latin1,
140
(const uchar*) (*cur_rt)->m_name.str, len,
141
(const uchar*) name, len) == 0))
148
Geometry *Geometry::construct(Geometry_buffer *buffer,
149
const char *data, uint32 data_len)
155
if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4)
157
byte_order= data[SRID_SIZE];
158
geom_type= uint4korr(data + SRID_SIZE + 1);
159
if (!(result= create_by_typeid(buffer, (int) geom_type)))
161
result->m_data= data+ SRID_SIZE + WKB_HEADER_SIZE;
162
result->m_data_end= data + data_len;
167
Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
168
Gis_read_stream *trs, String *wkt,
174
if (trs->get_next_word(&name))
176
trs->set_error_msg("Geometry name expected");
179
if (!(ci= find_class(name.str, name.length)) ||
180
wkt->reserve(1 + 4, 512))
182
(*ci->m_create_func)((void *)buffer);
183
Geometry *result= (Geometry *)buffer;
185
wkt->q_append((char) wkb_ndr);
186
wkt->q_append((uint32) result->get_class_info()->m_type_id);
187
if (trs->check_next_symbol('(') ||
188
result->init_from_wkt(trs, wkt) ||
189
trs->check_next_symbol(')'))
193
result->set_data_ptr(wkt->ptr(), wkt->length());
194
result->shift_wkb_header();
200
static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
203
if (bo != Geometry::wkb_xdr)
210
inv_array[0]= ptr[7];
211
inv_array[1]= ptr[6];
212
inv_array[2]= ptr[5];
213
inv_array[3]= ptr[4];
214
inv_array[4]= ptr[3];
215
inv_array[5]= ptr[2];
216
inv_array[6]= ptr[1];
217
inv_array[7]= ptr[0];
218
float8get(res, inv_array);
224
static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
226
if (bo != Geometry::wkb_xdr)
227
return uint4korr(ptr);
231
inv_array[0]= ptr[3];
232
inv_array[1]= ptr[2];
233
inv_array[2]= ptr[1];
234
inv_array[3]= ptr[0];
235
return uint4korr(inv_array);
240
Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
241
const char *wkb, uint32 len, String *res)
246
if (len < WKB_HEADER_SIZE)
248
geom_type= wkb_get_uint(wkb+1, (wkbByteOrder)wkb[0]);
249
if (!(geom= create_by_typeid(buffer, (int) geom_type)) ||
250
res->reserve(WKB_HEADER_SIZE, 512))
253
res->q_append((char) wkb_ndr);
254
res->q_append(geom_type);
256
return geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
257
(wkbByteOrder) wkb[0], res) ? geom : NULL;
261
bool Geometry::envelope(String *result) const
266
if (get_mbr(&mbr, &end) || result->reserve(1+4*3+SIZEOF_STORED_DOUBLE*10))
269
result->q_append((char) wkb_ndr);
270
result->q_append((uint32) wkb_polygon);
271
result->q_append((uint32) 1);
272
result->q_append((uint32) 5);
273
result->q_append(mbr.xmin);
274
result->q_append(mbr.ymin);
275
result->q_append(mbr.xmax);
276
result->q_append(mbr.ymin);
277
result->q_append(mbr.xmax);
278
result->q_append(mbr.ymax);
279
result->q_append(mbr.xmin);
280
result->q_append(mbr.ymax);
281
result->q_append(mbr.xmin);
282
result->q_append(mbr.ymin);
289
Create a point from data.
293
result Put result here
294
data Data for point is here.
298
1 Can't reallocate 'result'
301
bool Geometry::create_point(String *result, const char *data) const
303
if (no_data(data, SIZEOF_STORED_DOUBLE * 2) ||
304
result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
306
result->q_append((char) wkb_ndr);
307
result->q_append((uint32) wkb_point);
308
/* Copy two double in same format */
309
result->q_append(data, SIZEOF_STORED_DOUBLE*2);
314
Create a point from coordinates.
318
result Put result here
319
x x coordinate for point
320
y y coordinate for point
324
1 Can't reallocate 'result'
327
bool Geometry::create_point(String *result, double x, double y) const
329
if (result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
332
result->q_append((char) wkb_ndr);
333
result->q_append((uint32) wkb_point);
340
Append N points from packed format to text
344
txt Append points here
345
n_points Number of points
347
offset Offset between points
353
const char *Geometry::append_points(String *txt, uint32 n_points,
354
const char *data, uint32 offset) const
360
get_point(&x, &y, data);
361
data+= SIZEOF_STORED_DOUBLE * 2;
372
Get most bounding rectangle (mbr) for X points
376
mbr MBR (store rectangle here)
377
points Number of points
379
offset Offset between points
386
const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
390
/* read number of points */
391
if (no_data(data, 4))
393
points= uint4korr(data);
396
if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points))
399
/* Calculate MBR for points */
403
mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE);
404
data+= SIZEOF_STORED_DOUBLE * 2;
410
/***************************** Point *******************************/
412
uint32 Gis_point::get_data_size() const
414
return POINT_DATA_SIZE;
418
bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
421
if (trs->get_next_number(&x) || trs->get_next_number(&y) ||
422
wkb->reserve(SIZEOF_STORED_DOUBLE * 2))
430
uint Gis_point::init_from_wkb(const char *wkb, uint len,
431
wkbByteOrder bo, String *res)
434
if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE))
436
x= wkb_get_double(wkb, bo);
437
y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
440
return POINT_DATA_SIZE;
444
bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
449
if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
454
*end= m_data+ POINT_DATA_SIZE;
459
bool Gis_point::get_mbr(MBR *mbr, const char **end) const
465
*end= m_data+ POINT_DATA_SIZE;
469
const Geometry::Class_info *Gis_point::get_class_info() const
475
/***************************** LineString *******************************/
477
uint32 Gis_line_string::get_data_size() const
479
if (no_data(m_data, 4))
480
return GET_SIZE_ERROR;
481
return 4 + uint4korr(m_data) * POINT_DATA_SIZE;
485
bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
488
uint32 np_pos= wkb->length();
491
if (wkb->reserve(4, 512))
493
wkb->length(wkb->length()+4); // Reserve space for points
497
if (p.init_from_wkt(trs, wkb))
500
if (trs->skip_char(',')) // Didn't find ','
505
trs->set_error_msg("Too few points in LINESTRING");
508
wkb->write_at_position(np_pos, n_points);
513
uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
514
wkbByteOrder bo, String *res)
516
uint32 n_points, proper_length;
522
n_points= wkb_get_uint(wkb, bo);
523
proper_length= 4 + n_points * POINT_DATA_SIZE;
525
if (len < proper_length || res->reserve(proper_length))
528
res->q_append(n_points);
529
wkb_end= wkb + proper_length;
530
for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE)
532
if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res))
536
return proper_length;
540
bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
543
const char *data= m_data;
545
if (no_data(data, 4))
547
n_points= uint4korr(data);
551
no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) ||
552
txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
558
get_point(&x, &y, data);
559
data+= SIZEOF_STORED_DOUBLE * 2;
565
txt->length(txt->length() - 1); // Remove end ','
571
bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
573
return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0;
577
int Gis_line_string::geom_length(double *len) const
580
double prev_x, prev_y;
581
const char *data= m_data;
583
*len= 0; // In case of errors
584
if (no_data(data, 4))
586
n_points= uint4korr(data);
588
if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
591
get_point(&prev_x, &prev_y, data);
592
data+= SIZEOF_STORED_DOUBLE*2;
597
get_point(&x, &y, data);
598
data+= SIZEOF_STORED_DOUBLE * 2;
599
*len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
607
int Gis_line_string::is_closed(int *closed) const
610
double x1, y1, x2, y2;
611
const char *data= m_data;
613
if (no_data(data, 4))
615
n_points= uint4korr(data);
622
if (no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
625
/* Get first point */
626
get_point(&x1, &y1, data);
629
data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE;
630
get_point(&x2, &y2, data);
632
*closed= (x1==x2) && (y1==y2);
637
int Gis_line_string::num_points(uint32 *n_points) const
639
*n_points= uint4korr(m_data);
644
int Gis_line_string::start_point(String *result) const
646
/* +4 is for skipping over number of points */
647
return create_point(result, m_data + 4);
651
int Gis_line_string::end_point(String *result) const
654
if (no_data(m_data, 4))
656
n_points= uint4korr(m_data);
657
return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE);
661
int Gis_line_string::point_n(uint32 num, String *result) const
664
if (no_data(m_data, 4))
666
n_points= uint4korr(m_data);
667
if ((uint32) (num - 1) >= n_points) // means (num > n_points || num < 1)
670
return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE);
673
const Geometry::Class_info *Gis_line_string::get_class_info() const
675
return &linestring_class;
679
/***************************** Polygon *******************************/
681
uint32 Gis_polygon::get_data_size() const
683
uint32 n_linear_rings;
684
const char *data= m_data;
686
if (no_data(data, 4))
687
return GET_SIZE_ERROR;
688
n_linear_rings= uint4korr(data);
691
while (n_linear_rings--)
693
if (no_data(data, 4))
694
return GET_SIZE_ERROR;
695
data+= 4 + uint4korr(data)*POINT_DATA_SIZE;
697
return (uint32) (data - m_data);
701
bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
703
uint32 n_linear_rings= 0;
704
uint32 lr_pos= wkb->length();
707
if (wkb->reserve(4, 512))
709
wkb->length(wkb->length()+4); // Reserve space for points
713
uint32 ls_pos=wkb->length();
714
if (trs->check_next_symbol('(') ||
715
ls.init_from_wkt(trs, wkb) ||
716
trs->check_next_symbol(')'))
719
ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
720
if (ls.is_closed(&closed) || !closed)
722
trs->set_error_msg("POLYGON's linear ring isn't closed");
726
if (trs->skip_char(',')) // Didn't find ','
729
wkb->write_at_position(lr_pos, n_linear_rings);
734
uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
737
uint32 n_linear_rings;
738
const char *wkb_orig= wkb;
743
n_linear_rings= wkb_get_uint(wkb, bo);
744
if (res->reserve(4, 512))
748
res->q_append(n_linear_rings);
750
while (n_linear_rings--)
753
uint32 ls_pos= res->length();
757
if (!(ls_len= ls.init_from_wkb(wkb, len, bo, res)))
760
ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos);
762
if (ls.is_closed(&closed) || !closed)
767
return (uint) (wkb - wkb_orig);
771
bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
773
uint32 n_linear_rings;
774
const char *data= m_data;
776
if (no_data(data, 4))
779
n_linear_rings= uint4korr(data);
782
while (n_linear_rings--)
785
if (no_data(data, 4))
787
n_points= uint4korr(data);
789
if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) ||
790
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
793
data= append_points(txt, n_points, data, 0);
794
(*txt) [txt->length() - 1]= ')'; // Replace end ','
797
txt->length(txt->length() - 1); // Remove end ','
803
bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const
805
uint32 n_linear_rings;
806
const char *data= m_data;
808
if (no_data(data, 4))
810
n_linear_rings= uint4korr(data);
813
while (n_linear_rings--)
815
if (!(data= get_mbr_for_points(mbr, data, 0)))
823
int Gis_polygon::area(double *ar, const char **end_of_data) const
825
uint32 n_linear_rings;
827
const char *data= m_data;
829
if (no_data(data, 4))
831
n_linear_rings= uint4korr(data);
834
while (n_linear_rings--)
836
double prev_x, prev_y;
840
if (no_data(data, 4))
842
n_points= uint4korr(data);
843
if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
845
get_point(&prev_x, &prev_y, data+4);
846
data+= (4+SIZEOF_STORED_DOUBLE*2);
848
while (--n_points) // One point is already read
851
get_point(&x, &y, data);
852
data+= (SIZEOF_STORED_DOUBLE*2);
853
lr_area+= (prev_x + x)* (prev_y - y);
857
lr_area= fabs(lr_area)/2;
869
int Gis_polygon::exterior_ring(String *result) const
871
uint32 n_points, length;
872
const char *data= m_data + 4; // skip n_linerings
874
if (no_data(data, 4))
876
n_points= uint4korr(data);
878
length= n_points * POINT_DATA_SIZE;
879
if (no_data(data, length) || result->reserve(1+4+4+ length))
882
result->q_append((char) wkb_ndr);
883
result->q_append((uint32) wkb_linestring);
884
result->q_append(n_points);
885
result->q_append(data, n_points * POINT_DATA_SIZE);
890
int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const
892
if (no_data(m_data, 4))
894
*n_int_rings= uint4korr(m_data)-1;
899
int Gis_polygon::interior_ring_n(uint32 num, String *result) const
901
const char *data= m_data;
902
uint32 n_linear_rings;
906
if (no_data(data, 4))
908
n_linear_rings= uint4korr(data);
911
if (num >= n_linear_rings || num < 1)
916
if (no_data(data, 4))
918
data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
920
if (no_data(data, 4))
922
n_points= uint4korr(data);
923
points_size= n_points * POINT_DATA_SIZE;
925
if (no_data(data, points_size) || result->reserve(1+4+4+ points_size))
928
result->q_append((char) wkb_ndr);
929
result->q_append((uint32) wkb_linestring);
930
result->q_append(n_points);
931
result->q_append(data, points_size);
937
int Gis_polygon::centroid_xy(double *x, double *y) const
939
uint32 n_linear_rings;
940
double UNINIT_VAR(res_area);
941
double UNINIT_VAR(res_cx), UNINIT_VAR(res_cy);
942
const char *data= m_data;
945
if (no_data(data, 4))
947
n_linear_rings= uint4korr(data);
950
DBUG_ASSERT(n_linear_rings > 0);
952
while (n_linear_rings--)
954
uint32 n_points, org_n_points;
955
double prev_x, prev_y;
960
if (no_data(data, 4))
962
org_n_points= n_points= uint4korr(data);
964
if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
966
get_point(&prev_x, &prev_y, data);
967
data+= (SIZEOF_STORED_DOUBLE*2);
969
while (--n_points) // One point is already read
972
get_point(&tmp_x, &tmp_y, data);
973
data+= (SIZEOF_STORED_DOUBLE*2);
974
cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y);
980
cur_area= fabs(cur_area) / 2;
981
cur_cx= cur_cx / (org_n_points - 1);
982
cur_cy= cur_cy / (org_n_points - 1);
986
double d_area= fabs(res_area - cur_area);
987
res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area;
988
res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area;
1005
int Gis_polygon::centroid(String *result) const
1008
if (centroid_xy(&x, &y))
1010
return create_point(result, x, y);
1013
const Geometry::Class_info *Gis_polygon::get_class_info() const
1015
return &polygon_class;
1019
/***************************** MultiPoint *******************************/
1021
uint32 Gis_multi_point::get_data_size() const
1023
if (no_data(m_data, 4))
1024
return GET_SIZE_ERROR;
1025
return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE);
1029
bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
1032
uint32 np_pos= wkb->length();
1035
if (wkb->reserve(4, 512))
1037
wkb->length(wkb->length()+4); // Reserve space for points
1041
if (wkb->reserve(1+4, 512))
1043
wkb->q_append((char) wkb_ndr);
1044
wkb->q_append((uint32) wkb_point);
1045
if (p.init_from_wkt(trs, wkb))
1048
if (trs->skip_char(',')) // Didn't find ','
1051
wkb->write_at_position(np_pos, n_points); // Store number of found points
1056
uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
1062
const char *wkb_end;
1066
n_points= wkb_get_uint(wkb, bo);
1067
proper_size= 4 + n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
1069
if (len < proper_size || res->reserve(proper_size))
1072
res->q_append(n_points);
1073
wkb_end= wkb + proper_size;
1074
for (wkb+=4; wkb < wkb_end; wkb+= (WKB_HEADER_SIZE + POINT_DATA_SIZE))
1076
res->q_append((char)wkb_ndr);
1077
res->q_append((uint32)wkb_point);
1078
if (!p.init_from_wkb(wkb + WKB_HEADER_SIZE,
1079
POINT_DATA_SIZE, (wkbByteOrder) wkb[0], res))
1086
bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
1089
if (no_data(m_data, 4))
1092
n_points= uint4korr(m_data);
1093
if (no_data(m_data+4,
1094
n_points * (SIZEOF_STORED_DOUBLE * 2 + WKB_HEADER_SIZE)) ||
1095
txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
1097
*end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE);
1098
txt->length(txt->length()-1); // Remove end ','
1103
bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const
1105
return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0;
1109
int Gis_multi_point::num_geometries(uint32 *num) const
1111
*num= uint4korr(m_data);
1116
int Gis_multi_point::geometry_n(uint32 num, String *result) const
1118
const char *data= m_data;
1121
if (no_data(data, 4))
1123
n_points= uint4korr(data);
1124
data+= 4+ (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
1126
if (num > n_points || num < 1 ||
1127
no_data(data, WKB_HEADER_SIZE + POINT_DATA_SIZE) ||
1128
result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE))
1131
result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE);
1135
const Geometry::Class_info *Gis_multi_point::get_class_info() const
1137
return &multipoint_class;
1141
/***************************** MultiLineString *******************************/
1143
uint32 Gis_multi_line_string::get_data_size() const
1145
uint32 n_line_strings;
1146
const char *data= m_data;
1148
if (no_data(data, 4))
1149
return GET_SIZE_ERROR;
1150
n_line_strings= uint4korr(data);
1153
while (n_line_strings--)
1155
if (no_data(data, WKB_HEADER_SIZE + 4))
1156
return GET_SIZE_ERROR;
1157
data+= (WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) *
1160
return (uint32) (data - m_data);
1164
bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
1166
uint32 n_line_strings= 0;
1167
uint32 ls_pos= wkb->length();
1169
if (wkb->reserve(4, 512))
1171
wkb->length(wkb->length()+4); // Reserve space for points
1177
if (wkb->reserve(1+4, 512))
1179
wkb->q_append((char) wkb_ndr);
1180
wkb->q_append((uint32) wkb_linestring);
1182
if (trs->check_next_symbol('(') ||
1183
ls.init_from_wkt(trs, wkb) ||
1184
trs->check_next_symbol(')'))
1187
if (trs->skip_char(',')) // Didn't find ','
1190
wkb->write_at_position(ls_pos, n_line_strings);
1195
uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
1196
wkbByteOrder bo, String *res)
1198
uint32 n_line_strings;
1199
const char *wkb_orig= wkb;
1203
n_line_strings= wkb_get_uint(wkb, bo);
1205
if (res->reserve(4, 512))
1207
res->q_append(n_line_strings);
1210
while (n_line_strings--)
1215
if ((len < WKB_HEADER_SIZE) ||
1216
res->reserve(WKB_HEADER_SIZE, 512))
1219
res->q_append((char) wkb_ndr);
1220
res->q_append((uint32) wkb_linestring);
1222
if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
1223
(wkbByteOrder) wkb[0], res)))
1225
ls_len+= WKB_HEADER_SIZE;;
1229
return (uint) (wkb - wkb_orig);
1233
bool Gis_multi_line_string::get_data_as_wkt(String *txt,
1234
const char **end) const
1236
uint32 n_line_strings;
1237
const char *data= m_data;
1239
if (no_data(data, 4))
1241
n_line_strings= uint4korr(data);
1244
while (n_line_strings--)
1247
if (no_data(data, (WKB_HEADER_SIZE + 4)))
1249
n_points= uint4korr(data + WKB_HEADER_SIZE);
1250
data+= WKB_HEADER_SIZE + 4;
1251
if (no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) ||
1252
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
1254
txt->qs_append('(');
1255
data= append_points(txt, n_points, data, 0);
1256
(*txt) [txt->length() - 1]= ')';
1257
txt->qs_append(',');
1259
txt->length(txt->length() - 1);
1265
bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const
1267
uint32 n_line_strings;
1268
const char *data= m_data;
1270
if (no_data(data, 4))
1272
n_line_strings= uint4korr(data);
1275
while (n_line_strings--)
1277
data+= WKB_HEADER_SIZE;
1278
if (!(data= get_mbr_for_points(mbr, data, 0)))
1286
int Gis_multi_line_string::num_geometries(uint32 *num) const
1288
*num= uint4korr(m_data);
1293
int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
1295
uint32 n_line_strings, n_points, length;
1296
const char *data= m_data;
1298
if (no_data(data, 4))
1300
n_line_strings= uint4korr(data);
1303
if ((num > n_line_strings) || (num < 1))
1308
if (no_data(data, WKB_HEADER_SIZE + 4))
1310
n_points= uint4korr(data + WKB_HEADER_SIZE);
1311
length= WKB_HEADER_SIZE + 4+ POINT_DATA_SIZE * n_points;
1312
if (no_data(data, length))
1318
return result->append(data, length, (uint32) 0);
1322
int Gis_multi_line_string::geom_length(double *len) const
1324
uint32 n_line_strings;
1325
const char *data= m_data;
1327
if (no_data(data, 4))
1329
n_line_strings= uint4korr(data);
1333
while (n_line_strings--)
1337
data+= WKB_HEADER_SIZE;
1338
ls.set_data_ptr(data, (uint32) (m_data_end - data));
1339
if (ls.geom_length(&ls_len))
1343
We know here that ls was ok, so we can call the trivial function
1344
Gis_line_string::get_data_size without error checking
1346
data+= ls.get_data_size();
1352
int Gis_multi_line_string::is_closed(int *closed) const
1354
uint32 n_line_strings;
1355
const char *data= m_data;
1357
if (no_data(data, 4 + WKB_HEADER_SIZE))
1359
n_line_strings= uint4korr(data);
1360
data+= 4 + WKB_HEADER_SIZE;
1362
while (n_line_strings--)
1365
if (no_data(data, 0))
1367
ls.set_data_ptr(data, (uint32) (m_data_end - data));
1368
if (ls.is_closed(closed))
1373
We know here that ls was ok, so we can call the trivial function
1374
Gis_line_string::get_data_size without error checking
1376
data+= ls.get_data_size() + WKB_HEADER_SIZE;
1381
const Geometry::Class_info *Gis_multi_line_string::get_class_info() const
1383
return &multilinestring_class;
1387
/***************************** MultiPolygon *******************************/
1389
uint32 Gis_multi_polygon::get_data_size() const
1392
const char *data= m_data;
1394
if (no_data(data, 4))
1395
return GET_SIZE_ERROR;
1396
n_polygons= uint4korr(data);
1399
while (n_polygons--)
1401
uint32 n_linear_rings;
1402
if (no_data(data, 4 + WKB_HEADER_SIZE))
1403
return GET_SIZE_ERROR;
1405
n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
1406
data+= 4 + WKB_HEADER_SIZE;
1408
while (n_linear_rings--)
1410
if (no_data(data, 4))
1411
return GET_SIZE_ERROR;
1412
data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
1415
return (uint32) (data - m_data);
1419
bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
1421
uint32 n_polygons= 0;
1422
int np_pos= wkb->length();
1425
if (wkb->reserve(4, 512))
1427
wkb->length(wkb->length()+4); // Reserve space for points
1431
if (wkb->reserve(1+4, 512))
1433
wkb->q_append((char) wkb_ndr);
1434
wkb->q_append((uint32) wkb_polygon);
1436
if (trs->check_next_symbol('(') ||
1437
p.init_from_wkt(trs, wkb) ||
1438
trs->check_next_symbol(')'))
1441
if (trs->skip_char(',')) // Didn't find ','
1444
wkb->write_at_position(np_pos, n_polygons);
1449
uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
1450
wkbByteOrder bo, String *res)
1453
const char *wkb_orig= wkb;
1457
n_poly= wkb_get_uint(wkb, bo);
1459
if (res->reserve(4, 512))
1461
res->q_append(n_poly);
1469
if (len < WKB_HEADER_SIZE ||
1470
res->reserve(WKB_HEADER_SIZE, 512))
1472
res->q_append((char) wkb_ndr);
1473
res->q_append((uint32) wkb_polygon);
1475
if (!(p_len= p.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
1476
(wkbByteOrder) wkb[0], res)))
1478
p_len+= WKB_HEADER_SIZE;
1482
return (uint) (wkb - wkb_orig);
1486
bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
1489
const char *data= m_data;
1491
if (no_data(data, 4))
1493
n_polygons= uint4korr(data);
1496
while (n_polygons--)
1498
uint32 n_linear_rings;
1499
if (no_data(data, 4 + WKB_HEADER_SIZE) ||
1500
txt->reserve(1, 512))
1502
n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
1503
data+= 4 + WKB_HEADER_SIZE;
1506
while (n_linear_rings--)
1508
if (no_data(data, 4))
1510
uint32 n_points= uint4korr(data);
1512
if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) ||
1513
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
1516
txt->qs_append('(');
1517
data= append_points(txt, n_points, data, 0);
1518
(*txt) [txt->length() - 1]= ')';
1519
txt->qs_append(',');
1521
(*txt) [txt->length() - 1]= ')';
1522
txt->qs_append(',');
1524
txt->length(txt->length() - 1);
1530
bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const
1533
const char *data= m_data;
1535
if (no_data(data, 4))
1537
n_polygons= uint4korr(data);
1540
while (n_polygons--)
1542
uint32 n_linear_rings;
1543
if (no_data(data, 4+WKB_HEADER_SIZE))
1545
n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
1546
data+= WKB_HEADER_SIZE + 4;
1548
while (n_linear_rings--)
1550
if (!(data= get_mbr_for_points(mbr, data, 0)))
1559
int Gis_multi_polygon::num_geometries(uint32 *num) const
1561
*num= uint4korr(m_data);
1566
int Gis_multi_polygon::geometry_n(uint32 num, String *result) const
1569
const char *data= m_data, *start_of_polygon;
1571
if (no_data(data, 4))
1573
n_polygons= uint4korr(data);
1576
if (num > n_polygons || num < 1)
1581
uint32 n_linear_rings;
1582
start_of_polygon= data;
1584
if (no_data(data, WKB_HEADER_SIZE + 4))
1586
n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
1587
data+= WKB_HEADER_SIZE + 4;
1589
while (n_linear_rings--)
1592
if (no_data(data, 4))
1594
n_points= uint4korr(data);
1595
data+= 4 + POINT_DATA_SIZE * n_points;
1598
if (no_data(data, 0)) // We must check last segment
1600
return result->append(start_of_polygon, (uint32) (data - start_of_polygon),
1605
int Gis_multi_polygon::area(double *ar, const char **end_of_data) const
1608
const char *data= m_data;
1611
if (no_data(data, 4))
1613
n_polygons= uint4korr(data);
1616
while (n_polygons--)
1621
data+= WKB_HEADER_SIZE;
1622
p.set_data_ptr(data, (uint32) (m_data_end - data));
1623
if (p.area(&p_area, &data))
1633
int Gis_multi_polygon::centroid(String *result) const
1638
double UNINIT_VAR(res_area), UNINIT_VAR(res_cx), UNINIT_VAR(res_cy);
1639
double cur_area, cur_cx, cur_cy;
1640
const char *data= m_data;
1642
if (no_data(data, 4))
1644
n_polygons= uint4korr(data);
1647
while (n_polygons--)
1649
data+= WKB_HEADER_SIZE;
1650
p.set_data_ptr(data, (uint32) (m_data_end - data));
1651
if (p.area(&cur_area, &data) ||
1652
p.centroid_xy(&cur_cx, &cur_cy))
1657
double sum_area= res_area + cur_area;
1658
res_cx= (res_area * res_cx + cur_area * cur_cx) / sum_area;
1659
res_cy= (res_area * res_cy + cur_area * cur_cy) / sum_area;
1670
return create_point(result, res_cx, res_cy);
1673
const Geometry::Class_info *Gis_multi_polygon::get_class_info() const
1675
return &multipolygon_class;
1679
/************************* GeometryCollection ****************************/
1681
uint32 Gis_geometry_collection::get_data_size() const
1684
const char *data= m_data;
1685
Geometry_buffer buffer;
1688
if (no_data(data, 4))
1689
return GET_SIZE_ERROR;
1690
n_objects= uint4korr(data);
1695
uint32 wkb_type,object_size;
1697
if (no_data(data, WKB_HEADER_SIZE))
1698
return GET_SIZE_ERROR;
1699
wkb_type= uint4korr(data + 1);
1700
data+= WKB_HEADER_SIZE;
1702
if (!(geom= create_by_typeid(&buffer, wkb_type)))
1703
return GET_SIZE_ERROR;
1704
geom->set_data_ptr(data, (uint) (m_data_end - data));
1705
if ((object_size= geom->get_data_size()) == GET_SIZE_ERROR)
1706
return GET_SIZE_ERROR;
1709
return (uint32) (data - m_data);
1713
bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
1715
uint32 n_objects= 0;
1716
uint32 no_pos= wkb->length();
1717
Geometry_buffer buffer;
1720
if (wkb->reserve(4, 512))
1722
wkb->length(wkb->length()+4); // Reserve space for points
1726
if (!(g= create_from_wkt(&buffer, trs, wkb)))
1729
if (g->get_class_info()->m_type_id == wkb_geometrycollection)
1731
trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
1735
if (trs->skip_char(',')) // Didn't find ','
1739
wkb->write_at_position(no_pos, n_objects);
1744
uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
1745
wkbByteOrder bo, String *res)
1748
const char *wkb_orig= wkb;
1752
n_geom= wkb_get_uint(wkb, bo);
1754
if (res->reserve(4, 512))
1756
res->q_append(n_geom);
1761
Geometry_buffer buffer;
1766
if (len < WKB_HEADER_SIZE ||
1767
res->reserve(WKB_HEADER_SIZE, 512))
1770
res->q_append((char) wkb_ndr);
1771
wkb_type= wkb_get_uint(wkb+1, (wkbByteOrder) wkb[0]);
1772
res->q_append(wkb_type);
1774
if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
1775
!(g_len= geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len,
1776
(wkbByteOrder) wkb[0], res)))
1778
g_len+= WKB_HEADER_SIZE;
1782
return (uint) (wkb - wkb_orig);
1786
bool Gis_geometry_collection::get_data_as_wkt(String *txt,
1787
const char **end) const
1790
Geometry_buffer buffer;
1792
const char *data= m_data;
1794
if (no_data(data, 4))
1796
n_objects= uint4korr(data);
1803
if (no_data(data, WKB_HEADER_SIZE))
1805
wkb_type= uint4korr(data + 1);
1806
data+= WKB_HEADER_SIZE;
1808
if (!(geom= create_by_typeid(&buffer, wkb_type)))
1810
geom->set_data_ptr(data, (uint) (m_data_end - data));
1811
if (geom->as_wkt(txt, &data))
1813
if (txt->append(STRING_WITH_LEN(","), 512))
1816
txt->length(txt->length() - 1);
1822
bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
1825
const char *data= m_data;
1826
Geometry_buffer buffer;
1829
if (no_data(data, 4))
1831
n_objects= uint4korr(data);
1838
if (no_data(data, WKB_HEADER_SIZE))
1840
wkb_type= uint4korr(data + 1);
1841
data+= WKB_HEADER_SIZE;
1843
if (!(geom= create_by_typeid(&buffer, wkb_type)))
1845
geom->set_data_ptr(data, (uint32) (m_data_end - data));
1846
if (geom->get_mbr(mbr, &data))
1854
int Gis_geometry_collection::num_geometries(uint32 *num) const
1856
if (no_data(m_data, 4))
1858
*num= uint4korr(m_data);
1863
int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
1865
uint32 n_objects, wkb_type, length;
1866
const char *data= m_data;
1867
Geometry_buffer buffer;
1870
if (no_data(data, 4))
1872
n_objects= uint4korr(data);
1874
if (num > n_objects || num < 1)
1879
if (no_data(data, WKB_HEADER_SIZE))
1881
wkb_type= uint4korr(data + 1);
1882
data+= WKB_HEADER_SIZE;
1884
if (!(geom= create_by_typeid(&buffer, wkb_type)))
1886
geom->set_data_ptr(data, (uint) (m_data_end - data));
1887
if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
1892
/* Copy found object to result */
1893
if (result->reserve(1+4+length))
1895
result->q_append((char) wkb_ndr);
1896
result->q_append((uint32) wkb_type);
1897
result->q_append(data-length, length); // data-length = start_of_data
1903
Return dimension for object
1907
res_dim Result dimension
1908
end End of object will be stored here. May be 0 for
1915
bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
1918
const char *data= m_data;
1919
Geometry_buffer buffer;
1922
if (no_data(data, 4))
1924
n_objects= uint4korr(data);
1930
uint32 wkb_type, length, dim;
1931
const char *end_data;
1933
if (no_data(data, WKB_HEADER_SIZE))
1935
wkb_type= uint4korr(data + 1);
1936
data+= WKB_HEADER_SIZE;
1937
if (!(geom= create_by_typeid(&buffer, wkb_type)))
1939
geom->set_data_ptr(data, (uint32) (m_data_end - data));
1940
if (geom->dimension(&dim, &end_data))
1942
set_if_bigger(*res_dim, dim);
1943
if (end_data) // Complex object
1945
else if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
1954
const Geometry::Class_info *Gis_geometry_collection::get_class_info() const
1956
return &geometrycollection_class;
1959
#endif /*HAVE_SPATIAL*/