spatial.cc 41.7 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6
/* Copyright (C) 2004 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
unknown's avatar
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
unknown's avatar
unknown committed
12

unknown's avatar
unknown committed
13 14 15 16 17
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "mysql_priv.h"
18 19 20

#ifdef HAVE_SPATIAL

unknown's avatar
unknown committed
21 22
#define MAX_DIGITS_IN_DOUBLE 16

unknown's avatar
unknown committed
23
/***************************** Gis_class_info *******************************/
unknown's avatar
unknown committed
24

25
Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]=
26 27
{
  NULL, NULL, NULL, NULL, NULL, NULL, NULL
unknown's avatar
unknown committed
28 29
};

30
static Geometry::Class_info **ci_collection_end=
unknown's avatar
unknown committed
31
                                Geometry::ci_collection+Geometry::wkb_end + 1;
unknown's avatar
unknown committed
32

33 34 35 36 37 38
Geometry::Class_info::Class_info(const char *name, int type_id,
					 void(*create_func)(void *)):
  m_name(name, strlen(name)), m_type_id(type_id), m_create_func(create_func)
{
  ci_collection[type_id]= this;
}
unknown's avatar
unknown committed
39

40 41 42 43
static void create_point(void *buffer)
{
  new(buffer) Gis_point;
}
unknown's avatar
unknown committed
44

45
static void create_linestring(void *buffer)
unknown's avatar
unknown committed
46
{
47 48 49 50 51 52 53 54 55 56 57
  new(buffer) Gis_line_string;
}

static void create_polygon(void *buffer)
{
  new(buffer) Gis_polygon;
}

static void create_multipoint(void *buffer)
{
  new(buffer) Gis_multi_point;
unknown's avatar
unknown committed
58
}
unknown's avatar
unknown committed
59

60
static void create_multipolygon(void *buffer)
unknown's avatar
unknown committed
61
{
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
  new(buffer) Gis_multi_polygon;
}

static void create_multilinestring(void *buffer)
{
  new(buffer) Gis_multi_line_string;
}

static void create_geometrycollection(void *buffer)
{
  new(buffer) Gis_geometry_collection;
}



static Geometry::Class_info point_class("POINT",
					Geometry::wkb_point, create_point);

static Geometry::Class_info linestring_class("LINESTRING",
					     Geometry::wkb_linestring,
					     create_linestring);
static Geometry::Class_info polygon_class("POLYGON",
					      Geometry::wkb_polygon,
					      create_polygon);
static Geometry::Class_info multipoint_class("MULTIPOINT",
						 Geometry::wkb_multipoint,
						 create_multipoint);
static Geometry::Class_info 
multilinestring_class("MULTILINESTRING",
		      Geometry::wkb_multilinestring, create_multilinestring);
static Geometry::Class_info multipolygon_class("MULTIPOLYGON",
						   Geometry::wkb_multipolygon,
						   create_multipolygon);
static Geometry::Class_info 
geometrycollection_class("GEOMETRYCOLLECTION",Geometry::wkb_geometrycollection,
			 create_geometrycollection);

99 100 101 102 103 104
static void get_point(double *x, double *y, const char *data)
{
  float8get(*x, data);
  float8get(*y, data + SIZEOF_STORED_DOUBLE);
}

105 106 107 108 109 110
/***************************** Geometry *******************************/

Geometry::Class_info *Geometry::find_class(const char *name, uint32 len)
{
  for (Class_info **cur_rt= ci_collection;
       cur_rt < ci_collection_end; cur_rt++)
unknown's avatar
unknown committed
111
  {
112 113
    if (*cur_rt &&
	((*cur_rt)->m_name.length == len) &&
unknown's avatar
unknown committed
114
	(my_strnncoll(&my_charset_latin1,
115
		      (const uchar*) (*cur_rt)->m_name.str, len,
unknown's avatar
unknown committed
116
		      (const uchar*) name, len) == 0))
117
      return *cur_rt;
unknown's avatar
unknown committed
118
  }
unknown's avatar
unknown committed
119
  return 0;
unknown's avatar
unknown committed
120 121
}

122 123 124

Geometry *Geometry::construct(Geometry_buffer *buffer,
                              const char *data, uint32 data_len)
unknown's avatar
unknown committed
125 126
{
  uint32 geom_type;
127
  Geometry *result;
128
  char byte_order;
unknown's avatar
unknown committed
129

unknown's avatar
unknown committed
130
  if (data_len < SRID_SIZE + WKB_HEADER_SIZE)   // < 4 + (1 + 4)
131
    return NULL;
132 133
  byte_order= data[SRID_SIZE];
  geom_type= uint4korr(data + SRID_SIZE + 1);
134 135
  if (!(result= create_by_typeid(buffer, (int) geom_type)))
    return NULL;
unknown's avatar
unknown committed
136 137
  result->m_data= data+ SRID_SIZE + WKB_HEADER_SIZE;
  result->m_data_end= data + data_len;
138
  return result;
unknown's avatar
unknown committed
139 140
}

unknown's avatar
unknown committed
141

142 143 144
Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
				    Gis_read_stream *trs, String *wkt,
				    bool init_stream)
unknown's avatar
unknown committed
145
{
unknown's avatar
unknown committed
146
  LEX_STRING name;
147
  Class_info *ci;
unknown's avatar
unknown committed
148 149

  if (trs->get_next_word(&name))
unknown's avatar
unknown committed
150 151
  {
    trs->set_error_msg("Geometry name expected");
152
    return NULL;
unknown's avatar
unknown committed
153
  }
154
  if (!(ci= find_class(name.str, name.length)) ||
unknown's avatar
unknown committed
155
      wkt->reserve(1 + 4, 512))
156 157 158 159 160 161
    return NULL;
  (*ci->m_create_func)((void *)buffer);
  Geometry *result= (Geometry *)buffer;
  
  wkt->q_append((char) wkb_ndr);
  wkt->q_append((uint32) result->get_class_info()->m_type_id);
unknown's avatar
unknown committed
162
  if (trs->check_next_symbol('(') ||
163
      result->init_from_wkt(trs, wkt) ||
unknown's avatar
unknown committed
164
      trs->check_next_symbol(')'))
165
    return NULL;
unknown's avatar
unknown committed
166 167
  if (init_stream)  
  {
168
    result->set_data_ptr(wkt->ptr(), wkt->length());
169
    result->shift_wkb_header();
unknown's avatar
unknown committed
170
  }
171
  return result;
unknown's avatar
unknown committed
172 173
}

unknown's avatar
unknown committed
174

175 176 177 178
static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
{
  double res;
  if (bo != Geometry::wkb_xdr)
unknown's avatar
unknown committed
179
  {
180
    float8get(res, ptr);
unknown's avatar
unknown committed
181
  }
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
  else
  {
    char inv_array[8];
    inv_array[0]= ptr[7];
    inv_array[1]= ptr[6];
    inv_array[2]= ptr[5];
    inv_array[3]= ptr[4];
    inv_array[4]= ptr[3];
    inv_array[5]= ptr[2];
    inv_array[6]= ptr[1];
    inv_array[7]= ptr[0];
    float8get(res, inv_array);
  }
  return res;
}


static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
{
  if (bo != Geometry::wkb_xdr)
    return uint4korr(ptr);
  /* else */
  {
    char inv_array[4];
    inv_array[0]= ptr[3];
    inv_array[1]= ptr[2];
    inv_array[2]= ptr[1];
    inv_array[3]= ptr[0];
    return uint4korr(inv_array);
  }
}


int Geometry::create_from_wkb(Geometry_buffer *buffer,
                              const char *wkb, uint32 len, String *res)
{
  uint32 geom_type;
  Geometry *geom;

  if (len < WKB_HEADER_SIZE)
    return 1;
  geom_type= wkb_get_uint(wkb+1, (wkbByteOrder)wkb[0]);
  if (!(geom= create_by_typeid(buffer, (int) geom_type)) ||
      res->reserve(WKB_HEADER_SIZE, 512))
    return 1;

unknown's avatar
unknown committed
228
  res->q_append((char) wkb_ndr);
229 230
  res->q_append(geom_type);
  return geom->init_from_wkb(wkb+WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
unknown's avatar
unknown committed
231
                             (wkbByteOrder) wkb[0], res);
232 233 234
}


unknown's avatar
unknown committed
235
bool Geometry::envelope(String *result) const
unknown's avatar
unknown committed
236 237
{
  MBR mbr;
unknown's avatar
unknown committed
238
  const char *end;
unknown's avatar
unknown committed
239

unknown's avatar
unknown committed
240
  if (get_mbr(&mbr, &end) || result->reserve(1+4*3+SIZEOF_STORED_DOUBLE*10))
unknown's avatar
unknown committed
241 242
    return 1;

243 244
  result->q_append((char) wkb_ndr);
  result->q_append((uint32) wkb_polygon);
unknown's avatar
unknown committed
245 246
  result->q_append((uint32) 1);
  result->q_append((uint32) 5);
unknown's avatar
unknown committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260
  result->q_append(mbr.xmin);
  result->q_append(mbr.ymin);
  result->q_append(mbr.xmax);
  result->q_append(mbr.ymin);
  result->q_append(mbr.xmax);
  result->q_append(mbr.ymax);
  result->q_append(mbr.xmin);
  result->q_append(mbr.ymax);
  result->q_append(mbr.xmin);
  result->q_append(mbr.ymin);

  return 0;
}

