~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to sql/spatial.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2004 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include "mysql_priv.h"
 
17
 
 
18
#ifdef HAVE_SPATIAL
 
19
 
 
20
/* 
 
21
  exponential notation :
 
22
  1   sign
 
23
  1   number before the decimal point
 
24
  1   decimal point
 
25
  14  number of significant digits (see String::qs_append(double))
 
26
  1   'e' sign
 
27
  1   exponent sign
 
28
  3   exponent digits
 
29
  ==
 
30
  22
 
31
 
 
32
  "f" notation :
 
33
  1   optional 0
 
34
  1   sign
 
35
  14  number significant digits (see String::qs_append(double) )
 
36
  1   decimal point
 
37
  ==
 
38
  17
 
39
*/
 
40
 
 
41
#define MAX_DIGITS_IN_DOUBLE 22
 
42
 
 
43
/***************************** Gis_class_info *******************************/
 
44
 
 
45
String Geometry::bad_geometry_data("Bad object", &my_charset_bin);
 
46
 
 
47
Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_last+1]=
 
48
{
 
49
  NULL, NULL, NULL, NULL, NULL, NULL, NULL
 
50
};
 
51
 
 
52
static Geometry::Class_info **ci_collection_end=
 
53
                                Geometry::ci_collection+Geometry::wkb_last + 1;
 
54
 
 
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)
 
58
{
 
59
  m_name.str= (char *) name;
 
60
  m_name.length= strlen(name);
 
61
 
 
62
  ci_collection[type_id]= this;
 
63
}
 
64
 
 
65
static void create_point(void *buffer)
 
66
{
 
67
  new(buffer) Gis_point;
 
68
}
 
69
 
 
70
static void create_linestring(void *buffer)
 
71
{
 
72
  new(buffer) Gis_line_string;
 
73
}
 
74
 
 
75
static void create_polygon(void *buffer)
 
76
{
 
77
  new(buffer) Gis_polygon;
 
78
}
 
79
 
 
80
static void create_multipoint(void *buffer)
 
81
{
 
82
  new(buffer) Gis_multi_point;
 
83
}
 
84
 
 
85
static void create_multipolygon(void *buffer)
 
86
{
 
87
  new(buffer) Gis_multi_polygon;
 
88
}
 
89
 
 
90
static void create_multilinestring(void *buffer)
 
91
{
 
92
  new(buffer) Gis_multi_line_string;
 
93
}
 
94
 
 
95
static void create_geometrycollection(void *buffer)
 
96
{
 
97
  new(buffer) Gis_geometry_collection;
 
98
}
 
99
 
 
100
 
 
101
 
 
102
static Geometry::Class_info point_class("POINT",
 
103
                                        Geometry::wkb_point, create_point);
 
104
 
 
105
static Geometry::Class_info linestring_class("LINESTRING",
 
106
                                             Geometry::wkb_linestring,
 
107
                                             create_linestring);
 
108
static Geometry::Class_info polygon_class("POLYGON",
 
109
                                              Geometry::wkb_polygon,
 
110
                                              create_polygon);
 
111
static Geometry::Class_info multipoint_class("MULTIPOINT",
 
112
                                                 Geometry::wkb_multipoint,
 
113
                                                 create_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);
 
123
 
 
124
static void get_point(double *x, double *y, const char *data)
 
125
{
 
126
  float8get(*x, data);
 
127
  float8get(*y, data + SIZEOF_STORED_DOUBLE);
 
128
}
 
129
 
 
130
/***************************** Geometry *******************************/
 
131
 
 
132
Geometry::Class_info *Geometry::find_class(const char *name, uint32 len)
 
133
{
 
134
  for (Class_info **cur_rt= ci_collection;
 
135
       cur_rt < ci_collection_end; cur_rt++)
 
136
  {
 
137
    if (*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))
 
142
      return *cur_rt;
 
143
  }
 
144
  return 0;
 
145
}
 
146
 
 
147
 
 
148
Geometry *Geometry::construct(Geometry_buffer *buffer,
 
149
                              const char *data, uint32 data_len)
 
150
{
 
151
  uint32 geom_type;
 
152
  Geometry *result;
 
153
  char byte_order;
 
154
 
 
155
  if (data_len < SRID_SIZE + WKB_HEADER_SIZE)   // < 4 + (1 + 4)
 
156
    return NULL;
 
157
  byte_order= data[SRID_SIZE];
 
158
  geom_type= uint4korr(data + SRID_SIZE + 1);
 
159
  if (!(result= create_by_typeid(buffer, (int) geom_type)))
 
160
    return NULL;
 
161
  result->m_data= data+ SRID_SIZE + WKB_HEADER_SIZE;
 
162
  result->m_data_end= data + data_len;
 
163
  return result;
 
164
}
 
165
 
 
166
 
 
167
Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
 
168
                                    Gis_read_stream *trs, String *wkt,
 
169
                                    bool init_stream)
 
170
{
 
171
  LEX_STRING name;
 
172
  Class_info *ci;
 
173
 
 
174
  if (trs->get_next_word(&name))
 
175
  {
 
176
    trs->set_error_msg("Geometry name expected");
 
177
    return NULL;
 
178
  }
 
179
  if (!(ci= find_class(name.str, name.length)) ||
 
180
      wkt->reserve(1 + 4, 512))
 
181
    return NULL;
 
182
  (*ci->m_create_func)((void *)buffer);
 
183
  Geometry *result= (Geometry *)buffer;
 
184
  
 
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(')'))
 
190
    return NULL;
 
191
  if (init_stream)  
 
192
  {
 
193
    result->set_data_ptr(wkt->ptr(), wkt->length());
 
194
    result->shift_wkb_header();
 
195
  }
 
196
  return result;
 
197
}
 
198
 
 
199
 
 
200
static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
 
201
{
 
202
  double res;
 
203
  if (bo != Geometry::wkb_xdr)
 
204
  {
 
205
    float8get(res, ptr);
 
206
  }
 
207
  else
 
208
  {
 
209
    char inv_array[8];
 
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);
 
219
  }
 
220
  return res;
 
221
}
 
222
 
 
223
 
 
224
static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
 
225
{
 
226
  if (bo != Geometry::wkb_xdr)
 
227
    return uint4korr(ptr);
 
228
  /* else */
 
229
  {
 
230
    char inv_array[4];
 
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);
 
236
  }
 
237
}
 
238
 
 
239
 
 
240
Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
 
241
                                    const char *wkb, uint32 len, String *res)
 
242
{
 
243
  uint32 geom_type;
 
244
  Geometry *geom;
 
245
 
 
246
  if (len < WKB_HEADER_SIZE)
 
247
    return NULL;
 
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))
 
251
    return NULL;
 
252
 
 
253
  res->q_append((char) wkb_ndr);
 
254
  res->q_append(geom_type);
 
255
 
 
256
  return geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
 
257
                             (wkbByteOrder) wkb[0], res) ? geom : NULL;
 
258
}
 
259
 
 
260
 
 
261
bool Geometry::envelope(String *result) const
 
262
{
 
263
  MBR mbr;
 
264
  const char *end;
 
265
 
 
266
  if (get_mbr(&mbr, &end) || result->reserve(1+4*3+SIZEOF_STORED_DOUBLE*10))
 
267
    return 1;
 
268
 
 
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);
 
283
 
 
284
  return 0;
 
285
}
 
286
 
 
287
 
 
288
/*
 
289
  Create a point from data.
 
290
 
 
291
  SYNPOSIS
 
292
    create_point()
 
293
    result              Put result here
 
294
    data                Data for point is here.
 
295
 
 
296
  RETURN
 
297
    0   ok
 
298
    1   Can't reallocate 'result'
 
299
*/
 
300
 
 
301
bool Geometry::create_point(String *result, const char *data) const
 
302
{
 
303
  if (no_data(data, SIZEOF_STORED_DOUBLE * 2) ||
 
304
      result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
 
305
    return 1;
 
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);
 
310
  return 0;
 
311
}
 
312
 
 
313
/*
 
314
  Create a point from coordinates.
 
315
 
 
316
  SYNPOSIS
 
317
    create_point()
 
318
    result              Put result here
 
319
    x                   x coordinate for point
 
320
    y                   y coordinate for point
 
321
 
 
322
  RETURN
 
323
    0   ok
 
324
    1   Can't reallocate 'result'
 
325
*/
 
326
 
 
327
bool Geometry::create_point(String *result, double x, double y) const
 
328
{
 
329
  if (result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
 
330
    return 1;
 
331
 
 
332
  result->q_append((char) wkb_ndr);
 
333
  result->q_append((uint32) wkb_point);
 
334
  result->q_append(x);
 
335
  result->q_append(y);
 
336
  return 0;
 
337
}
 
338
 
 
339
/*
 
340
  Append N points from packed format to text
 
341
 
 
342
  SYNOPSIS
 
343
    append_points()
 
344
    txt                 Append points here
 
345
    n_points            Number of points
 
346
    data                Packed data
 
347
    offset              Offset between points
 
348
 
 
349
  RETURN
 
350
    # end of data
 
351
*/
 
352
 
 
353
const char *Geometry::append_points(String *txt, uint32 n_points,
 
354
                                    const char *data, uint32 offset) const
 
355
{                            
 
356
  while (n_points--)
 
357
  {
 
358
    double x,y;
 
359
    data+= offset;
 
360
    get_point(&x, &y, data);
 
361
    data+= SIZEOF_STORED_DOUBLE * 2;
 
362
    txt->qs_append(x);
 
363
    txt->qs_append(' ');
 
364
    txt->qs_append(y);
 
365
    txt->qs_append(',');
 
366
  }
 
367
  return data;
 
368
}
 
369
 
 
370
 
 
371
/*
 
372
  Get most bounding rectangle (mbr) for X points
 
373
 
 
374
  SYNOPSIS
 
375
    get_mbr_for_points()
 
376
    mbr                 MBR (store rectangle here)
 
377
    points              Number of points
 
378
    data                Packed data
 
379
    offset              Offset between points
 
380
 
 
381
  RETURN
 
382
    0   Wrong data
 
383
    #   end of data
 
384
*/
 
385
 
 
386
const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
 
387
                                         uint offset) const
 
388
{
 
389
  uint32 points;
 
390
  /* read number of points */
 
391
  if (no_data(data, 4))
 
392
    return 0;
 
393
  points= uint4korr(data);
 
394
  data+= 4;
 
395
 
 
396
  if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points))
 
397
    return 0;
 
398
 
 
399
  /* Calculate MBR for points */
 
400
  while (points--)
 
401
  {
 
402
    data+= offset;
 
403
    mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE);
 
404
    data+= SIZEOF_STORED_DOUBLE * 2;
 
405
  }
 
406
  return data;
 
407
}
 
408
 
 
409
 
 
410
/***************************** Point *******************************/
 
411
 
 
412
uint32 Gis_point::get_data_size() const
 
413
{
 
414
  return POINT_DATA_SIZE;
 
415
}
 
416
 
 
417
 
 
418
bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
 
419
{
 
420
  double x, y;
 
421
  if (trs->get_next_number(&x) || trs->get_next_number(&y) ||
 
422
      wkb->reserve(SIZEOF_STORED_DOUBLE * 2))
 
423
    return 1;
 
424
  wkb->q_append(x);
 
425
  wkb->q_append(y);
 
426
  return 0;
 
427
}
 
428
 
 
429
 
 
430
uint Gis_point::init_from_wkb(const char *wkb, uint len,
 
431
                              wkbByteOrder bo, String *res)
 
432
{
 
433
  double x, y;
 
434
  if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE))
 
435
    return 0;
 
436
  x= wkb_get_double(wkb, bo);
 
437
  y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
 
438
  res->q_append(x);
 
439
  res->q_append(y);
 
440
  return POINT_DATA_SIZE;
 
441
}
 
442
 
 
443
 
 
444
bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
 
445
{
 
446
  double x, y;
 
447
  if (get_xy(&x, &y))
 
448
    return 1;
 
449
  if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
 
450
    return 1;
 
451
  txt->qs_append(x);
 
452
  txt->qs_append(' ');
 
453
  txt->qs_append(y);
 
454
  *end= m_data+ POINT_DATA_SIZE;
 
455
  return 0;
 
456
}
 
457
 
 
458
 
 
459
bool Gis_point::get_mbr(MBR *mbr, const char **end) const
 
460
{
 
461
  double x, y;
 
462
  if (get_xy(&x, &y))
 
463
    return 1;
 
464
  mbr->add_xy(x, y);
 
465
  *end= m_data+ POINT_DATA_SIZE;
 
466
  return 0;
 
467
}
 
468
 
 
469
const Geometry::Class_info *Gis_point::get_class_info() const
 
470
{
 
471
  return &point_class;
 
472
}
 
473
 
 
474
 
 
475
/***************************** LineString *******************************/
 
476
 
 
477
uint32 Gis_line_string::get_data_size() const 
 
478
{
 
479
  if (no_data(m_data, 4))
 
480
    return GET_SIZE_ERROR;
 
481
  return 4 + uint4korr(m_data) * POINT_DATA_SIZE;
 
482
}
 
483
 
 
484
 
 
485
bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
 
486
{
 
487
  uint32 n_points= 0;
 
488
  uint32 np_pos= wkb->length();
 
489
  Gis_point p;
 
490
 
 
491
  if (wkb->reserve(4, 512))
 
492
    return 1;
 
493
  wkb->length(wkb->length()+4);                 // Reserve space for points  
 
494
 
 
495
  for (;;)
 
496
  {
 
497
    if (p.init_from_wkt(trs, wkb))
 
498
      return 1;
 
499
    n_points++;
 
500
    if (trs->skip_char(','))                    // Didn't find ','
 
501
      break;
 
502
  }
 
503
  if (n_points < 1)
 
504
  {
 
505
    trs->set_error_msg("Too few points in LINESTRING");
 
506
    return 1;
 
507
  }
 
508
  wkb->write_at_position(np_pos, n_points);
 
509
  return 0;
 
510
}
 
511
 
 
512
 
 
513
uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
 
514
                                    wkbByteOrder bo, String *res)
 
515
{
 
516
  uint32 n_points, proper_length;
 
517
  const char *wkb_end;
 
518
  Gis_point p;
 
519
 
 
520
  if (len < 4)
 
521
    return 0;
 
522
  n_points= wkb_get_uint(wkb, bo);
 
523
  proper_length= 4 + n_points * POINT_DATA_SIZE;
 
524
 
 
525
  if (len < proper_length || res->reserve(proper_length))
 
526
    return 0;
 
527
 
 
528
  res->q_append(n_points);
 
529
  wkb_end= wkb + proper_length;
 
530
  for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE)
 
531
  {
 
532
    if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res))
 
533
      return 0;
 
534
  }
 
535
 
 
536
  return proper_length;
 
537
}
 
538
 
 
539
 
 
540
bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
 