unknown's avatar
unknown committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274

/*
  Create a point from data.

  SYNPOSIS
    create_point()
    result		Put result here
    data		Data for point is here.

  RETURN
    0	ok
    1	Can't reallocate 'result'
*/

275
bool Geometry::create_point(String *result, const char *data) const
unknown's avatar
unknown committed
276 277 278 279
{
  if (no_data(data, SIZEOF_STORED_DOUBLE * 2) ||
      result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
    return 1;
280 281
  result->q_append((char) wkb_ndr);
  result->q_append((uint32) wkb_point);
unknown's avatar
unknown committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
  /* Copy two double in same format */
  result->q_append(data, SIZEOF_STORED_DOUBLE*2);
  return 0;
}

/*
  Create a point from coordinates.

  SYNPOSIS
    create_point()
    result		Put result here
    x			x coordinate for point
    y			y coordinate for point

  RETURN
    0	ok
    1	Can't reallocate 'result'
*/

301
bool Geometry::create_point(String *result, double x, double y) const
unknown's avatar
unknown committed
302 303 304 305
{
  if (result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
    return 1;

306 307
  result->q_append((char) wkb_ndr);
  result->q_append((uint32) wkb_point);
unknown's avatar
unknown committed
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
  result->q_append(x);
  result->q_append(y);
  return 0;
}

/*
  Append N points from packed format to text

  SYNOPSIS
    append_points()
    txt			Append points here
    n_points		Number of points
    data		Packed data
    offset		Offset between points

  RETURN
    # end of data
*/

const char *Geometry::append_points(String *txt, uint32 n_points,
328
				    const char *data, uint32 offset) const
unknown's avatar
unknown committed
329 330 331
{			     
  while (n_points--)
  {
332
    double x,y;
unknown's avatar
unknown committed
333
    data+= offset;
334
    get_point(&x, &y, data);
unknown's avatar
unknown committed
335
    data+= SIZEOF_STORED_DOUBLE * 2;
336 337 338
    txt->qs_append(x);
    txt->qs_append(' ');
    txt->qs_append(y);
unknown's avatar
unknown committed
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
    txt->qs_append(',');
  }
  return data;
}


/*
  Get most bounding rectangle (mbr) for X points

  SYNOPSIS
    get_mbr_for_points()
    mbr			MBR (store rectangle here)
    points		Number of points
    data		Packed data
    offset		Offset between points

  RETURN
    0	Wrong data
    #	end of data
*/

const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
					 uint offset) const
{
  uint32 points;
  /* read number of points */
  if (no_data(data, 4))
    return 0;
  points= uint4korr(data);
  data+= 4;

  if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points))
    return 0;

  /* Calculate MBR for points */
  while (points--)
  {
    data+= offset;
    mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE);
    data+= SIZEOF_STORED_DOUBLE * 2;
  }
  return data;
}


unknown's avatar
unknown committed
384 385
/***************************** Point *******************************/

unknown's avatar
unknown committed
386
uint32 Gis_point::get_data_size() const
unknown's avatar
unknown committed
387 388 389 390
{
  return POINT_DATA_SIZE;
}

unknown's avatar
unknown committed
391 392

bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
unknown's avatar
unknown committed
393 394
{
  double x, y;
unknown's avatar
unknown committed
395 396
  if (trs->get_next_number(&x) || trs->get_next_number(&y) ||
      wkb->reserve(SIZEOF_STORED_DOUBLE * 2))
unknown's avatar
unknown committed
397 398 399 400 401 402
    return 1;
  wkb->q_append(x);
  wkb->q_append(y);
  return 0;
}

unknown's avatar
unknown committed
403

404 405 406 407 408 409 410 411 412 413 414 415 416 417
uint Gis_point::init_from_wkb(const char *wkb, uint len,
                              wkbByteOrder bo, String *res)
{
  double x, y;
  if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE))
    return 0;
  x= wkb_get_double(wkb, bo);
  y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
  res->q_append(x);
  res->q_append(y);
  return POINT_DATA_SIZE;
}


418
bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
unknown's avatar
unknown committed
419 420 421 422 423 424 425 426 427
{
  double x, y;
  if (get_xy(&x, &y))
    return 1;
  if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
    return 1;
  txt->qs_append(x);
  txt->qs_append(' ');
  txt->qs_append(y);
unknown's avatar
unknown committed
428
  *end= m_data+ POINT_DATA_SIZE;
unknown's avatar
unknown committed
429 430 431
  return 0;
}

unknown's avatar
unknown committed
432

433
bool Gis_point::get_mbr(MBR *mbr, const char **end) const
unknown's avatar
unknown committed
434 435 436 437 438
{
  double x, y;
  if (get_xy(&x, &y))
    return 1;
  mbr->add_xy(x, y);
unknown's avatar
unknown committed
439
  *end= m_data+ POINT_DATA_SIZE;
unknown's avatar
unknown committed
440 441 442
  return 0;
}

443 444 445 446 447
const Geometry::Class_info *Gis_point::get_class_info() const
{
  return &point_class;
}

unknown's avatar
unknown committed
448

unknown's avatar
unknown committed
449 450
/***************************** LineString *******************************/

unknown's avatar
unknown committed
451
uint32 Gis_line_string::get_data_size() const 
unknown's avatar
unknown committed
452
{
unknown's avatar
unknown committed
453 454 455
  if (no_data(m_data, 4))
    return GET_SIZE_ERROR;
  return 4 + uint4korr(m_data) * POINT_DATA_SIZE;
unknown's avatar
unknown committed
456 457
}

unknown's avatar
unknown committed
458 459

bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
unknown's avatar
unknown committed
460
{
unknown's avatar
unknown committed
461 462 463
  uint32 n_points= 0;
  uint32 np_pos= wkb->length();
  Gis_point p;
unknown's avatar
unknown committed
464 465 466

  if (wkb->reserve(4, 512))
    return 1;
unknown's avatar
unknown committed
467
  wkb->length(wkb->length()+4);			// Reserve space for points  
unknown's avatar
unknown committed
468 469 470

  for (;;)
  {
471
    if (p.init_from_wkt(trs, wkb))
unknown's avatar
unknown committed
472
      return 1;
unknown's avatar
unknown committed
473 474 475
    n_points++;
    if (trs->skip_char(','))			// Didn't find ','
      break;
unknown's avatar
unknown committed
476
  }
unknown's avatar
unknown committed
477
  if (n_points < 1)
unknown's avatar
unknown committed
478 479 480 481
  {
    trs->set_error_msg("Too few points in LINESTRING");
    return 1;
  }
unknown's avatar
unknown committed
482
  wkb->write_at_position(np_pos, n_points);
unknown's avatar
unknown committed
483 484 485
  return 0;
}

unknown's avatar
unknown committed
486

487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
                                    wkbByteOrder bo, String *res)
{
  uint32 n_points, proper_length;
  const char *wkb_end;
  Gis_point p;

  if (len < 4)
    return 0;
  n_points= wkb_get_uint(wkb, bo);
  proper_length= 4 + n_points * POINT_DATA_SIZE;

  if (len < proper_length || res->reserve(proper_length))
    return 0;

  res->q_append(n_points);
  wkb_end= wkb + proper_length;
  for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE)
  {
    if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res))
      return 0;
  }

  return proper_length;
}


514
bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
unknown's avatar
unknown committed
515 516
{
  uint32 n_points;
unknown's avatar
unknown committed
517
  const char *data= m_data;
unknown's avatar
unknown committed
518 519 520

  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
521
  n_points= uint4korr(data);
unknown's avatar
unknown committed
522 523
  data += 4;

unknown's avatar
unknown committed
524 525 526
  if (n_points < 1 ||
      no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) ||
      txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
unknown's avatar
unknown committed
527 528
    return 1;

unknown's avatar
unknown committed
529
  while (n_points--)
unknown's avatar
unknown committed
530 531
  {
    double x, y;
532
    get_point(&x, &y, data);
unknown's avatar
unknown committed
533
    data+= SIZEOF_STORED_DOUBLE * 2;
unknown's avatar
unknown committed
534 535 536 537 538
    txt->qs_append(x);
    txt->qs_append(' ');
    txt->qs_append(y);
    txt->qs_append(',');
  }
unknown's avatar
unknown committed
539 540
  txt->length(txt->length() - 1);		// Remove end ','
  *end= data;
unknown's avatar
unknown committed
541 542 543 544
  return 0;
}


unknown's avatar
unknown committed
545 546 547
bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
{
  return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0;
unknown's avatar
unknown committed
548 549
}

unknown's avatar
unknown committed
550

551
int Gis_line_string::length(double *len) const
unknown's avatar
unknown committed
552 553 554
{
  uint32 n_points;
  double prev_x, prev_y;
unknown's avatar
unknown committed
555
  const char *data= m_data;
unknown's avatar
unknown committed
556

unknown's avatar
unknown committed
557
  *len= 0;					// In case of errors
unknown's avatar
unknown committed
558 559
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
560 561 562
  n_points= uint4korr(data);
  data+= 4;
  if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
unknown's avatar
unknown committed
563 564
    return 1;

565
  get_point(&prev_x, &prev_y, data);
unknown's avatar
unknown committed
566
  data+= SIZEOF_STORED_DOUBLE*2;
unknown's avatar
unknown committed
567

unknown's avatar
unknown committed
568
  while (--n_points)
unknown's avatar
unknown committed
569 570
  {
    double x, y;
571
    get_point(&x, &y, data);
unknown's avatar
unknown committed
572 573 574 575
    data+= SIZEOF_STORED_DOUBLE * 2;
    *len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
    prev_x= x;
    prev_y= y;
unknown's avatar
unknown committed
576 577 578 579 580
  }
  return 0;
}


581
int Gis_line_string::is_closed(int *closed) const
unknown's avatar
unknown committed
582 583 584
{
  uint32 n_points;
  double x1, y1, x2, y2;
unknown's avatar
unknown committed
585
  const char *data= m_data;
unknown's avatar
unknown committed
586 587 588

  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
589
  n_points= uint4korr(data);
unknown's avatar
unknown committed
590 591 592 593 594
  if (n_points == 1)
  {
    *closed=1;
    return 0;
  }
unknown's avatar
unknown committed
595 596
  data+= 4;
  if (no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
unknown's avatar
unknown committed
597
    return 1;
unknown's avatar
unknown committed
598 599

  /* Get first point */
600
  get_point(&x1, &y1, data);
unknown's avatar
unknown committed
601

unknown's avatar
unknown committed
602 603
  /* get last point */
  data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE;
604
  get_point(&x2, &y2, data);
unknown's avatar
unknown committed
605

unknown's avatar
unknown committed
606
  *closed= (x1==x2) && (y1==y2);
unknown's avatar
unknown committed
607 608 609
  return 0;
}

unknown's avatar
unknown committed
610

611
int Gis_line_string::num_points(uint32 *n_points) const
unknown's avatar
unknown committed
612
{
unknown's avatar
unknown committed
613
  *n_points= uint4korr(m_data);
unknown's avatar
unknown committed
614 615 616 617
  return 0;
}


618
int Gis_line_string::start_point(String *result) const
unknown's avatar
unknown committed
619 620 621
{
  /* +4 is for skipping over number of points */
  return create_point(result, m_data + 4);
unknown's avatar
unknown committed
622 623
}

unknown's avatar
unknown committed
624

625
int Gis_line_string::end_point(String *result) const
unknown's avatar
unknown committed
626 627
{
  uint32 n_points;
unknown's avatar
unknown committed
628
  if (no_data(m_data, 4))
unknown's avatar
unknown committed
629
    return 1;
unknown's avatar
unknown committed
630 631
  n_points= uint4korr(m_data);
  return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE);
unknown's avatar
unknown committed
632 633 634
}


635
int Gis_line_string::point_n(uint32 num, String *result) const
unknown's avatar
unknown committed
636 637
{
  uint32 n_points;
unknown's avatar
unknown committed
638
  if (no_data(m_data, 4))
unknown's avatar
unknown committed
639
    return 1;
unknown's avatar
unknown committed
640
  n_points= uint4korr(m_data);
641
  if ((uint32) (num - 1) >= n_points) // means (num > n_points || num < 1)
unknown's avatar
unknown committed
642 643
    return 1;

unknown's avatar
unknown committed
644
  return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE);
unknown's avatar
unknown committed
645 646
}

647 648 649 650 651
const Geometry::Class_info *Gis_line_string::get_class_info() const
{
  return &linestring_class;
}

unknown's avatar
unknown committed
652

unknown's avatar
unknown committed
653 654
/***************************** Polygon *******************************/

unknown's avatar
unknown committed
655
uint32 Gis_polygon::get_data_size() const 
unknown's avatar
unknown committed
656
{
unknown's avatar
unknown committed
657 658 659
  uint32 n_linear_rings;
  const char *data= m_data;

unknown's avatar
unknown committed
660
  if (no_data(data, 4))
unknown's avatar
unknown committed
661 662 663
    return GET_SIZE_ERROR;
  n_linear_rings= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
664

unknown's avatar
unknown committed
665
  while (n_linear_rings--)
unknown's avatar
unknown committed
666 667
  {
    if (no_data(data, 4))
unknown's avatar
unknown committed
668 669
      return GET_SIZE_ERROR;
    data+= 4 + uint4korr(data)*POINT_DATA_SIZE;
unknown's avatar
unknown committed
670
  }
unknown's avatar
unknown committed
671
  return (uint32) (data - m_data);
unknown's avatar
unknown committed
672 673
}

unknown's avatar
unknown committed
674 675

bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
unknown's avatar
unknown committed
676
{
unknown's avatar
unknown committed
677 678 679
  uint32 n_linear_rings= 0;
  uint32 lr_pos= wkb->length();
  int closed;
unknown's avatar
unknown committed
680 681 682

  if (wkb->reserve(4, 512))
    return 1;
unknown's avatar
unknown committed
683
  wkb->length(wkb->length()+4);			// Reserve space for points
unknown's avatar
unknown committed
684 685
  for (;;)  
  {
unknown's avatar
unknown committed
686 687 688 689 690
    Gis_line_string ls;
    uint32 ls_pos=wkb->length();
    if (trs->check_next_symbol('(') ||
	ls.init_from_wkt(trs, wkb) ||
	trs->check_next_symbol(')'))
unknown's avatar
unknown committed
691
      return 1;
unknown's avatar
unknown committed
692

unknown's avatar
unknown committed
693
    ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
unknown's avatar
unknown committed
694
    if (ls.is_closed(&closed) || !closed)
unknown's avatar
unknown committed
695 696 697 698
    {
      trs->set_error_msg("POLYGON's linear ring isn't closed");
      return 1;
    }
unknown's avatar
unknown committed
699 700
    n_linear_rings++;
    if (trs->skip_char(','))			// Didn't find ','
unknown's avatar
unknown committed
701 702
      break;
  }
unknown's avatar
unknown committed
703
  wkb->write_at_position(lr_pos, n_linear_rings);
unknown's avatar
unknown committed
704 705 706
  return 0;
}

unknown's avatar
unknown committed
707

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
                                String *res)
{
  uint32 n_linear_rings;
  const char *wkb_orig= wkb;

  if (len < 4)
    return 0;

  n_linear_rings= wkb_get_uint(wkb, bo);
  if (res->reserve(4, 512))
    return 0;
  wkb+= 4;
  len-= 4;
  res->q_append(n_linear_rings);

  while (n_linear_rings--)
  {
    Gis_line_string ls;
    uint32 ls_pos= res->length();
    int ls_len;
    int closed;

    if (!(ls_len= ls.init_from_wkb(wkb, len, bo, res)))
      return 0;

unknown's avatar
unknown committed
734
    ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos);
735 736 737 738 739 740

    if (ls.is_closed(&closed) || !closed)
      return 0;
    wkb+= ls_len;
  }

unknown's avatar
unknown committed
741
  return (uint) (wkb - wkb_orig);
742 743 744
}


745
bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
unknown's avatar
unknown committed
746 747
{
  uint32 n_linear_rings;
748
  const char *data= m_data;
unknown's avatar
unknown committed
749 750 751 752

  if (no_data(data, 4))
    return 1;

753 754
  n_linear_rings= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
755

unknown's avatar
unknown committed
756
  while (n_linear_rings--)
unknown's avatar
unknown committed
757
  {
unknown's avatar
unknown committed
758
    uint32 n_points;
unknown's avatar
unknown committed
759
    if (no_data(data, 4))
unknown's avatar
unknown committed
760
      return 1;
unknown's avatar
unknown committed
761
    n_points= uint4korr(data);
762
    data+= 4;
unknown's avatar
unknown committed
763 764
    if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) ||
	txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
unknown's avatar
unknown committed
765 766
      return 1;
    txt->qs_append('(');
unknown's avatar
unknown committed
767 768
    data= append_points(txt, n_points, data, 0);
    (*txt) [txt->length() - 1]= ')';		// Replace end ','
unknown's avatar
unknown committed
769 770
    txt->qs_append(',');
  }
unknown's avatar
unknown committed
771 772
  txt->length(txt->length() - 1);		// Remove end ','
  *end= data;
unknown's avatar
unknown committed
773 774 775
  return 0;
}

unknown's avatar
unknown committed
776 777

bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const
unknown's avatar
unknown committed
778 779
{
  uint32 n_linear_rings;
unknown's avatar
unknown committed
780
  const char *data= m_data;
unknown's avatar
unknown committed
781 782 783

  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
784 785 786 787
  n_linear_rings= uint4korr(data);
  data+= 4;

  while (n_linear_rings--)
unknown's avatar
unknown committed
788
  {
unknown's avatar
unknown committed
789
    if (!(data= get_mbr_for_points(mbr, data, 0)))
unknown's avatar
unknown committed
790 791
      return 1;
  }
unknown's avatar
unknown committed
792
  *end= data;
unknown's avatar
unknown committed
793 794 795
  return 0;
}

unknown's avatar
unknown committed
796