541
{
 
542
  uint32 n_points;
 
543
  const char *data= m_data;
 
544
 
 
545
  if (no_data(data, 4))
 
546
    return 1;
 
547
  n_points= uint4korr(data);
 
548
  data += 4;
 
549
 
 
550
  if (n_points < 1 ||
 
551
      no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) ||
 
552
      txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
 
553
    return 1;
 
554
 
 
555
  while (n_points--)
 
556
  {
 
557
    double x, y;
 
558
    get_point(&x, &y, data);
 
559
    data+= SIZEOF_STORED_DOUBLE * 2;
 
560
    txt->qs_append(x);
 
561
    txt->qs_append(' ');
 
562
    txt->qs_append(y);
 
563
    txt->qs_append(',');
 
564
  }
 
565
  txt->length(txt->length() - 1);               // Remove end ','
 
566
  *end= data;
 
567
  return 0;
 
568
}
 
569
 
 
570
 
 
571
bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
 
572
{
 
573
  return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0;
 
574
}
 
575
 
 
576
 
 
577
int Gis_line_string::geom_length(double *len) const
 
578
{
 
579
  uint32 n_points;
 
580
  double prev_x, prev_y;
 
581
  const char *data= m_data;
 
582
 
 
583
  *len= 0;                                      // In case of errors
 
584
  if (no_data(data, 4))
 
585
    return 1;
 
586
  n_points= uint4korr(data);
 
587
  data+= 4;
 
588
  if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
 
589
    return 1;
 
590
 
 
591
  get_point(&prev_x, &prev_y, data);
 
592
  data+= SIZEOF_STORED_DOUBLE*2;
 
593
 
 
594
  while (--n_points)
 
595
  {
 
596
    double x, y;
 
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));
 
600
    prev_x= x;
 
601
    prev_y= y;
 
602
  }
 
603
  return 0;
 
604
}
 
605
 
 
606
 
 
607
int Gis_line_string::is_closed(int *closed) const
 
608
{
 
609
  uint32 n_points;
 
610
  double x1, y1, x2, y2;
 
611
  const char *data= m_data;
 
612
 
 
613
  if (no_data(data, 4))
 
614
    return 1;
 
615
  n_points= uint4korr(data);
 
616
  if (n_points == 1)
 
617
  {
 
618
    *closed=1;
 
619
    return 0;
 
620
  }
 
621
  data+= 4;
 
622
  if (no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
 
623
    return 1;
 
624
 
 
625
  /* Get first point */
 
626
  get_point(&x1, &y1, data);
 
627
 
 
628
  /* get last point */
 
629
  data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE;
 
630
  get_point(&x2, &y2, data);
 
631
 
 
632
  *closed= (x1==x2) && (y1==y2);
 
633
  return 0;
 
634
}
 
635
 
 
636
 
 
637
int Gis_line_string::num_points(uint32 *n_points) const
 
638
{
 
639
  *n_points= uint4korr(m_data);
 
640
  return 0;
 
641
}
 
642
 
 
643
 
 
644
int Gis_line_string::start_point(String *result) const
 
645
{
 
646
  /* +4 is for skipping over number of points */
 
647
  return create_point(result, m_data + 4);
 
648
}
 
649
 
 
650
 
 
651
int Gis_line_string::end_point(String *result) const
 
652
{
 
653
  uint32 n_points;
 
654
  if (no_data(m_data, 4))
 
655
    return 1;
 
656
  n_points= uint4korr(m_data);
 
657
  return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE);
 
658
}
 
659
 
 
660
 
 
661
int Gis_line_string::point_n(uint32 num, String *result) const
 
662
{
 
663
  uint32 n_points;
 
664
  if (no_data(m_data, 4))
 
665
    return 1;
 
666
  n_points= uint4korr(m_data);
 
667
  if ((uint32) (num - 1) >= n_points) // means (num > n_points || num < 1)
 
668
    return 1;
 
669
 
 
670
  return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE);
 
671
}
 
672
 
 
673
const Geometry::Class_info *Gis_line_string::get_class_info() const
 
674
{
 
675
  return &linestring_class;
 
676
}
 
677
 
 
678
 
 
679
/***************************** Polygon *******************************/
 
680
 
 
681
uint32 Gis_polygon::get_data_size() const 
 
682
{
 
683
  uint32 n_linear_rings;
 
684
  const char *data= m_data;
 
685
 
 
686
  if (no_data(data, 4))
 
687
    return GET_SIZE_ERROR;
 
688
  n_linear_rings= uint4korr(data);
 
689
  data+= 4;
 
690
 
 
691
  while (n_linear_rings--)
 
692
  {
 
693
    if (no_data(data, 4))
 
694
      return GET_SIZE_ERROR;
 
695
    data+= 4 + uint4korr(data)*POINT_DATA_SIZE;
 
696
  }
 
697
  return (uint32) (data - m_data);
 
698
}
 
699
 
 
700
 
 
701
bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
 
702
{
 
703
  uint32 n_linear_rings= 0;
 
704
  uint32 lr_pos= wkb->length();
 
705
  int closed;
 
706
 
 
707
  if (wkb->reserve(4, 512))
 
708
    return 1;
 
709
  wkb->length(wkb->length()+4);                 // Reserve space for points
 
710
  for (;;)  
 
711
  {
 
712
    Gis_line_string ls;
 
713
    uint32 ls_pos=wkb->length();
 
714
    if (trs->check_next_symbol('(') ||
 
715
        ls.init_from_wkt(trs, wkb) ||
 
716
        trs->check_next_symbol(')'))
 
717
      return 1;
 
718
 
 
719
    ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
 
720
    if (ls.is_closed(&closed) || !closed)
 
721
    {
 
722
      trs->set_error_msg("POLYGON's linear ring isn't closed");
 
723
      return 1;
 
724
    }
 
725
    n_linear_rings++;
 
726
    if (trs->skip_char(','))                    // Didn't find ','
 
727
      break;
 
728
  }
 
729
  wkb->write_at_position(lr_pos, n_linear_rings);
 
730
  return 0;
 
731
}
 
732
 
 
733
 
 
734
uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
 
735
                                String *res)
 
736
{
 
737
  uint32 n_linear_rings;
 
738
  const char *wkb_orig= wkb;
 
739
 
 
740
  if (len < 4)
 
741
    return 0;
 
742
 
 
743
  n_linear_rings= wkb_get_uint(wkb, bo);
 
744
  if (res->reserve(4, 512))
 
745
    return 0;
 
746
  wkb+= 4;
 
747
  len-= 4;
 
748
  res->q_append(n_linear_rings);
 
749
 
 
750
  while (n_linear_rings--)
 
751
  {
 
752
    Gis_line_string ls;
 
753
    uint32 ls_pos= res->length();
 
754
    int ls_len;
 
755
    int closed;
 
756
 
 
757
    if (!(ls_len= ls.init_from_wkb(wkb, len, bo, res)))
 
758
      return 0;
 
759
 
 
760
    ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos);
 
761
 
 
762
    if (ls.is_closed(&closed) || !closed)
 
763
      return 0;
 
764
    wkb+= ls_len;
 
765
  }
 
766
 
 
767
  return (uint) (wkb - wkb_orig);
 
768
}
 
769
 
 
770
 
 
771
bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
 
772
{
 
773
  uint32 n_linear_rings;
 
774
  const char *data= m_data;
 
775
 
 
776
  if (no_data(data, 4))
 
777
    return 1;
 
778
 
 
779
  n_linear_rings= uint4korr(data);
 
780
  data+= 4;
 
781
 
 
782
  while (n_linear_rings--)
 
783
  {
 
784
    uint32 n_points;
 
785
    if (no_data(data, 4))
 
786
      return 1;
 
787
    n_points= uint4korr(data);
 
788
    data+= 4;
 
789
    if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) ||
 
790
        txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
 
791
      return 1;
 
792
    txt->qs_append('(');
 
793
    data= append_points(txt, n_points, data, 0);
 
794
    (*txt) [txt->length() - 1]= ')';            // Replace end ','
 
795
    txt->qs_append(',');
 
796
  }
 