797
int Gis_polygon::area(double *ar, const char **end_of_data) const
unknown's avatar
unknown committed
798 799
{
  uint32 n_linear_rings;
unknown's avatar
unknown committed
800 801
  double result= -1.0;
  const char *data= m_data;
unknown's avatar
unknown committed
802 803 804

  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
805 806 807 808
  n_linear_rings= uint4korr(data);
  data+= 4;

  while (n_linear_rings--)
unknown's avatar
unknown committed
809 810
  {
    double prev_x, prev_y;
unknown's avatar
unknown committed
811 812 813
    double lr_area= 0;
    uint32 n_points;

unknown's avatar
unknown committed
814 815
    if (no_data(data, 4))
      return 1;
unknown's avatar
unknown committed
816 817
    n_points= uint4korr(data);
    if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
unknown's avatar
unknown committed
818
      return 1;
819
    get_point(&prev_x, &prev_y, data+4);
unknown's avatar
unknown committed
820
    data+= (4+SIZEOF_STORED_DOUBLE*2);
unknown's avatar
unknown committed
821

unknown's avatar
unknown committed
822
    while (--n_points)				// One point is already read
unknown's avatar
unknown committed
823 824
    {
      double x, y;
825
      get_point(&x, &y, data);
unknown's avatar
unknown committed
826 827 828 829 830
      data+= (SIZEOF_STORED_DOUBLE*2);
      /* QQ: Is the following prev_x+x right ? */
      lr_area+= (prev_x + x)* (prev_y - y);
      prev_x= x;
      prev_y= y;
unknown's avatar
unknown committed
831
    }
unknown's avatar
unknown committed
832 833 834 835 836
    lr_area= fabs(lr_area)/2;
    if (result == -1.0)
      result= lr_area;
    else
      result-= lr_area;
unknown's avatar
unknown committed
837
  }
unknown's avatar
unknown committed
838 839
  *ar= fabs(result);
  *end_of_data= data;
unknown's avatar
unknown committed
840 841 842 843
  return 0;
}


844
int Gis_polygon::exterior_ring(String *result) const
unknown's avatar
unknown committed
845
{
unknown's avatar
unknown committed
846 847
  uint32 n_points, length;
  const char *data= m_data + 4; // skip n_linerings
unknown's avatar
unknown committed
848 849 850

  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
851 852 853 854
  n_points= uint4korr(data);
  data+= 4;
  length= n_points * POINT_DATA_SIZE;
  if (no_data(data, length) || result->reserve(1+4+4+ length))
unknown's avatar
unknown committed
855 856
    return 1;

857 858
  result->q_append((char) wkb_ndr);
  result->q_append((uint32) wkb_linestring);
unknown's avatar
unknown committed
859 860 861 862 863
  result->q_append(n_points);
  result->q_append(data, n_points * POINT_DATA_SIZE); 
  return 0;
}

unknown's avatar
unknown committed
864

865
int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const
unknown's avatar
unknown committed
866
{
unknown's avatar
unknown committed
867
  if (no_data(m_data, 4))
unknown's avatar
unknown committed
868
    return 1;
unknown's avatar
unknown committed
869
  *n_int_rings= uint4korr(m_data)-1;
unknown's avatar
unknown committed
870 871 872
  return 0;
}

unknown's avatar
unknown committed
873

874
int Gis_polygon::interior_ring_n(uint32 num, String *result) const
unknown's avatar
unknown committed
875
{
unknown's avatar
unknown committed
876
  const char *data= m_data;
unknown's avatar
unknown committed
877 878
  uint32 n_linear_rings;
  uint32 n_points;
unknown's avatar
unknown committed
879
  uint32 points_size;
unknown's avatar
unknown committed
880 881 882

  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
883 884
  n_linear_rings= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
885

unknown's avatar
unknown committed
886 887
  if (num >= n_linear_rings || num < 1)
    return 1;
unknown's avatar
unknown committed
888

unknown's avatar
unknown committed
889
  while (num--)
unknown's avatar
unknown committed
890 891 892
  {
    if (no_data(data, 4))
      return 1;
unknown's avatar
unknown committed
893
    data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
unknown's avatar
unknown committed
894 895 896
  }
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
897 898 899 900
  n_points= uint4korr(data);
  points_size= n_points * POINT_DATA_SIZE;
  data+= 4;
  if (no_data(data, points_size) || result->reserve(1+4+4+ points_size))
unknown's avatar
unknown committed
901 902
    return 1;

903 904
  result->q_append((char) wkb_ndr);
  result->q_append((uint32) wkb_linestring);
unknown's avatar
unknown committed
905 906 907 908 909 910
  result->q_append(n_points);
  result->q_append(data, points_size); 

  return 0;
}

unknown's avatar
unknown committed
911

912
int Gis_polygon::centroid_xy(double *x, double *y) const
unknown's avatar
unknown committed
913 914
{
  uint32 n_linear_rings;
915 916
  double res_area;
  double res_cx, res_cy;
unknown's avatar
unknown committed
917 918
  const char *data= m_data;
  bool first_loop= 1;
919 920 921
  LINT_INIT(res_area);
  LINT_INIT(res_cx);
  LINT_INIT(res_cy);
unknown's avatar
unknown committed
922 923 924

  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
925 926
  n_linear_rings= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
927

unknown's avatar
unknown committed
928
  while (n_linear_rings--)
unknown's avatar
unknown committed
929
  {
unknown's avatar
unknown committed
930
    uint32 n_points, org_n_points;
unknown's avatar
unknown committed
931
    double prev_x, prev_y;
unknown's avatar
unknown committed
932 933 934
    double cur_area= 0;
    double cur_cx= 0;
    double cur_cy= 0;
unknown's avatar
unknown committed
935

unknown's avatar
unknown committed
936 937 938 939 940
    if (no_data(data, 4))
      return 1;
    org_n_points= n_points= uint4korr(data);
    data+= 4;
    if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
unknown's avatar
unknown committed
941
      return 1;
942
    get_point(&prev_x, &prev_y, data);
unknown's avatar
unknown committed
943
    data+= (SIZEOF_STORED_DOUBLE*2);
unknown's avatar
unknown committed
944

unknown's avatar
unknown committed
945
    while (--n_points)				// One point is already read
unknown's avatar
unknown committed
946 947
    {
      double x, y;
948
      get_point(&x, &y, data);
unknown's avatar
unknown committed
949 950 951 952 953 954 955
      data+= (SIZEOF_STORED_DOUBLE*2);
      /* QQ: Is the following prev_x+x right ? */
      cur_area+= (prev_x + x) * (prev_y - y);
      cur_cx+= x;
      cur_cy+= y;
      prev_x= x;
      prev_y= y;
unknown's avatar
unknown committed
956
    }
unknown's avatar
unknown committed
957 958 959
    cur_area= fabs(cur_area) / 2;
    cur_cx= cur_cx / (org_n_points - 1);
    cur_cy= cur_cy / (org_n_points - 1);
960

unknown's avatar
unknown committed
961
    if (!first_loop)
unknown's avatar
unknown committed
962
    {
963
      double d_area= fabs(res_area - cur_area);
unknown's avatar
unknown committed
964 965
      res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area;
      res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area;
unknown's avatar
unknown committed
966 967 968
    }
    else
    {
unknown's avatar
unknown committed
969 970 971 972
      first_loop= 0;
      res_area= cur_area;
      res_cx= cur_cx;
      res_cy= cur_cy;
unknown's avatar
unknown committed
973 974 975
    }
  }

unknown's avatar
unknown committed
976 977
  *x= res_cx;
  *y= res_cy;
unknown's avatar
unknown committed
978 979 980
  return 0;
}

unknown's avatar
unknown committed
981

982
int Gis_polygon::centroid(String *result) const
unknown's avatar
unknown committed
983 984
{
  double x, y;
unknown's avatar
unknown committed
985
  if (centroid_xy(&x, &y))
unknown's avatar
unknown committed
986
    return 1;
unknown's avatar
unknown committed
987
  return create_point(result, x, y);
unknown's avatar
unknown committed
988 989
}

990 991 992 993 994
const Geometry::Class_info *Gis_polygon::get_class_info() const
{
  return &polygon_class;
}

unknown's avatar
unknown committed
995 996 997

/***************************** MultiPoint *******************************/

unknown's avatar
unknown committed
998
uint32 Gis_multi_point::get_data_size() const 
unknown's avatar
unknown committed
999
{
unknown's avatar
unknown committed
1000 1001
  if (no_data(m_data, 4))
    return GET_SIZE_ERROR;
unknown's avatar
unknown committed
1002 1003 1004
  return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE);
}

unknown's avatar
unknown committed
1005 1006

bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
unknown's avatar
unknown committed
1007
{
unknown's avatar
unknown committed
1008 1009 1010
  uint32 n_points= 0;
  uint32 np_pos= wkb->length();
  Gis_point p;
unknown's avatar
unknown committed
1011 1012 1013

  if (wkb->reserve(4, 512))
    return 1;
unknown's avatar
unknown committed
1014
  wkb->length(wkb->length()+4);			// Reserve space for points
unknown's avatar
unknown committed
1015 1016 1017 1018 1019

  for (;;)
  {
    if (wkb->reserve(1+4, 512))
      return 1;
1020 1021
    wkb->q_append((char) wkb_ndr);
    wkb->q_append((uint32) wkb_point);
1022
    if (p.init_from_wkt(trs, wkb))
unknown's avatar
unknown committed
1023
      return 1;
unknown's avatar
unknown committed
1024 1025
    n_points++;
    if (trs->skip_char(','))			// Didn't find ','
unknown's avatar
unknown committed
1026 1027
      break;
  }
unknown's avatar
unknown committed
1028
  wkb->write_at_position(np_pos, n_points);	// Store number of found points
unknown's avatar
unknown committed
1029 1030 1031
  return 0;
}