797
  txt->length(txt->length() - 1);               // Remove end ','
 
798
  *end= data;
 
799
  return 0;
 
800
}
 
801
 
 
802
 
 
803
bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const
 
804
{
 
805
  uint32 n_linear_rings;
 
806
  const char *data= m_data;
 
807
 
 
808
  if (no_data(data, 4))
 
809
    return 1;
 
810
  n_linear_rings= uint4korr(data);
 
811
  data+= 4;
 
812
 
 
813
  while (n_linear_rings--)
 
814
  {
 
815
    if (!(data= get_mbr_for_points(mbr, data, 0)))
 
816
      return 1;
 
817
  }
 
818
  *end= data;
 
819
  return 0;
 
820
}
 
821
 
 
822
 
 
823
int Gis_polygon::area(double *ar, const char **end_of_data) const
 
824
{
 
825
  uint32 n_linear_rings;
 
826
  double result= -1.0;
 
827
  const char *data= m_data;
 
828
 
 
829
  if (no_data(data, 4))
 
830
    return 1;
 
831
  n_linear_rings= uint4korr(data);
 
832
  data+= 4;
 
833
 
 
834
  while (n_linear_rings--)
 
835
  {
 
836
    double prev_x, prev_y;
 
837
    double lr_area= 0;
 
838
    uint32 n_points;
 
839
 
 
840
    if (no_data(data, 4))
 
841
      return 1;
 
842
    n_points= uint4korr(data);
 
843
    if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
 
844
      return 1;
 
845
    get_point(&prev_x, &prev_y, data+4);
 
846
    data+= (4+SIZEOF_STORED_DOUBLE*2);
 
847
 
 
848
    while (--n_points)                          // One point is already read
 
849
    {
 
850
      double x, y;
 
851
      get_point(&x, &y, data);
 
852
      data+= (SIZEOF_STORED_DOUBLE*2);
 
853
      lr_area+= (prev_x + x)* (prev_y - y);
 
854
      prev_x= x;
 
855
      prev_y= y;
 
856
    }
 
857
    lr_area= fabs(lr_area)/2;
 
858
    if (result == -1.0)
 
859
      result= lr_area;
 
860
    else
 
861
      result-= lr_area;
 
862
  }
 
863
  *ar= fabs(result);
 
864
  *end_of_data= data;
 
865
  return 0;
 
866
}
 
867
 
 
868
 
 
869
int Gis_polygon::exterior_ring(String *result) const
 
870
{
 
871
  uint32 n_points, length;
 
872
  const char *data= m_data + 4; // skip n_linerings
 
873
 
 
874
  if (no_data(data, 4))
 
875
    return 1;
 
876
  n_points= uint4korr(data);
 
877
  data+= 4;
 
878
  length= n_points * POINT_DATA_SIZE;
 
879
  if (no_data(data, length) || result->reserve(1+4+4+ length))
 
880
    return 1;
 
881
 
 
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); 
 
886
  return 0;
 
887
}
 
888
 
 
889
 
 
890
int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const
 
891
{
 
892
  if (no_data(m_data, 4))
 
893
    return 1;
 
894
  *n_int_rings= uint4korr(m_data)-1;
 
895
  return 0;
 
896
}
 
897
 
 
898
 
 
899
int Gis_polygon::interior_ring_n(uint32 num, String *result) const
 
900
{
 
901
  const char *data= m_data;
 
902
  uint32 n_linear_rings;
 
903
  uint32 n_points;
 
904
  uint32 points_size;
 
905
 
 
906
  if (no_data(data, 4))
 
907
    return 1;
 
908
  n_linear_rings= uint4korr(data);
 
909
  data+= 4;
 
910
 
 
911
  if (num >= n_linear_rings || num < 1)
 
912
    return 1;
 
913
 
 
914
  while (num--)
 
915
  {
 
916
    if (no_data(data, 4))
 
917
      return 1;
 
918
    data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
 
919
  }
 
920
  if (no_data(data, 4))
 
921
    return 1;
 
922
  n_points= uint4korr(data);
 
923
  points_size= n_points * POINT_DATA_SIZE;
 
924
  data+= 4;
 
925
  if (no_data(data, points_size) || result->reserve(1+4+4+ points_size))
 
926
    return 1;
 
927
 
 
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); 
 
932
 
 
933
  return 0;
 
934
}
 
935
 
 
936
 
 
937
int Gis_polygon::centroid_xy(double *x, double *y) const
 
938
{
 
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;
 
943
  bool first_loop= 1;
 
944
 
 
945
  if (no_data(data, 4))
 
946
    return 1;
 
947
  n_linear_rings= uint4korr(data);
 
948
  data+= 4;
 
949
 
 
950
  DBUG_ASSERT(n_linear_rings > 0);
 
951
 
 
952
  while (n_linear_rings--)
 
953
  {
 
954
    uint32 n_points, org_n_points;
 
955
    double prev_x, prev_y;
 
956
    double cur_area= 0;
 
957
    double cur_cx= 0;
 
958
    double cur_cy= 0;
 
959
 
 
960
    if (no_data(data, 4))
 
961
      return 1;
 
962
    org_n_points= n_points= uint4korr(data);
 
963
    data+= 4;
 
964
    if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
 
965
      return 1;
 
966
    get_point(&prev_x, &prev_y, data);
 
967
    data+= (SIZEOF_STORED_DOUBLE*2);
 
968
 
 
969
    while (--n_points)                          // One point is already read
 
970
    {
 
971
      double tmp_x, tmp_y;
 
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);
 
975
      cur_cx+= tmp_x;
 
976
      cur_cy+= tmp_y;
 
977
      prev_x= tmp_x;
 
978
      prev_y= tmp_y;
 
979
    }
 
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);
 
983
 
 
984
    if (!first_loop)
 
985
    {
 
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;
 
989
    }
 
990
    else
 
991
    {
 
992
      first_loop= 0;
 
993
      res_area= cur_area;
 
994
      res_cx= cur_cx;
 
995
      res_cy= cur_cy;
 
996
    }
 
997
  }
 
998
 
 
999
  *x= res_cx;
 
1000
  *y= res_cy;
 
1001
  return 0;
 
1002
}
 
1003
 
 
1004
 
 
1005
int Gis_polygon::centroid(String *result) const
 
1006
{
 
1007
  double x, y;
 
1008
  if (centroid_xy(&x, &y))
 
1009
    return 1;
 
1010
  return create_point(result, x, y);
 
1011
}
 
1012
 
 
1013
const Geometry::Class_info *Gis_polygon::get_class_info() const
 
1014
{
 
1015
  return &polygon_class;
 
1016
}
 
1017
 
 
1018
 
 
1019
/***************************** MultiPoint *******************************/
 
1020
 
 
1021
uint32 Gis_multi_point::get_data_size() const 
 
1022
{
 
1023
  if (no_data(m_data, 4))
 
1024
    return GET_SIZE_ERROR;
 
1025
  return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE);
 
1026
}
 
1027
 
 
1028
 
 
1029
bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
 
1030
{
 
1031
  uint32 n_points= 0;
 
1032
  uint32 np_pos= wkb->length();
 
1033
  Gis_point p;
 
1034
 
 
1035
  if (wkb->reserve(4, 512))
 
1036
    return 1;
 
1037
  wkb->length(wkb->length()+4);                 // Reserve space for points
 
1038
 
 
1039
  for (;;)
 
1040
  {
 
1041
    if (wkb->reserve(1+4, 512))
 
1042
      return 1;
 
1043
    wkb->q_append((char) wkb_ndr);
 
1044
    wkb->q_append((uint32) wkb_point);
 
1045
    if (p.init_from_wkt(trs, wkb))
 
1046
      return 1;
 
1047
    n_points++;
 
1048
    if (trs->skip_char(','))                    // Didn't find ','
 
1049
      break;
 
1050
  }
 
1051
  wkb->write_at_position(np_pos, n_points);     // Store number of found points
 
1052
  return 0;
 
1053
}
 