unknown's avatar
unknown committed
1032

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
                                    String *res)
{
  uint32 n_points;
  uint proper_size;
  Gis_point p;
  const char *wkb_end;

  if (len < 4)
    return 0;
  n_points= wkb_get_uint(wkb, bo);
  proper_size= 4 + n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
 
  if (len < proper_size || res->reserve(proper_size))
    return 0;
    
  res->q_append(n_points);
  wkb_end= wkb + proper_size;
  for (wkb+=4; wkb < wkb_end; wkb+= (WKB_HEADER_SIZE + POINT_DATA_SIZE))
  {
    res->q_append((char)wkb_ndr);
    res->q_append((uint32)wkb_point);
    if (!p.init_from_wkb(wkb + WKB_HEADER_SIZE,
unknown's avatar
unknown committed
1056
                         POINT_DATA_SIZE, (wkbByteOrder) wkb[0], res))
1057 1058 1059 1060 1061 1062
      return 0;
  }
  return proper_size;
}


1063
bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
unknown's avatar
unknown committed
1064 1065
{
  uint32 n_points;
unknown's avatar
unknown committed
1066
  if (no_data(m_data, 4))
unknown's avatar
unknown committed
1067 1068
    return 1;

unknown's avatar
unknown committed
1069 1070 1071 1072
  n_points= uint4korr(m_data);
  if (no_data(m_data+4,
	      n_points * (SIZEOF_STORED_DOUBLE * 2 + WKB_HEADER_SIZE)) ||
      txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
unknown's avatar
unknown committed
1073
    return 1;
unknown's avatar
unknown committed
1074 1075
  *end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE);
  txt->length(txt->length()-1);			// Remove end ','
unknown's avatar
unknown committed
1076 1077 1078
  return 0;
}

unknown's avatar
unknown committed
1079 1080

bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const
unknown's avatar
unknown committed
1081
{
unknown's avatar
unknown committed
1082
  return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0;
unknown's avatar
unknown committed
1083 1084
}

unknown's avatar
unknown committed
1085

1086
int Gis_multi_point::num_geometries(uint32 *num) const
1087
{
unknown's avatar
unknown committed
1088
  *num= uint4korr(m_data);
1089 1090 1091
  return 0;
}

unknown's avatar
unknown committed
1092

1093
int Gis_multi_point::geometry_n(uint32 num, String *result) const
1094 1095 1096
{
  const char *data= m_data;
  uint32 n_points;
unknown's avatar
unknown committed
1097

1098 1099 1100
  if (no_data(data, 4))
    return 1;
  n_points= uint4korr(data);
unknown's avatar
unknown committed
1101 1102 1103 1104 1105
  data+= 4+ (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE);

  if (num > n_points || num < 1 ||
      no_data(data, WKB_HEADER_SIZE + POINT_DATA_SIZE) ||
      result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE))
1106 1107
    return 1;

unknown's avatar
unknown committed
1108
  result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE);
1109 1110 1111
  return 0;
}

1112 1113 1114 1115 1116
const Geometry::Class_info *Gis_multi_point::get_class_info() const
{
  return &multipoint_class;
}

unknown's avatar
unknown committed
1117

unknown's avatar
unknown committed
1118 1119
/***************************** MultiLineString *******************************/

1120
uint32 Gis_multi_line_string::get_data_size() const 
unknown's avatar
unknown committed
1121
{
unknown's avatar
unknown committed
1122 1123 1124
  uint32 n_line_strings;
  const char *data= m_data;

unknown's avatar
unknown committed
1125
  if (no_data(data, 4))
unknown's avatar
unknown committed
1126 1127 1128
    return GET_SIZE_ERROR;
  n_line_strings= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1129

unknown's avatar
unknown committed
1130
  while (n_line_strings--)
unknown's avatar
unknown committed
1131 1132
  {
    if (no_data(data, WKB_HEADER_SIZE + 4))
unknown's avatar
unknown committed
1133 1134 1135
      return GET_SIZE_ERROR;
    data+= (WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) *
	    POINT_DATA_SIZE);
unknown's avatar
unknown committed
1136
  }
unknown's avatar
unknown committed
1137
  return (uint32) (data - m_data);
unknown's avatar
unknown committed
1138 1139
}

unknown's avatar
unknown committed
1140

1141
bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
unknown's avatar
unknown committed
1142
{
unknown's avatar
unknown committed
1143 1144
  uint32 n_line_strings= 0;
  uint32 ls_pos= wkb->length();
unknown's avatar
unknown committed
1145 1146 1147

  if (wkb->reserve(4, 512))
    return 1;
unknown's avatar
unknown committed
1148
  wkb->length(wkb->length()+4);			// Reserve space for points
unknown's avatar
unknown committed
1149 1150 1151
  
  for (;;)
  {
unknown's avatar
unknown committed
1152
    Gis_line_string ls;
unknown's avatar
unknown committed
1153 1154 1155

    if (wkb->reserve(1+4, 512))
      return 1;
1156 1157
    wkb->q_append((char) wkb_ndr);
    wkb->q_append((uint32) wkb_linestring);
unknown's avatar
unknown committed
1158

unknown's avatar
unknown committed
1159 1160 1161
    if (trs->check_next_symbol('(') ||
	ls.init_from_wkt(trs, wkb) ||
	trs->check_next_symbol(')'))
unknown's avatar
unknown committed
1162
      return 1;
unknown's avatar
unknown committed
1163 1164
    n_line_strings++;
    if (trs->skip_char(','))			// Didn't find ','
unknown's avatar
unknown committed
1165 1166
      break;
  }
unknown's avatar
unknown committed
1167
  wkb->write_at_position(ls_pos, n_line_strings);
unknown's avatar
unknown committed
1168 1169 1170
  return 0;
}

unknown's avatar
unknown committed
1171

1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
                                          wkbByteOrder bo, String *res)
{
  uint32 n_line_strings;
  const char *wkb_orig= wkb;

  if (len < 4)
    return 0;
  n_line_strings= wkb_get_uint(wkb, bo);

  if (res->reserve(4, 512))
    return 0;
  res->q_append(n_line_strings);
  
unknown's avatar
unknown committed
1186 1187
  wkb+= 4;
  while (n_line_strings--)
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
  {
    Gis_line_string ls;
    int ls_len;

    if ((len < WKB_HEADER_SIZE) ||
        res->reserve(WKB_HEADER_SIZE, 512))
      return 0;

    res->q_append((char) wkb_ndr);
    res->q_append((uint32) wkb_linestring);

    if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
unknown's avatar
unknown committed
1200
                                   (wkbByteOrder) wkb[0], res)))
1201
      return 0;
unknown's avatar
unknown committed
1202 1203 1204
    ls_len+= WKB_HEADER_SIZE;;
    wkb+= ls_len;
    len-= ls_len;
1205
  }
unknown's avatar
unknown committed
1206
  return (uint) (wkb - wkb_orig);
1207 1208 1209
}


1210 1211
bool Gis_multi_line_string::get_data_as_wkt(String *txt, 
					     const char **end) const
unknown's avatar
unknown committed
1212 1213
{
  uint32 n_line_strings;
1214
  const char *data= m_data;
unknown's avatar
unknown committed
1215

unknown's avatar
unknown committed
1216 1217
  if (no_data(data, 4))
    return 1;
1218 1219
  n_line_strings= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1220 1221

  while (n_line_strings--)
unknown's avatar
unknown committed
1222
  {
unknown's avatar
unknown committed
1223
    uint32 n_points;
unknown's avatar
unknown committed
1224 1225
    if (no_data(data, (WKB_HEADER_SIZE + 4)))
      return 1;
unknown's avatar
unknown committed
1226
    n_points= uint4korr(data + WKB_HEADER_SIZE);
1227
    data+= WKB_HEADER_SIZE + 4;
unknown's avatar
unknown committed
1228 1229
    if (no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) ||
	txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
unknown's avatar
unknown committed
1230 1231
      return 1;
    txt->qs_append('(');
unknown's avatar
unknown committed
1232 1233
    data= append_points(txt, n_points, data, 0);
    (*txt) [txt->length() - 1]= ')';
unknown's avatar
unknown committed
1234 1235 1236
    txt->qs_append(',');
  }
  txt->length(txt->length() - 1);
unknown's avatar
unknown committed
1237
  *end= data;
unknown's avatar
unknown committed
1238 1239 1240
  return 0;
}

unknown's avatar
unknown committed
1241

1242
bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const
unknown's avatar
unknown committed
1243 1244
{
  uint32 n_line_strings;
unknown's avatar
unknown committed
1245 1246
  const char *data= m_data;

unknown's avatar
unknown committed
1247 1248
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1249 1250
  n_line_strings= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1251

unknown's avatar
unknown committed
1252
  while (n_line_strings--)
unknown's avatar
unknown committed
1253
  {
unknown's avatar
unknown committed
1254 1255
    data+= WKB_HEADER_SIZE;
    if (!(data= get_mbr_for_points(mbr, data, 0)))
unknown's avatar
unknown committed
1256 1257
      return 1;
  }
unknown's avatar
unknown committed
1258
  *end= data;
unknown's avatar
unknown committed
1259 1260 1261
  return 0;
}

unknown's avatar
unknown committed
1262

1263
int Gis_multi_line_string::num_geometries(uint32 *num) const
1264
{
unknown's avatar
unknown committed
1265
  *num= uint4korr(m_data);
1266 1267 1268
  return 0;
}

unknown's avatar
unknown committed
1269