1054
 
 
1055
 
 
1056
uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
 
1057
                                    String *res)
 
1058
{
 
1059
  uint32 n_points;
 
1060
  uint proper_size;
 
1061
  Gis_point p;
 
1062
  const char *wkb_end;
 
1063
 
 
1064
  if (len < 4)
 
1065
    return 0;
 
1066
  n_points= wkb_get_uint(wkb, bo);
 
1067
  proper_size= 4 + n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
 
1068
 
 
1069
  if (len < proper_size || res->reserve(proper_size))
 
1070
    return 0;
 
1071
    
 
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))
 
1075
  {
 
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))
 
1080
      return 0;
 
1081
  }
 
1082
  return proper_size;
 
1083
}
 
1084
 
 
1085
 
 
1086
bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
 
1087
{
 
1088
  uint32 n_points;
 
1089
  if (no_data(m_data, 4))
 
1090
    return 1;
 
1091
 
 
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))
 
1096
    return 1;
 
1097
  *end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE);
 
1098
  txt->length(txt->length()-1);                 // Remove end ','
 
1099
  return 0;
 
1100
}
 
1101
 
 
1102
 
 
1103
bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const
 
1104
{
 
1105
  return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0;
 
1106
}
 
1107
 
 
1108
 
 
1109
int Gis_multi_point::num_geometries(uint32 *num) const
 
1110
{
 
1111
  *num= uint4korr(m_data);
 
1112
  return 0;
 
1113
}
 
1114
 
 
1115
 
 
1116
int Gis_multi_point::geometry_n(uint32 num, String *result) const
 
1117
{
 
1118
  const char *data= m_data;
 
1119
  uint32 n_points;
 
1120
 
 
1121
  if (no_data(data, 4))
 
1122
    return 1;
 
1123
  n_points= uint4korr(data);
 
1124
  data+= 4+ (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
 
1125
 
 
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))
 
1129
    return 1;
 
1130
 
 
1131
  result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE);
 
1132
  return 0;
 
1133
}
 
1134
 
 
1135
const Geometry::Class_info *Gis_multi_point::get_class_info() const
 
1136
{
 
1137
  return &multipoint_class;
 
1138
}
 
1139
 
 
1140
 
 
1141
/***************************** MultiLineString *******************************/
 
1142
 
 
1143
uint32 Gis_multi_line_string::get_data_size() const 
 
1144
{
 
1145
  uint32 n_line_strings;
 
1146
  const char *data= m_data;
 
1147
 
 
1148
  if (no_data(data, 4))
 
1149
    return GET_SIZE_ERROR;
 
1150
  n_line_strings= uint4korr(data);
 
1151
  data+= 4;
 
1152
 
 
1153
  while (n_line_strings--)
 
1154
  {
 
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) *
 
1158
            POINT_DATA_SIZE);
 
1159
  }
 
1160
  return (uint32) (data - m_data);
 
1161
}
 
1162
 
 
1163
 
 
1164
bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
 
1165
{
 
1166
  uint32 n_line_strings= 0;
 
1167
  uint32 ls_pos= wkb->length();
 
1168
 
 
1169
  if (wkb->reserve(4, 512))
 
1170
    return 1;
 
1171
  wkb->length(wkb->length()+4);                 // Reserve space for points
 
1172
  
 
1173
  for (;;)
 
1174
  {
 
1175
    Gis_line_string ls;
 
1176
 
 
1177
    if (wkb->reserve(1+4, 512))
 
1178
      return 1;
 
1179
    wkb->q_append((char) wkb_ndr);
 
1180
    wkb->q_append((uint32) wkb_linestring);
 
1181
 
 
1182
    if (trs->check_next_symbol('(') ||
 
1183
        ls.init_from_wkt(trs, wkb) ||
 
1184
        trs->check_next_symbol(')'))
 
1185
      return 1;
 
1186
    n_line_strings++;
 
1187
    if (trs->skip_char(','))                    // Didn't find ','
 
1188
      break;
 
1189
  }
 
1190
  wkb->write_at_position(ls_pos, n_line_strings);
 
1191
  return 0;
 
1192
}
 
1193
 
 
1194
 
 
1195
uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
 
1196
                                          wkbByteOrder bo, String *res)
 
1197
{
 
1198
  uint32 n_line_strings;
 
1199
  const char *wkb_orig= wkb;
 
1200
 
 
1201
  if (len < 4)
 
1202
    return 0;
 
1203
  n_line_strings= wkb_get_uint(wkb, bo);
 
1204
 
 
1205
  if (res->reserve(4, 512))
 
1206
    return 0;
 
1207
  res->q_append(n_line_strings);
 
1208
  
 
1209
  wkb+= 4;
 
1210
  while (n_line_strings--)
 
1211
  {
 
1212
    Gis_line_string ls;
 
1213
    int ls_len;
 
1214
 
 
1215
    if ((len < WKB_HEADER_SIZE) ||
 
1216
        res->reserve(WKB_HEADER_SIZE, 512))
 
1217
      return 0;
 
1218
 
 
1219
    res->q_append((char) wkb_ndr);
 
1220
    res->q_append((uint32) wkb_linestring);
 
1221
 
 
1222
    if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
 
1223
                                   (wkbByteOrder) wkb[0], res)))
 
1224
      return 0;
 
1225
    ls_len+= WKB_HEADER_SIZE;;
 
1226
    wkb+= ls_len;
 
1227
    len-= ls_len;
 
1228
  }
 
1229
  return (uint) (wkb - wkb_orig);
 
1230
}
 
1231
 
 
1232
 
 
1233
bool Gis_multi_line_string::get_data_as_wkt(String *txt, 
 
1234
                                             const char **end) const
 
1235
{
 
1236
  uint32 n_line_strings;
 
1237
  const char *data= m_data;
 
1238
 
 
1239
  if (no_data(data, 4))
 
1240
    return 1;
 
1241
  n_line_strings= uint4korr(data);
 
1242
  data+= 4;
 
1243
 
 
1244
  while (n_line_strings--)
 
1245
  {
 
1246
    uint32 n_points;
 
1247
    if (no_data(data, (WKB_HEADER_SIZE + 4)))
 
1248
      return 1;
 
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))
 
1253
      return 1;
 
1254
    txt->qs_append('(');
 
1255
    data= append_points(txt, n_points, data, 0);
 
1256
    (*txt) [txt->length() - 1]= ')';
 
1257
    txt->qs_append(',');
 
1258
  }
 
1259
  txt->length(txt->length() - 1);
 
1260
  *end= data;
 
1261
  return 0;
 
1262
}
 
1263
 
 
1264
 
 
1265
bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const
 
1266
{
 
1267
  uint32 n_line_strings;
 
1268
  const char *data= m_data;
 
1269
 
 
1270
  if (no_data(data, 4))
 
1271
    return 1;
 
1272
  n_line_strings= uint4korr(data);
 
1273
  data+= 4;
 
1274
 
 
1275
  while (n_line_strings--)
 
1276
  {
 
1277
    data+= WKB_HEADER_SIZE;
 
1278
    if (!(data= get_mbr_for_points(mbr, data, 0)))
 
1279
      return 1;
 
1280
  }
 
1281
  *end= data;
 
1282
  return 0;
 
1283
}
 
1284
 
 
1285
 
 
1286
int Gis_multi_line_string::num_geometries(uint32 *num) const
 
1287
{
 
1288
  *num= uint4korr(m_data);
 
1289
  return 0;
 
1290
}
 
1291
 
 
1292
 
 
1293
int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
 
1294
{
 
1295
  uint32 n_line_strings, n_points, length;
 
1296
  const char *data= m_data;
 
1297
 
 
1298
  if (no_data(data, 4))
 
1299
    return 1;
 
1300
  n_line_strings= uint4korr(data);
 
1301
  data+= 4;
 
1302
 
 
1303
  if ((num > n_line_strings) || (num < 1))
 
1304
    return 1;
 
1305
 
 
1306
  for (;;)
 
1307
  {
 
1308
    if (no_data(data, WKB_HEADER_SIZE + 4))
 
1309
      return 1;
 
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))
 
1313
      return 1;
 
1314
    if (!--num)
 
1315
      break;
 
1316
    data+= length;
 
1317
  }
 
1318
  return result->append(data, length, (uint32) 0);
 
1319
}
 
1320
 
 
1321
 
 
1322
int Gis_multi_line_string::geom_length(double *len) const
 
1323
{
 
1324
  uint32 n_line_strings;
 
1325
  const char *data= m_data;
 
1326
 
 
1327
  if (no_data(data, 4))
 
1328
    return 1;
 
1329
  n_line_strings= uint4korr(data);
 
1330
  data+= 4;
 
1331
 
 
1332
  *len=0;
 
1333
  while (n_line_strings--)
 
1334
  {
 
1335
    double ls_len;
 
1336
    Gis_line_string ls;
 
1337
    data+= WKB_HEADER_SIZE;
 
1338
    ls.set_data_ptr(data, (uint32) (m_data_end - data));
 
1339
    if (ls.geom_length(&ls_len))
 
1340
      return 1;
 
1341
    *len+= ls_len;
 
1342
    /*
 
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
 
1345
    */
 
1346
    data+= ls.get_data_size();
 
1347
  }
 
1348
  return 0;
 
1349
}
 
1350
 
 
1351
 
 
1352
int Gis_multi_line_string::is_closed(int *closed) const
 
1353
{
 
1354
  uint32 n_line_strings;
 
1355
  const char *data= m_data;
 
1356
 
 
1357
  if (no_data(data, 4 + WKB_HEADER_SIZE))
 
1358
    return 1;
 
1359
  n_line_strings= uint4korr(data);
 
1360
  data+= 4 + WKB_HEADER_SIZE;
 
1361
 
 
1362
  while (n_line_strings--)
 
1363
  {
 
1364
    Gis_line_string ls;
 
1365
    if (no_data(data, 0))
 
1366
      return 1;
 
1367
    ls.set_data_ptr(data, (uint32) (m_data_end - data));
 
1368
    if (ls.is_closed(closed))
 
1369
      return 1;
 
1370
    if (!*closed)
 
1371
      return 0;
 
1372
    /*
 
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
 
1375
    */
 
1376
    data+= ls.get_data_size() + WKB_HEADER_SIZE;
 
1377
  }
 
1378
  return 0;
 
1379
}
 
1380
 
 
1381
const Geometry::Class_info *Gis_multi_line_string::get_class_info() const
 
1382
{
 
1383
  return &multilinestring_class;
 
1384
}
 
1385
 
 
1386
 
 
1387
/***************************** MultiPolygon *******************************/
 
1388
 
 
1389
uint32 Gis_multi_polygon::get_data_size() const 
 
1390
{
 
1391
  uint32 n_polygons;
 
1392
  const char *data= m_data;
 
1393
 
 
1394
  if (no_data(data, 4))
 
1395
    return GET_SIZE_ERROR;
 
1396
  n_polygons= uint4korr(data);
 
1397
  data+= 4;
 
1398
 
 
1399
  while (n_polygons--)
 
1400
  {
 
1401
    uint32 n_linear_rings;
 
1402
    if (no_data(data, 4 + WKB_HEADER_SIZE))
 
1403
      return GET_SIZE_ERROR;
 
1404
 
 
1405
    n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
 
1406
    data+= 4 + WKB_HEADER_SIZE;
 
1407
 
 
1408
    while (n_linear_rings--)
 
1409
    {
 
1410
      if (no_data(data, 4))
 
1411
        return GET_SIZE_ERROR;
 
1412
      data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
 
1413
    }
 
1414
  }
 
1415
  return (uint32) (data - m_data);
 
1416
}
 
1417
 
 
1418
 
 
1419
bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
 
1420
{
 
1421
  uint32 n_polygons= 0;
 
1422
  int np_pos= wkb->length();
 
1423
  Gis_polygon p;
 
1424
 
 
1425
  if (wkb->reserve(4, 512))
 
1426
    return 1;
 
1427
  wkb->length(wkb->length()+4);                 // Reserve space for points
 
1428
 
 
1429
  for (;;)  
 
1430
  {
 
1431
    if (wkb->reserve(1+4, 512))
 
1432
      return 1;
 
1433
    wkb->q_append((char) wkb_ndr);
 
1434
    wkb->q_append((uint32) wkb_polygon);
 
1435
 
 
1436
    if (trs->check_next_symbol('(') ||
 
1437
        p.init_from_wkt(trs, wkb) ||
 
1438
        trs->check_next_symbol(')'))
 
1439
      return 1;
 
1440
    n_polygons++;
 
1441
    if (trs->skip_char(','))                    // Didn't find ','
 
1442
      break;
 
1443
  }
 
1444
  wkb->write_at_position(np_pos, n_polygons);
 
1445
  return 0;
 
1446
}
 
1447
 
 
1448
 
 
1449
uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
 
1450
                                      wkbByteOrder bo, String *res)
 
1451
{
 
1452
  uint32 n_poly;
 
1453
  const char *wkb_orig= wkb;
 
1454
 
 
1455
  if (len < 4)
 
1456
    return 0;
 
1457
  n_poly= wkb_get_uint(wkb, bo);
 
1458
 
 
1459
  if (res->reserve(4, 512))
 
1460
    return 0;
 
1461
  res->q_append(n_poly);
 
1462
  
 
1463
  wkb+=4;
 
1464
  while (n_poly--)
 
1465
  {
 
1466
    Gis_polygon p;
 
1467
    int p_len;
 
1468
 
 
1469
    if (len < WKB_HEADER_SIZE ||
 
1470
        res->reserve(WKB_HEADER_SIZE, 512))
 
1471
      return 0;
 
1472
    res->q_append((char) wkb_ndr);
 
1473
    res->q_append((uint32) wkb_polygon);
 
1474
 
 
1475
    if (!(p_len= p.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
 
1476
                                 (wkbByteOrder) wkb[0], res)))
 
1477
      return 0;
 
1478
    p_len+= WKB_HEADER_SIZE;
 
1479
    wkb+= p_len;
 
1480
    len-= p_len;
 
1481
  }
 
1482
  return (uint) (wkb - wkb_orig);
 
1483
}
 
1484
 
 
1485
 
 
1486
bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
 
1487
{
 
1488
  uint32 n_polygons;
 
1489
  const char *data= m_data;
 
1490
 
 
1491
  if (no_data(data, 4))
 
1492
    return 1;
 
1493
  n_polygons= uint4korr(data);
 
1494
  data+= 4;
 
1495
 
 
1496
  while (n_polygons--)
 
1497
  {
 
1498
    uint32 n_linear_rings;
 
1499
    if (no_data(data, 4 + WKB_HEADER_SIZE) ||
 
1500
        txt->reserve(1, 512))
 
1501
      return 1;
 
1502
    n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
 
1503
    data+= 4 + WKB_HEADER_SIZE;
 
1504
    txt->q_append('(');
 
1505
 
 
1506
    while (n_linear_rings--)
 
1507
    {
 
1508
      if (no_data(data, 4))
 
1509
        return 1;
 
1510
      uint32 n_points= uint4korr(data);
 
1511
      data+= 4;
 
1512
      if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) ||
 
1513
          txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
 
1514
                       512))
 