1270
int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
1271
{
unknown's avatar
unknown committed
1272
  uint32 n_line_strings, n_points, length;
1273
  const char *data= m_data;
unknown's avatar
unknown committed
1274

1275 1276 1277 1278 1279 1280
  if (no_data(data, 4))
    return 1;
  n_line_strings= uint4korr(data);
  data+= 4;

  if ((num > n_line_strings) || (num < 1))
unknown's avatar
unknown committed
1281
    return 1;
1282
 
unknown's avatar
unknown committed
1283
  for (;;)
1284 1285 1286
  {
    if (no_data(data, WKB_HEADER_SIZE + 4))
      return 1;
unknown's avatar
unknown committed
1287 1288 1289 1290 1291
    n_points= uint4korr(data + WKB_HEADER_SIZE);
    length= WKB_HEADER_SIZE + 4+ POINT_DATA_SIZE * n_points;
    if (no_data(data, length))
      return 1;
    if (!--num)
1292
      break;
unknown's avatar
unknown committed
1293
    data+= length;
1294
  }
unknown's avatar
unknown committed
1295
  return result->append(data, length, (uint32) 0);
1296 1297
}

unknown's avatar
unknown committed
1298

1299
int Gis_multi_line_string::length(double *len) const
unknown's avatar
unknown committed
1300 1301
{
  uint32 n_line_strings;
unknown's avatar
unknown committed
1302 1303
  const char *data= m_data;

unknown's avatar
unknown committed
1304 1305
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1306 1307 1308
  n_line_strings= uint4korr(data);
  data+= 4;

unknown's avatar
unknown committed
1309
  *len=0;
unknown's avatar
unknown committed
1310
  while (n_line_strings--)
unknown's avatar
unknown committed
1311 1312
  {
    double ls_len;
unknown's avatar
unknown committed
1313 1314
    Gis_line_string ls;
    data+= WKB_HEADER_SIZE;
1315
    ls.set_data_ptr(data, (uint32) (m_data_end - data));
unknown's avatar
unknown committed
1316 1317
    if (ls.length(&ls_len))
      return 1;
unknown's avatar
unknown committed
1318 1319 1320 1321 1322 1323
    *len+= ls_len;
    /*
      We know here that ls was ok, so we can call the trivial function
      Gis_line_string::get_data_size without error checking
    */
    data+= ls.get_data_size();
unknown's avatar
unknown committed
1324 1325 1326 1327
  }
  return 0;
}

unknown's avatar
unknown committed
1328

1329
int Gis_multi_line_string::is_closed(int *closed) const
unknown's avatar
unknown committed
1330 1331
{
  uint32 n_line_strings;
unknown's avatar
unknown committed
1332 1333 1334
  const char *data= m_data;

  if (no_data(data, 4 + WKB_HEADER_SIZE))
unknown's avatar
unknown committed
1335
    return 1;
unknown's avatar
unknown committed
1336 1337 1338 1339
  n_line_strings= uint4korr(data);
  data+= 4 + WKB_HEADER_SIZE;

  while (n_line_strings--)
unknown's avatar
unknown committed
1340
  {
unknown's avatar
unknown committed
1341 1342 1343
    Gis_line_string ls;
    if (no_data(data, 0))
      return 1;
1344
    ls.set_data_ptr(data, (uint32) (m_data_end - data));
unknown's avatar
unknown committed
1345 1346 1347 1348
    if (ls.is_closed(closed))
      return 1;
    if (!*closed)
      return 0;
unknown's avatar
unknown committed
1349 1350 1351 1352 1353
    /*
      We know here that ls was ok, so we can call the trivial function
      Gis_line_string::get_data_size without error checking
    */
    data+= ls.get_data_size() + WKB_HEADER_SIZE;
unknown's avatar
unknown committed
1354 1355 1356 1357
  }
  return 0;
}

1358 1359 1360 1361 1362
const Geometry::Class_info *Gis_multi_line_string::get_class_info() const
{
  return &multilinestring_class;
}

unknown's avatar
unknown committed
1363

unknown's avatar
unknown committed
1364 1365
/***************************** MultiPolygon *******************************/

unknown's avatar
unknown committed
1366
uint32 Gis_multi_polygon::get_data_size() const 
unknown's avatar
unknown committed
1367 1368
{
  uint32 n_polygons;
unknown's avatar
unknown committed
1369 1370
  const char *data= m_data;

unknown's avatar
unknown committed
1371
  if (no_data(data, 4))
unknown's avatar
unknown committed
1372 1373 1374
    return GET_SIZE_ERROR;
  n_polygons= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1375

unknown's avatar
unknown committed
1376
  while (n_polygons--)
unknown's avatar
unknown committed
1377
  {
unknown's avatar
unknown committed
1378
    uint32 n_linear_rings;
unknown's avatar
unknown committed
1379
    if (no_data(data, 4 + WKB_HEADER_SIZE))
unknown's avatar
unknown committed
1380
      return GET_SIZE_ERROR;
unknown's avatar
unknown committed
1381

unknown's avatar
unknown committed
1382 1383 1384 1385
    n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
    data+= 4 + WKB_HEADER_SIZE;

    while (n_linear_rings--)
unknown's avatar
unknown committed
1386
    {
unknown's avatar
unknown committed
1387 1388 1389
      if (no_data(data, 4))
	return GET_SIZE_ERROR;
      data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
unknown's avatar
unknown committed
1390 1391
    }
  }
unknown's avatar
unknown committed
1392
  return (uint32) (data - m_data);
unknown's avatar
unknown committed
1393 1394
}

unknown's avatar
unknown committed
1395 1396

bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
unknown's avatar
unknown committed
1397
{
unknown's avatar
unknown committed
1398 1399 1400
  uint32 n_polygons= 0;
  int np_pos= wkb->length();
  Gis_polygon p;
unknown's avatar
unknown committed
1401 1402 1403

  if (wkb->reserve(4, 512))
    return 1;
unknown's avatar
unknown committed
1404
  wkb->length(wkb->length()+4);			// Reserve space for points
unknown's avatar
unknown committed
1405 1406 1407 1408 1409

  for (;;)  
  {
    if (wkb->reserve(1+4, 512))
      return 1;
1410 1411
    wkb->q_append((char) wkb_ndr);
    wkb->q_append((uint32) wkb_polygon);
unknown's avatar
unknown committed
1412

unknown's avatar
unknown committed
1413 1414 1415
    if (trs->check_next_symbol('(') ||
	p.init_from_wkt(trs, wkb) ||
	trs->check_next_symbol(')'))
unknown's avatar
unknown committed
1416
      return 1;
unknown's avatar
unknown committed
1417 1418
    n_polygons++;
    if (trs->skip_char(','))			// Didn't find ','
unknown's avatar
unknown committed
1419 1420
      break;
  }
unknown's avatar
unknown committed
1421
  wkb->write_at_position(np_pos, n_polygons);
unknown's avatar
unknown committed
1422 1423 1424
  return 0;
}

unknown's avatar
unknown committed
1425

1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
                                      wkbByteOrder bo, String *res)
{
  uint32 n_poly;
  const char *wkb_orig= wkb;

  if (len < 4)
    return 0;
  n_poly= wkb_get_uint(wkb, bo);

  if (res->reserve(4, 512))
    return 0;
  res->q_append(n_poly);
  
unknown's avatar
unknown committed
1440 1441
  wkb+=4;
  while (n_poly--)
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452
  {
    Gis_polygon p;
    int p_len;

    if (len < WKB_HEADER_SIZE ||
        res->reserve(WKB_HEADER_SIZE, 512))
      return 0;
    res->q_append((char) wkb_ndr);
    res->q_append((uint32) wkb_polygon);

    if (!(p_len= p.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
unknown's avatar
unknown committed
1453
                                 (wkbByteOrder) wkb[0], res)))
1454
      return 0;
unknown's avatar
unknown committed
1455 1456 1457
    p_len+= WKB_HEADER_SIZE;
    wkb+= p_len;
    len-= p_len;
1458
  }
unknown's avatar
unknown committed
1459
  return (uint) (wkb - wkb_orig);
1460 1461 1462
}


1463
bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
unknown's avatar
unknown committed
1464 1465
{
  uint32 n_polygons;
1466
  const char *data= m_data;
unknown's avatar
unknown committed
1467

unknown's avatar
unknown committed
1468 1469
  if (no_data(data, 4))
    return 1;
1470 1471
  n_polygons= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1472

unknown's avatar
unknown committed
1473
  while (n_polygons--)
unknown's avatar
unknown committed
1474
  {
unknown's avatar
unknown committed
1475 1476 1477
    uint32 n_linear_rings;
    if (no_data(data, 4 + WKB_HEADER_SIZE) ||
	txt->reserve(1, 512))
unknown's avatar
unknown committed
1478
      return 1;
unknown's avatar
unknown committed
1479 1480
    n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
    data+= 4 + WKB_HEADER_SIZE;
unknown's avatar
unknown committed
1481
    txt->q_append('(');
unknown's avatar
unknown committed
1482 1483

    while (n_linear_rings--)
unknown's avatar
unknown committed
1484 1485 1486
    {
      if (no_data(data, 4))
        return 1;
1487 1488
      uint32 n_points= uint4korr(data);
      data+= 4;
unknown's avatar
unknown committed
1489 1490 1491 1492
      if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) ||
	  txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
		       512))
	return 1;
unknown's avatar
unknown committed
1493
      txt->qs_append('(');
unknown's avatar
unknown committed
1494 1495
      data= append_points(txt, n_points, data, 0);
      (*txt) [txt->length() - 1]= ')';