1515
        return 1;
 
1516
      txt->qs_append('(');
 
1517
      data= append_points(txt, n_points, data, 0);
 
1518
      (*txt) [txt->length() - 1]= ')';
 
1519
      txt->qs_append(',');
 
1520
    }
 
1521
    (*txt) [txt->length() - 1]= ')';
 
1522
    txt->qs_append(',');
 
1523
  }
 
1524
  txt->length(txt->length() - 1);
 
1525
  *end= data;
 
1526
  return 0;
 
1527
}
 
1528
 
 
1529
 
 
1530
bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const
 
1531
{
 
1532
  uint32 n_polygons;
 
1533
  const char *data= m_data;
 
1534
 
 
1535
  if (no_data(data, 4))
 
1536
    return 1;
 
1537
  n_polygons= uint4korr(data);
 
1538
  data+= 4;
 
1539
 
 
1540
  while (n_polygons--)
 
1541
  {
 
1542
    uint32 n_linear_rings;
 
1543
    if (no_data(data, 4+WKB_HEADER_SIZE))
 
1544
      return 1;
 
1545
    n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
 
1546
    data+= WKB_HEADER_SIZE + 4;
 
1547
 
 
1548
    while (n_linear_rings--)
 
1549
    {
 
1550
      if (!(data= get_mbr_for_points(mbr, data, 0)))
 
1551
        return 1;
 
1552
    }
 
1553
  }
 
1554
  *end= data;
 
1555
  return 0;
 
1556
}
 
1557
 
 
1558
 
 
1559
int Gis_multi_polygon::num_geometries(uint32 *num) const
 
1560
{
 
1561
  *num= uint4korr(m_data);
 
1562
  return 0;
 
1563
}
 
1564
 
 
1565
 
 
1566
int Gis_multi_polygon::geometry_n(uint32 num, String *result) const
 
1567
{
 
1568
  uint32 n_polygons;
 
1569
  const char *data= m_data, *start_of_polygon;
 
1570
 
 
1571
  if (no_data(data, 4))
 
1572
    return 1;
 
1573
  n_polygons= uint4korr(data);
 
1574
  data+= 4;
 
1575
 
 
1576
  if (num > n_polygons || num < 1)
 
1577
    return -1;
 
1578
 
 
1579
  do
 
1580
  {
 
1581
    uint32 n_linear_rings;
 
1582
    start_of_polygon= data;
 
1583
 
 
1584
    if (no_data(data, WKB_HEADER_SIZE + 4))
 
1585
      return 1;
 
1586
    n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
 
1587
    data+= WKB_HEADER_SIZE + 4;
 
1588
 
 
1589
    while (n_linear_rings--)
 
1590
    {
 
1591
      uint32 n_points;
 
1592
      if (no_data(data, 4))
 
1593
        return 1;
 
1594
      n_points= uint4korr(data);
 
1595
      data+= 4 + POINT_DATA_SIZE * n_points;
 
1596
    }
 
1597
  } while (--num);
 
1598
  if (no_data(data, 0))                         // We must check last segment
 
1599
    return 1;
 
1600
  return result->append(start_of_polygon, (uint32) (data - start_of_polygon),
 
1601
                        (uint32) 0);
 
1602
}
 
1603
 
 
1604
 
 
1605
int Gis_multi_polygon::area(double *ar,  const char **end_of_data) const
 
1606
{
 
1607
  uint32 n_polygons;
 
1608
  const char *data= m_data;
 
1609
  double result= 0;
 
1610
 
 
1611
  if (no_data(data, 4))
 
1612
    return 1;
 
1613
  n_polygons= uint4korr(data);
 
1614
  data+= 4;
 
1615
 
 
1616
  while (n_polygons--)
 
1617
  {
 
1618
    double p_area;
 
1619
    Gis_polygon p;
 
1620
 
 
1621
    data+= WKB_HEADER_SIZE;
 
1622
    p.set_data_ptr(data, (uint32) (m_data_end - data));
 
1623
    if (p.area(&p_area, &data))
 
1624
      return 1;
 
1625
    result+= p_area;
 
1626
  }
 
1627
  *ar= result;
 
1628
  *end_of_data= data;
 
1629
  return 0;
 
1630
}
 
1631
 
 
1632
 
 
1633
int Gis_multi_polygon::centroid(String *result) const
 
1634
{
 
1635
  uint32 n_polygons;
 
1636
  bool first_loop= 1;
 
1637
  Gis_polygon p;
 
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;
 
1641
 
 
1642
  if (no_data(data, 4))
 
1643
    return 1;
 
1644
  n_polygons= uint4korr(data);
 
1645
  data+= 4;
 
1646
 
 
1647
  while (n_polygons--)
 
1648
  {
 
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))
 
1653
      return 1;
 
1654
 
 
1655
    if (!first_loop)
 
1656
    {
 
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;
 
1660
    }
 
1661
    else
 
1662
    {
 
1663
      first_loop= 0;
 
1664
      res_area= cur_area;
 
1665
      res_cx= cur_cx;
 
1666
      res_cy= cur_cy;
 
1667
    }
 
1668
  }
 
1669
 
 
1670
  return create_point(result, res_cx, res_cy);
 
1671
}
 
1672
 
 
1673
const Geometry::Class_info *Gis_multi_polygon::get_class_info() const
 
1674
{
 
1675
  return &multipolygon_class;
 
1676
}
 
1677
 
 
1678
 
 
1679
/************************* GeometryCollection ****************************/
 
1680
 
 
1681
uint32 Gis_geometry_collection::get_data_size() const 
 
1682
{
 
1683
  uint32 n_objects;
 
1684
  const char *data= m_data;
 
1685
  Geometry_buffer buffer;
 
1686
  Geometry *geom;
 
1687
 
 
1688
  if (no_data(data, 4))
 
1689
    return GET_SIZE_ERROR;
 
1690
  n_objects= uint4korr(data);
 
1691
  data+= 4;
 
1692
 
 
1693
  while (n_objects--)
 
1694
  {
 
1695
    uint32 wkb_type,object_size;
 
1696
 
 
1697
    if (no_data(data, WKB_HEADER_SIZE))
 
1698
      return GET_SIZE_ERROR;
 
1699
    wkb_type= uint4korr(data + 1);
 
1700
    data+= WKB_HEADER_SIZE;
 
1701
 
 
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;
 
1707
    data+= object_size;
 
1708
  }
 
1709
  return (uint32) (data - m_data);
 
1710
}
 
1711
 
 
1712
 
 
1713
bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
 
1714
{
 
1715
  uint32 n_objects= 0;
 
1716
  uint32 no_pos= wkb->length();
 
1717
  Geometry_buffer buffer;
 
1718
  Geometry *g;
 
1719
 
 
1720
  if (wkb->reserve(4, 512))
 
1721
    return 1;
 
1722
  wkb->length(wkb->length()+4);                 // Reserve space for points
 
1723
 
 
1724
  for (;;)
 
1725
  {
 
1726
    if (!(g= create_from_wkt(&buffer, trs, wkb)))
 
1727
      return 1;
 
1728
 
 
1729
    if (g->get_class_info()->m_type_id == wkb_geometrycollection)
 
1730
    {
 
1731
      trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
 
1732
      return 1;
 
1733
    }
 
1734
    n_objects++;
 
1735
    if (trs->skip_char(','))                    // Didn't find ','
 
1736
      break;
 
1737
  }
 
1738
 
 
1739
  wkb->write_at_position(no_pos, n_objects);
 
1740
  return 0;
 
1741
}
 
1742
 
 
1743
 
 
1744
uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
 
1745
                                            wkbByteOrder bo, String *res)
 
1746
{
 
1747
  uint32 n_geom;
 
1748
  const char *wkb_orig= wkb;
 
1749
 
 
1750
  if (len < 4)
 
1751
    return 0;
 
1752
  n_geom= wkb_get_uint(wkb, bo);
 
1753
 
 
1754
  if (res->reserve(4, 512))
 
1755
    return 0;
 
1756
  res->q_append(n_geom);
 
1757
  
 
1758
  wkb+= 4;
 
1759
  while (n_geom--)
 
1760
  {
 
1761
    Geometry_buffer buffer;
 
1762
    Geometry *geom;
 
1763
    int g_len;
 
1764
    uint32 wkb_type;
 
1765
 
 
1766
    if (len < WKB_HEADER_SIZE ||
 
1767
        res->reserve(WKB_HEADER_SIZE, 512))
 
1768
      return 0;
 
1769
 
 
1770
    res->q_append((char) wkb_ndr);
 
1771
    wkb_type= wkb_get_uint(wkb+1, (wkbByteOrder) wkb[0]);
 
1772
    res->q_append(wkb_type);
 
1773
 
 
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)))
 
1777
      return 0;
 
1778
    g_len+= WKB_HEADER_SIZE;
 
1779
    wkb+= g_len;
 
1780
    len-= g_len;
 
1781
  }
 
1782
  return (uint) (wkb - wkb_orig);
 
1783
}
 
1784
 
 
1785
 
 
1786
bool Gis_geometry_collection::get_data_as_wkt(String *txt,
 
1787
                                             const char **end) const
 
1788
{
 
1789
  uint32 n_objects;
 
1790
  Geometry_buffer buffer;
 
1791
  Geometry *geom;
 
1792
  const char *data= m_data;
 
1793
 
 
1794
  if (no_data(data, 4))
 
1795
    return 1;
 
1796
  n_objects= uint4korr(data);
 
1797
  data+= 4;
 
1798
 
 
1799
  while (n_objects--)
 
1800
  {
 
1801
    uint32 wkb_type;
 
1802
 
 
1803
    if (no_data(data, WKB_HEADER_SIZE))
 
1804
      return 1;
 
1805
    wkb_type= uint4korr(data + 1);
 
1806
    data+= WKB_HEADER_SIZE;
 
1807
 
 
1808
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
 
1809
      return 1;
 
1810
    geom->set_data_ptr(data, (uint) (m_data_end - data));
 
1811
    if (geom->as_wkt(txt, &data))
 
1812
      return 1;
 
1813
    if (txt->append(STRING_WITH_LEN(","), 512))
 
1814
      return 1;
 
1815
  }
 
1816
  txt->length(txt->length() - 1);
 
1817
  *end= data;
 
1818
  return 0;
 
1819
}
 
1820
 
 
1821
 
 
1822
bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
 
1823
{
 
1824
  uint32 n_objects;
 
1825
  const char *data= m_data;
 
1826
  Geometry_buffer buffer;
 
1827
  Geometry *geom;
 
1828
 
 
1829
  if (no_data(data, 4))
 
1830
    return 1;
 
1831
  n_objects= uint4korr(data);
 
1832
  data+= 4;
 
1833
 
 
1834
  while (n_objects--)
 
1835
  {
 
1836
    uint32 wkb_type;
 
1837
 
 
1838
    if (no_data(data, WKB_HEADER_SIZE))
 
1839
      return 1;
 
1840
    wkb_type= uint4korr(data + 1);
 
1841
    data+= WKB_HEADER_SIZE;
 
1842
 
 
1843
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
 
1844
      return 1;
 
1845
    geom->set_data_ptr(data, (uint32) (m_data_end - data));
 
1846
    if (geom->get_mbr(mbr, &data))
 
1847
      return 1;
 
1848
  }
 
1849
  *end= data;
 
1850
  return 0;
 
1851
}
 
1852
 
 
1853
 
 
1854
int Gis_geometry_collection::num_geometries(uint32 *num) const
 
1855
{
 
1856
  if (no_data(m_data, 4))
 
1857
    return 1;
 
1858
  *num= uint4korr(m_data);
 
1859
  return 0;
 
1860
}
 
1861
 
 
1862
 
 
1863
int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
 
1864
{
 
1865
  uint32 n_objects, wkb_type, length;
 
1866
  const char *data= m_data;
 
1867
  Geometry_buffer buffer;
 
1868
  Geometry *geom;
 
1869
 
 
1870
  if (no_data(data, 4))
 
1871
    return 1;
 
1872
  n_objects= uint4korr(data);
 
1873
  data+= 4;
 
1874
  if (num > n_objects || num < 1)
 
1875
    return 1;
 
1876
 
 
1877
  do
 
1878
  {
 
1879
    if (no_data(data, WKB_HEADER_SIZE))
 
1880
      return 1;
 
1881
    wkb_type= uint4korr(data + 1);
 
1882
    data+= WKB_HEADER_SIZE;
 
1883
 
 
1884
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
 
1885
      return 1;
 
1886
    geom->set_data_ptr(data, (uint) (m_data_end - data));
 
1887
    if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
 
1888
      return 1;
 
1889
    data+= length;
 
1890
  } while (--num);
 
1891
 
 
1892
  /* Copy found object to result */
 
1893
  if (result->reserve(1+4+length))
 
1894
    return 1;
 
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
 
1898
  return 0;
 
1899
}
 
1900
 
 
1901
 
 
1902
/*
 
1903
  Return dimension for object
 
1904
 
 
1905
  SYNOPSIS
 
1906
    dimension()
 
1907
    res_dim             Result dimension
 
1908
    end                 End of object will be stored here. May be 0 for
 
1909
                        simple objects!
 
1910
  RETURN
 
1911
    0   ok
 
1912
    1   error
 
1913
*/
 
1914
 
 
1915
bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
 
1916
{
 
1917
  uint32 n_objects;
 
1918
  const char *data= m_data;
 
1919
  Geometry_buffer buffer;
 
1920
  Geometry *geom;
 
1921
 
 
1922
  if (no_data(data, 4))
 
1923
    return 1;
 
1924
  n_objects= uint4korr(data);
 
1925
  data+= 4;
 
1926
 
 
1927
  *res_dim= 0;
 
1928
  while (n_objects--)
 
1929
  {
 
1930
    uint32 wkb_type, length, dim;
 
1931
    const char *end_data;
 
1932
 
 
1933
    if (no_data(data, WKB_HEADER_SIZE))
 
1934
      return 1;
 
1935
    wkb_type= uint4korr(data + 1);
 
1936
    data+= WKB_HEADER_SIZE;
 
1937
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
 
1938
      return 1;
 
1939
    geom->set_data_ptr(data, (uint32) (m_data_end - data));
 
1940
    if (geom->dimension(&dim, &end_data))
 
1941
      return 1;
 
1942
    set_if_bigger(*res_dim, dim);
 
1943
    if (end_data)                               // Complex object
 
1944
      data= end_data;
 
1945
    else if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
 
1946
      return 1;
 
1947
    else
 
1948
      data+= length;
 
1949
  }
 
1950
  *end= data;
 
1951
  return 0;
 
1952
}
 
1953
 
 
1954
const Geometry::Class_info *Gis_geometry_collection::get_class_info() const
 
1955
{
 
1956
  return &geometrycollection_class;
 
1957
}
 
1958
 
 
1959
#endif /*HAVE_SPATIAL*/