unknown's avatar
unknown committed
1496 1497
      txt->qs_append(',');
    }
unknown's avatar
unknown committed
1498
    (*txt) [txt->length() - 1]= ')';
unknown's avatar
unknown committed
1499 1500 1501
    txt->qs_append(',');
  }
  txt->length(txt->length() - 1);
unknown's avatar
unknown committed
1502
  *end= data;
unknown's avatar
unknown committed
1503 1504 1505
  return 0;
}

unknown's avatar
unknown committed
1506 1507

bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const
unknown's avatar
unknown committed
1508 1509
{
  uint32 n_polygons;
unknown's avatar
unknown committed
1510 1511
  const char *data= m_data;

unknown's avatar
unknown committed
1512 1513
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1514 1515
  n_polygons= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1516

unknown's avatar
unknown committed
1517
  while (n_polygons--)
unknown's avatar
unknown committed
1518
  {
unknown's avatar
unknown committed
1519
    uint32 n_linear_rings;
unknown's avatar
unknown committed
1520 1521
    if (no_data(data, 4+WKB_HEADER_SIZE))
      return 1;
unknown's avatar
unknown committed
1522 1523
    n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
    data+= WKB_HEADER_SIZE + 4;
unknown's avatar
unknown committed
1524

unknown's avatar
unknown committed
1525
    while (n_linear_rings--)
unknown's avatar
unknown committed
1526
    {
unknown's avatar
unknown committed
1527 1528
      if (!(data= get_mbr_for_points(mbr, data, 0)))
	return 1;
unknown's avatar
unknown committed
1529 1530
    }
  }
unknown's avatar
unknown committed
1531
  *end= data;
unknown's avatar
unknown committed
1532 1533 1534
  return 0;
}

unknown's avatar
unknown committed
1535

1536
int Gis_multi_polygon::num_geometries(uint32 *num) const
1537
{
unknown's avatar
unknown committed
1538
  *num= uint4korr(m_data);
1539 1540 1541
  return 0;
}

unknown's avatar
unknown committed
1542

1543
int Gis_multi_polygon::geometry_n(uint32 num, String *result) const
1544 1545
{
  uint32 n_polygons;
unknown's avatar
unknown committed
1546
  const char *data= m_data, *start_of_polygon;
1547

1548 1549 1550 1551 1552
  if (no_data(data, 4))
    return 1;
  n_polygons= uint4korr(data);
  data+= 4;

unknown's avatar
unknown committed
1553
  if (num > n_polygons || num < 1)
1554 1555
    return -1;

unknown's avatar
unknown committed
1556
  do
1557
  {
unknown's avatar
unknown committed
1558 1559 1560
    uint32 n_linear_rings;
    start_of_polygon= data;

1561 1562
    if (no_data(data, WKB_HEADER_SIZE + 4))
      return 1;
unknown's avatar
unknown committed
1563
    n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
1564
    data+= WKB_HEADER_SIZE + 4;
unknown's avatar
unknown committed
1565 1566

    while (n_linear_rings--)
1567
    {
unknown's avatar
unknown committed
1568
      uint32 n_points;
1569 1570
      if (no_data(data, 4))
	return 1;
unknown's avatar
unknown committed
1571
      n_points= uint4korr(data);
1572 1573
      data+= 4 + POINT_DATA_SIZE * n_points;
    }
unknown's avatar
unknown committed
1574 1575 1576 1577 1578
  } while (--num);
  if (no_data(data, 0))				// We must check last segment
    return 1;
  return result->append(start_of_polygon, (uint32) (data - start_of_polygon),
			(uint32) 0);
1579
}
unknown's avatar
unknown committed
1580

unknown's avatar
unknown committed
1581

1582
int Gis_multi_polygon::area(double *ar,  const char **end_of_data) const
unknown's avatar
unknown committed
1583 1584
{
  uint32 n_polygons;
unknown's avatar
unknown committed
1585 1586 1587
  const char *data= m_data;
  double result= 0;

unknown's avatar
unknown committed
1588 1589
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1590 1591
  n_polygons= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1592

unknown's avatar
unknown committed
1593
  while (n_polygons--)
unknown's avatar
unknown committed
1594 1595
  {
    double p_area;
unknown's avatar
unknown committed
1596
    Gis_polygon p;
unknown's avatar
unknown committed
1597

unknown's avatar
unknown committed
1598
    data+= WKB_HEADER_SIZE;
1599
    p.set_data_ptr(data, (uint32) (m_data_end - data));
unknown's avatar
unknown committed
1600
    if (p.area(&p_area, &data))
unknown's avatar
unknown committed
1601
      return 1;
unknown's avatar
unknown committed
1602
    result+= p_area;
unknown's avatar
unknown committed
1603
  }
unknown's avatar
unknown committed
1604 1605
  *ar= result;
  *end_of_data= data;
unknown's avatar
unknown committed
1606 1607 1608
  return 0;
}

unknown's avatar
unknown committed
1609

1610
int Gis_multi_polygon::centroid(String *result) const
unknown's avatar
unknown committed
1611 1612
{
  uint32 n_polygons;
unknown's avatar
unknown committed
1613 1614
  bool first_loop= 1;
  Gis_polygon p;
unknown's avatar
unknown committed
1615 1616
  double res_area, res_cx, res_cy;
  double cur_area, cur_cx, cur_cy;
unknown's avatar
unknown committed
1617
  const char *data= m_data;
unknown's avatar
unknown committed
1618

1619 1620 1621 1622
  LINT_INIT(res_area);
  LINT_INIT(res_cx);
  LINT_INIT(res_cy);

unknown's avatar
unknown committed
1623 1624
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1625 1626
  n_polygons= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1627

unknown's avatar
unknown committed
1628
  while (n_polygons--)
unknown's avatar
unknown committed
1629
  {
unknown's avatar
unknown committed
1630
    data+= WKB_HEADER_SIZE;
1631
    p.set_data_ptr(data, (uint32) (m_data_end - data));
unknown's avatar
unknown committed
1632 1633
    if (p.area(&cur_area, &data) ||
	p.centroid_xy(&cur_cx, &cur_cy))
unknown's avatar
unknown committed
1634 1635
      return 1;

unknown's avatar
unknown committed
1636
    if (!first_loop)
unknown's avatar
unknown committed
1637
    {
unknown's avatar
unknown committed
1638 1639 1640
      double sum_area= res_area + cur_area;
      res_cx= (res_area * res_cx + cur_area * cur_cx) / sum_area;
      res_cy= (res_area * res_cy + cur_area * cur_cy) / sum_area;
unknown's avatar
unknown committed
1641 1642 1643
    }
    else
    {
unknown's avatar
unknown committed
1644 1645 1646 1647
      first_loop= 0;
      res_area= cur_area;
      res_cx= cur_cx;
      res_cy= cur_cy;
unknown's avatar
unknown committed
1648 1649 1650
    }
  }

unknown's avatar
unknown committed
1651
  return create_point(result, res_cx, res_cy);
unknown's avatar
unknown committed
1652 1653
}

1654 1655 1656 1657 1658
const Geometry::Class_info *Gis_multi_polygon::get_class_info() const
{
  return &multipolygon_class;
}

unknown's avatar
unknown committed
1659

unknown's avatar
unknown committed
1660 1661 1662
/************************* GeometryCollection ****************************/

uint32 Gis_geometry_collection::get_data_size() const 
unknown's avatar
unknown committed
1663 1664
{
  uint32 n_objects;
unknown's avatar
unknown committed
1665
  const char *data= m_data;
1666 1667
  Geometry_buffer buffer;
  Geometry *geom;
unknown's avatar
unknown committed
1668

unknown's avatar
unknown committed
1669
  if (no_data(data, 4))
unknown's avatar
unknown committed
1670 1671 1672
    return GET_SIZE_ERROR;
  n_objects= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1673

unknown's avatar
unknown committed
1674
  while (n_objects--)
unknown's avatar
unknown committed
1675
  {
unknown's avatar
unknown committed
1676
    uint32 wkb_type,object_size;
unknown's avatar
unknown committed
1677

unknown's avatar
unknown committed
1678 1679 1680 1681
    if (no_data(data, WKB_HEADER_SIZE))
      return GET_SIZE_ERROR;
    wkb_type= uint4korr(data + 1);
    data+= WKB_HEADER_SIZE;
unknown's avatar
unknown committed
1682

1683
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
unknown's avatar
unknown committed
1684
      return GET_SIZE_ERROR;
1685
    geom->set_data_ptr(data, (uint) (m_data_end - data));
1686
    if ((object_size= geom->get_data_size()) == GET_SIZE_ERROR)
unknown's avatar
unknown committed
1687 1688
      return GET_SIZE_ERROR;
    data+= object_size;
unknown's avatar
unknown committed
1689
  }
unknown's avatar
unknown committed
1690
  return (uint32) (data - m_data);
unknown's avatar
unknown committed
1691 1692
}

unknown's avatar
unknown committed
1693 1694

bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
unknown's avatar
unknown committed
1695
{
unknown's avatar
unknown committed
1696 1697
  uint32 n_objects= 0;
  uint32 no_pos= wkb->length();
1698 1699
  Geometry_buffer buffer;
  Geometry *g;
unknown's avatar
unknown committed
1700 1701 1702

  if (wkb->reserve(4, 512))
    return 1;
unknown's avatar
unknown committed
1703
  wkb->length(wkb->length()+4);			// Reserve space for points
unknown's avatar
unknown committed
1704 1705 1706

  for (;;)
  {
1707
    if (!(g= create_from_wkt(&buffer, trs, wkb)))
unknown's avatar
unknown committed
1708 1709
      return 1;

1710
    if (g->get_class_info()->m_type_id == wkb_geometrycollection)
unknown's avatar
unknown committed
1711 1712 1713 1714
    {
      trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
      return 1;
    }
unknown's avatar
unknown committed
1715 1716 1717
    n_objects++;
    if (trs->skip_char(','))			// Didn't find ','
      break;
unknown's avatar
unknown committed
1718 1719
  }

unknown's avatar
unknown committed
1720
  wkb->write_at_position(no_pos, n_objects);
unknown's avatar
unknown committed
1721 1722 1723
  return 0;
}

unknown's avatar
unknown committed
1724

1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
                                            wkbByteOrder bo, String *res)
{
  uint32 n_geom;
  const char *wkb_orig= wkb;

  if (len < 4)
    return 0;
  n_geom= wkb_get_uint(wkb, bo);

  if (res->reserve(4, 512))
    return 0;
  res->q_append(n_geom);
  
unknown's avatar
unknown committed
1739 1740
  wkb+= 4;
  while (n_geom--)
1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
  {
    Geometry_buffer buffer;
    Geometry *geom;
    int g_len;
    uint32 wkb_type;

    if (len < WKB_HEADER_SIZE ||
        res->reserve(WKB_HEADER_SIZE, 512))
      return 0;

    res->q_append((char) wkb_ndr);
unknown's avatar
unknown committed
1752
    wkb_type= wkb_get_uint(wkb+1, (wkbByteOrder) wkb[0]);
1753 1754 1755 1756
    res->q_append(wkb_type);

    if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
        !(g_len= geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len,
unknown's avatar
unknown committed
1757
                                     (wkbByteOrder)  wkb[0], res)))
1758
      return 0;
unknown's avatar
unknown committed
1759 1760 1761
    g_len+= WKB_HEADER_SIZE;
    wkb+= g_len;
    len-= g_len;
1762
  }
unknown's avatar
unknown committed
1763
  return (uint) (wkb - wkb_orig);
1764 1765 1766
}


1767 1768
bool Gis_geometry_collection::get_data_as_wkt(String *txt,
					     const char **end) const
unknown's avatar
unknown committed
1769 1770
{
  uint32 n_objects;
1771 1772
  Geometry_buffer buffer;
  Geometry *geom;
unknown's avatar
unknown committed
1773 1774
  const char *data= m_data;

unknown's avatar
unknown committed
1775 1776
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1777 1778
  n_objects= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1779

unknown's avatar
unknown committed
1780
  while (n_objects--)
unknown's avatar
unknown committed
1781
  {
unknown's avatar
unknown committed
1782 1783
    uint32 wkb_type;

unknown's avatar
unknown committed
1784 1785
    if (no_data(data, WKB_HEADER_SIZE))
      return 1;
unknown's avatar
unknown committed
1786 1787
    wkb_type= uint4korr(data + 1);
    data+= WKB_HEADER_SIZE;
unknown's avatar
unknown committed
1788

1789
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
unknown's avatar
unknown committed
1790
      return 1;
1791
    geom->set_data_ptr(data, (uint) (m_data_end - data));
1792
    if (geom->as_wkt(txt, &data))
unknown's avatar
unknown committed
1793 1794
      return 1;
    if (txt->append(",", 1, 512))
unknown's avatar
unknown committed
1795 1796 1797
      return 1;
  }
  txt->length(txt->length() - 1);
unknown's avatar
unknown committed
1798
  *end= data;
unknown's avatar
unknown committed
1799 1800 1801
  return 0;
}

unknown's avatar
unknown committed
1802 1803

bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
unknown's avatar
unknown committed
1804 1805
{
  uint32 n_objects;
unknown's avatar
unknown committed
1806
  const char *data= m_data;
1807 1808
  Geometry_buffer buffer;
  Geometry *geom;
unknown's avatar
unknown committed
1809

unknown's avatar
unknown committed
1810 1811
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1812 1813 1814 1815
  n_objects= uint4korr(data);
  data+= 4;

  while (n_objects--)
unknown's avatar
unknown committed
1816
  {
unknown's avatar
unknown committed
1817 1818
    uint32 wkb_type;

unknown's avatar
unknown committed
1819
    if (no_data(data, WKB_HEADER_SIZE))
unknown's avatar
unknown committed
1820
      return 1;
unknown's avatar
unknown committed
1821 1822
    wkb_type= uint4korr(data + 1);
    data+= WKB_HEADER_SIZE;
unknown's avatar
unknown committed
1823

1824
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
unknown's avatar
unknown committed
1825
      return 1;
1826
    geom->set_data_ptr(data, (uint32) (m_data_end - data));
1827
    if (geom->get_mbr(mbr, &data))
unknown's avatar
unknown committed
1828
      return 1;
unknown's avatar
unknown committed
1829
  }
unknown's avatar
unknown committed
1830
  *end= data;
unknown's avatar
unknown committed
1831 1832 1833
  return 0;
}

unknown's avatar
unknown committed
1834

1835
int Gis_geometry_collection::num_geometries(uint32 *num) const
unknown's avatar
unknown committed
1836
{
unknown's avatar
unknown committed
1837 1838 1839
  if (no_data(m_data, 4))
    return 1;
  *num= uint4korr(m_data);
unknown's avatar
unknown committed
1840 1841 1842
  return 0;
}

unknown's avatar
unknown committed
1843

1844
int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
unknown's avatar
unknown committed
1845
{
unknown's avatar
unknown committed
1846 1847
  uint32 n_objects, wkb_type, length;
  const char *data= m_data;
1848 1849
  Geometry_buffer buffer;
  Geometry *geom;
unknown's avatar
unknown committed
1850

unknown's avatar
unknown committed
1851 1852
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1853 1854 1855 1856
  n_objects= uint4korr(data);
  data+= 4;
  if (num > n_objects || num < 1)
    return 1;
unknown's avatar
unknown committed
1857

unknown's avatar
unknown committed
1858
  do
unknown's avatar
unknown committed
1859 1860 1861
  {
    if (no_data(data, WKB_HEADER_SIZE))
      return 1;
unknown's avatar
unknown committed
1862 1863
    wkb_type= uint4korr(data + 1);
    data+= WKB_HEADER_SIZE;
unknown's avatar
unknown committed
1864

1865
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
unknown's avatar
unknown committed
1866
      return 1;
1867
    geom->set_data_ptr(data, (uint) (m_data_end - data));
1868
    if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
unknown's avatar
unknown committed
1869 1870 1871 1872 1873 1874 1875
      return 1;
    data+= length;
  } while (--num);

  /* Copy found object to result */
  if (result->reserve(1+4+length))
    return 1;
1876
  result->q_append((char) wkb_ndr);
unknown's avatar
unknown committed
1877 1878
  result->q_append((uint32) wkb_type);
  result->q_append(data-length, length);	// data-length = start_of_data
unknown's avatar
unknown committed
1879 1880 1881
  return 0;
}

unknown's avatar
unknown committed
1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896

/*
  Return dimension for object

  SYNOPSIS
    dimension()
    res_dim		Result dimension
    end			End of object will be stored here. May be 0 for
			simple objects!
  RETURN
    0	ok
    1	error
*/

bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
unknown's avatar
unknown committed
1897 1898
{
  uint32 n_objects;
unknown's avatar
unknown committed
1899
  const char *data= m_data;
1900 1901
  Geometry_buffer buffer;
  Geometry *geom;
unknown's avatar
unknown committed
1902

unknown's avatar
unknown committed
1903 1904
  if (no_data(data, 4))
    return 1;
unknown's avatar
unknown committed
1905 1906
  n_objects= uint4korr(data);
  data+= 4;
unknown's avatar
unknown committed
1907

unknown's avatar
unknown committed
1908 1909
  *res_dim= 0;
  while (n_objects--)
unknown's avatar
unknown committed
1910
  {
unknown's avatar
unknown committed
1911 1912 1913
    uint32 wkb_type, length, dim;
    const char *end_data;

unknown's avatar
unknown committed
1914 1915
    if (no_data(data, WKB_HEADER_SIZE))
      return 1;
unknown's avatar
unknown committed
1916 1917
    wkb_type= uint4korr(data + 1);
    data+= WKB_HEADER_SIZE;
1918
    if (!(geom= create_by_typeid(&buffer, wkb_type)))
unknown's avatar
unknown committed
1919
      return 1;
1920
    geom->set_data_ptr(data, (uint32) (m_data_end - data));
1921
    if (geom->dimension(&dim, &end_data))
unknown's avatar
unknown committed
1922
      return 1;
unknown's avatar
unknown committed
1923 1924 1925
    set_if_bigger(*res_dim, dim);
    if (end_data)				// Complex object
      data= end_data;
1926
    else if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
unknown's avatar
unknown committed
1927 1928 1929
      return 1;
    else
      data+= length;
unknown's avatar
unknown committed
1930
  }
unknown's avatar
unknown committed
1931
  *end= data;
unknown's avatar
unknown committed
1932 1933
  return 0;
}
1934 1935 1936 1937 1938 1939

const Geometry::Class_info *Gis_geometry_collection::get_class_info() const
{
  return &geometrycollection_class;
}

1940
#endif /*HAVE_SPATIAL*/