spatial.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:42k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2004 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include "mysql_priv.h"
  14. #ifdef HAVE_SPATIAL
  15. #define MAX_DIGITS_IN_DOUBLE 16
  16. /***************************** Gis_class_info *******************************/
  17. Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]=
  18. {
  19.   NULL, NULL, NULL, NULL, NULL, NULL, NULL
  20. };
  21. static Geometry::Class_info **ci_collection_end=
  22.                                 Geometry::ci_collection+Geometry::wkb_end + 1;
  23. Geometry::Class_info::Class_info(const char *name, int type_id,
  24.  void(*create_func)(void *)):
  25.   m_name(name, strlen(name)), m_type_id(type_id), m_create_func(create_func)
  26. {
  27.   ci_collection[type_id]= this;
  28. }
  29. static void create_point(void *buffer)
  30. {
  31.   new(buffer) Gis_point;
  32. }
  33. static void create_linestring(void *buffer)
  34. {
  35.   new(buffer) Gis_line_string;
  36. }
  37. static void create_polygon(void *buffer)
  38. {
  39.   new(buffer) Gis_polygon;
  40. }
  41. static void create_multipoint(void *buffer)
  42. {
  43.   new(buffer) Gis_multi_point;
  44. }
  45. static void create_multipolygon(void *buffer)
  46. {
  47.   new(buffer) Gis_multi_polygon;
  48. }
  49. static void create_multilinestring(void *buffer)
  50. {
  51.   new(buffer) Gis_multi_line_string;
  52. }
  53. static void create_geometrycollection(void *buffer)
  54. {
  55.   new(buffer) Gis_geometry_collection;
  56. }
  57. static Geometry::Class_info point_class("POINT",
  58. Geometry::wkb_point, create_point);
  59. static Geometry::Class_info linestring_class("LINESTRING",
  60.      Geometry::wkb_linestring,
  61.      create_linestring);
  62. static Geometry::Class_info polygon_class("POLYGON",
  63.       Geometry::wkb_polygon,
  64.       create_polygon);
  65. static Geometry::Class_info multipoint_class("MULTIPOINT",
  66.  Geometry::wkb_multipoint,
  67.  create_multipoint);
  68. static Geometry::Class_info 
  69. multilinestring_class("MULTILINESTRING",
  70.       Geometry::wkb_multilinestring, create_multilinestring);
  71. static Geometry::Class_info multipolygon_class("MULTIPOLYGON",
  72.    Geometry::wkb_multipolygon,
  73.    create_multipolygon);
  74. static Geometry::Class_info 
  75. geometrycollection_class("GEOMETRYCOLLECTION",Geometry::wkb_geometrycollection,
  76.  create_geometrycollection);
  77. static void get_point(double *x, double *y, const char *data)
  78. {
  79.   float8get(*x, data);
  80.   float8get(*y, data + SIZEOF_STORED_DOUBLE);
  81. }
  82. /***************************** Geometry *******************************/
  83. Geometry::Class_info *Geometry::find_class(const char *name, uint32 len)
  84. {
  85.   for (Class_info **cur_rt= ci_collection;
  86.        cur_rt < ci_collection_end; cur_rt++)
  87.   {
  88.     if (*cur_rt &&
  89. ((*cur_rt)->m_name.length == len) &&
  90. (my_strnncoll(&my_charset_latin1,
  91.       (const uchar*) (*cur_rt)->m_name.str, len,
  92.       (const uchar*) name, len) == 0))
  93.       return *cur_rt;
  94.   }
  95.   return 0;
  96. }
  97. Geometry *Geometry::construct(Geometry_buffer *buffer,
  98.                               const char *data, uint32 data_len)
  99. {
  100.   uint32 geom_type;
  101.   Geometry *result;
  102.   char byte_order;
  103.   if (data_len < SRID_SIZE + WKB_HEADER_SIZE)   // < 4 + (1 + 4)
  104.     return NULL;
  105.   byte_order= data[SRID_SIZE];
  106.   geom_type= uint4korr(data + SRID_SIZE + 1);
  107.   if (!(result= create_by_typeid(buffer, (int) geom_type)))
  108.     return NULL;
  109.   result->m_data= data+ SRID_SIZE + WKB_HEADER_SIZE;
  110.   result->m_data_end= data + data_len;
  111.   return result;
  112. }
  113. Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
  114.     Gis_read_stream *trs, String *wkt,
  115.     bool init_stream)
  116. {
  117.   LEX_STRING name;
  118.   Class_info *ci;
  119.   if (trs->get_next_word(&name))
  120.   {
  121.     trs->set_error_msg("Geometry name expected");
  122.     return NULL;
  123.   }
  124.   if (!(ci= find_class(name.str, name.length)) ||
  125.       wkt->reserve(1 + 4, 512))
  126.     return NULL;
  127.   (*ci->m_create_func)((void *)buffer);
  128.   Geometry *result= (Geometry *)buffer;
  129.   
  130.   wkt->q_append((char) wkb_ndr);
  131.   wkt->q_append((uint32) result->get_class_info()->m_type_id);
  132.   if (trs->check_next_symbol('(') ||
  133.       result->init_from_wkt(trs, wkt) ||
  134.       trs->check_next_symbol(')'))
  135.     return NULL;
  136.   if (init_stream)  
  137.   {
  138.     result->set_data_ptr(wkt->ptr(), wkt->length());
  139.     result->shift_wkb_header();
  140.   }
  141.   return result;
  142. }
  143. static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
  144. {
  145.   double res;
  146.   if (bo != Geometry::wkb_xdr)
  147.     float8get(res, ptr);
  148.   else
  149.   {
  150.     char inv_array[8];
  151.     inv_array[0]= ptr[7];
  152.     inv_array[1]= ptr[6];
  153.     inv_array[2]= ptr[5];
  154.     inv_array[3]= ptr[4];
  155.     inv_array[4]= ptr[3];
  156.     inv_array[5]= ptr[2];
  157.     inv_array[6]= ptr[1];
  158.     inv_array[7]= ptr[0];
  159.     float8get(res, inv_array);
  160.   }
  161.   return res;
  162. }
  163. static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
  164. {
  165.   if (bo != Geometry::wkb_xdr)
  166.     return uint4korr(ptr);
  167.   /* else */
  168.   {
  169.     char inv_array[4];
  170.     inv_array[0]= ptr[3];
  171.     inv_array[1]= ptr[2];
  172.     inv_array[2]= ptr[1];
  173.     inv_array[3]= ptr[0];
  174.     return uint4korr(inv_array);
  175.   }
  176. }
  177. int Geometry::create_from_wkb(Geometry_buffer *buffer,
  178.                               const char *wkb, uint32 len, String *res)
  179. {
  180.   uint32 geom_type;
  181.   Geometry *geom;
  182.   if (len < WKB_HEADER_SIZE)
  183.     return 1;
  184.   geom_type= wkb_get_uint(wkb+1, (wkbByteOrder)wkb[0]);
  185.   if (!(geom= create_by_typeid(buffer, (int) geom_type)) ||
  186.       res->reserve(WKB_HEADER_SIZE, 512))
  187.     return 1;
  188.   res->q_append((char) wkb_ndr);
  189.   res->q_append(geom_type);
  190.   return geom->init_from_wkb(wkb+WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
  191.                              (wkbByteOrder) wkb[0], res);
  192. }
  193. bool Geometry::envelope(String *result) const
  194. {
  195.   MBR mbr;
  196.   const char *end;
  197.   if (get_mbr(&mbr, &end) || result->reserve(1+4*3+SIZEOF_STORED_DOUBLE*10))
  198.     return 1;
  199.   result->q_append((char) wkb_ndr);
  200.   result->q_append((uint32) wkb_polygon);
  201.   result->q_append((uint32) 1);
  202.   result->q_append((uint32) 5);
  203.   result->q_append(mbr.xmin);
  204.   result->q_append(mbr.ymin);
  205.   result->q_append(mbr.xmax);
  206.   result->q_append(mbr.ymin);
  207.   result->q_append(mbr.xmax);
  208.   result->q_append(mbr.ymax);
  209.   result->q_append(mbr.xmin);
  210.   result->q_append(mbr.ymax);
  211.   result->q_append(mbr.xmin);
  212.   result->q_append(mbr.ymin);
  213.   return 0;
  214. }
  215. /*
  216.   Create a point from data.
  217.   SYNPOSIS
  218.     create_point()
  219.     result Put result here
  220.     data Data for point is here.
  221.   RETURN
  222.     0 ok
  223.     1 Can't reallocate 'result'
  224. */
  225. bool Geometry::create_point(String *result, const char *data) const
  226. {
  227.   if (no_data(data, SIZEOF_STORED_DOUBLE * 2) ||
  228.       result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
  229.     return 1;
  230.   result->q_append((char) wkb_ndr);
  231.   result->q_append((uint32) wkb_point);
  232.   /* Copy two double in same format */
  233.   result->q_append(data, SIZEOF_STORED_DOUBLE*2);
  234.   return 0;
  235. }
  236. /*
  237.   Create a point from coordinates.
  238.   SYNPOSIS
  239.     create_point()
  240.     result Put result here
  241.     x x coordinate for point
  242.     y y coordinate for point
  243.   RETURN
  244.     0 ok
  245.     1 Can't reallocate 'result'
  246. */
  247. bool Geometry::create_point(String *result, double x, double y) const
  248. {
  249.   if (result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
  250.     return 1;
  251.   result->q_append((char) wkb_ndr);
  252.   result->q_append((uint32) wkb_point);
  253.   result->q_append(x);
  254.   result->q_append(y);
  255.   return 0;
  256. }
  257. /*
  258.   Append N points from packed format to text
  259.   SYNOPSIS
  260.     append_points()
  261.     txt Append points here
  262.     n_points Number of points
  263.     data Packed data
  264.     offset Offset between points
  265.   RETURN
  266.     # end of data
  267. */
  268. const char *Geometry::append_points(String *txt, uint32 n_points,
  269.     const char *data, uint32 offset) const
  270. {      
  271.   while (n_points--)
  272.   {
  273.     double x,y;
  274.     data+= offset;
  275.     get_point(&x, &y, data);
  276.     data+= SIZEOF_STORED_DOUBLE * 2;
  277.     txt->qs_append(x);
  278.     txt->qs_append(' ');
  279.     txt->qs_append(y);
  280.     txt->qs_append(',');
  281.   }
  282.   return data;
  283. }
  284. /*
  285.   Get most bounding rectangle (mbr) for X points
  286.   SYNOPSIS
  287.     get_mbr_for_points()
  288.     mbr MBR (store rectangle here)
  289.     points Number of points
  290.     data Packed data
  291.     offset Offset between points
  292.   RETURN
  293.     0 Wrong data
  294.     # end of data
  295. */
  296. const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
  297.  uint offset) const
  298. {
  299.   uint32 points;
  300.   /* read number of points */
  301.   if (no_data(data, 4))
  302.     return 0;
  303.   points= uint4korr(data);
  304.   data+= 4;
  305.   if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points))
  306.     return 0;
  307.   /* Calculate MBR for points */
  308.   while (points--)
  309.   {
  310.     data+= offset;
  311.     mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE);
  312.     data+= SIZEOF_STORED_DOUBLE * 2;
  313.   }
  314.   return data;
  315. }
  316. /***************************** Point *******************************/
  317. uint32 Gis_point::get_data_size() const
  318. {
  319.   return POINT_DATA_SIZE;
  320. }
  321. bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
  322. {
  323.   double x, y;
  324.   if (trs->get_next_number(&x) || trs->get_next_number(&y) ||
  325.       wkb->reserve(SIZEOF_STORED_DOUBLE * 2))
  326.     return 1;
  327.   wkb->q_append(x);
  328.   wkb->q_append(y);
  329.   return 0;
  330. }
  331. uint Gis_point::init_from_wkb(const char *wkb, uint len,
  332.                               wkbByteOrder bo, String *res)
  333. {
  334.   double x, y;
  335.   if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE))
  336.     return 0;
  337.   x= wkb_get_double(wkb, bo);
  338.   y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
  339.   res->q_append(x);
  340.   res->q_append(y);
  341.   return POINT_DATA_SIZE;
  342. }
  343. bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
  344. {
  345.   double x, y;
  346.   if (get_xy(&x, &y))
  347.     return 1;
  348.   if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
  349.     return 1;
  350.   txt->qs_append(x);
  351.   txt->qs_append(' ');
  352.   txt->qs_append(y);
  353.   *end= m_data+ POINT_DATA_SIZE;
  354.   return 0;
  355. }
  356. bool Gis_point::get_mbr(MBR *mbr, const char **end) const
  357. {
  358.   double x, y;
  359.   if (get_xy(&x, &y))
  360.     return 1;
  361.   mbr->add_xy(x, y);
  362.   *end= m_data+ POINT_DATA_SIZE;
  363.   return 0;
  364. }
  365. const Geometry::Class_info *Gis_point::get_class_info() const
  366. {
  367.   return &point_class;
  368. }
  369. /***************************** LineString *******************************/
  370. uint32 Gis_line_string::get_data_size() const 
  371. {
  372.   if (no_data(m_data, 4))
  373.     return GET_SIZE_ERROR;
  374.   return 4 + uint4korr(m_data) * POINT_DATA_SIZE;
  375. }
  376. bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
  377. {
  378.   uint32 n_points= 0;
  379.   uint32 np_pos= wkb->length();
  380.   Gis_point p;
  381.   if (wkb->reserve(4, 512))
  382.     return 1;
  383.   wkb->length(wkb->length()+4); // Reserve space for points  
  384.   for (;;)
  385.   {
  386.     if (p.init_from_wkt(trs, wkb))
  387.       return 1;
  388.     n_points++;
  389.     if (trs->skip_char(',')) // Didn't find ','
  390.       break;
  391.   }
  392.   if (n_points < 1)
  393.   {
  394.     trs->set_error_msg("Too few points in LINESTRING");
  395.     return 1;
  396.   }
  397.   wkb->write_at_position(np_pos, n_points);
  398.   return 0;
  399. }
  400. uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
  401.                                     wkbByteOrder bo, String *res)
  402. {
  403.   uint32 n_points, proper_length;
  404.   const char *wkb_end;
  405.   Gis_point p;
  406.   if (len < 4)
  407.     return 0;
  408.   n_points= wkb_get_uint(wkb, bo);
  409.   proper_length= 4 + n_points * POINT_DATA_SIZE;
  410.   if (len < proper_length || res->reserve(proper_length))
  411.     return 0;
  412.   res->q_append(n_points);
  413.   wkb_end= wkb + proper_length;
  414.   for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE)
  415.   {
  416.     if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res))
  417.       return 0;
  418.   }
  419.   return proper_length;
  420. }
  421. bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
  422. {
  423.   uint32 n_points;
  424.   const char *data= m_data;
  425.   if (no_data(data, 4))
  426.     return 1;
  427.   n_points= uint4korr(data);
  428.   data += 4;
  429.   if (n_points < 1 ||
  430.       no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) ||
  431.       txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
  432.     return 1;
  433.   while (n_points--)
  434.   {
  435.     double x, y;
  436.     get_point(&x, &y, data);
  437.     data+= SIZEOF_STORED_DOUBLE * 2;
  438.     txt->qs_append(x);
  439.     txt->qs_append(' ');
  440.     txt->qs_append(y);
  441.     txt->qs_append(',');
  442.   }
  443.   txt->length(txt->length() - 1); // Remove end ','
  444.   *end= data;
  445.   return 0;
  446. }
  447. bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
  448. {
  449.   return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0;
  450. }
  451. int Gis_line_string::length(double *len) const
  452. {
  453.   uint32 n_points;
  454.   double prev_x, prev_y;
  455.   const char *data= m_data;
  456.   *len= 0; // In case of errors
  457.   if (no_data(data, 4))
  458.     return 1;
  459.   n_points= uint4korr(data);
  460.   data+= 4;
  461.   if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
  462.     return 1;
  463.   get_point(&prev_x, &prev_y, data);
  464.   data+= SIZEOF_STORED_DOUBLE*2;
  465.   while (--n_points)
  466.   {
  467.     double x, y;
  468.     get_point(&x, &y, data);
  469.     data+= SIZEOF_STORED_DOUBLE * 2;
  470.     *len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
  471.     prev_x= x;
  472.     prev_y= y;
  473.   }
  474.   return 0;
  475. }
  476. int Gis_line_string::is_closed(int *closed) const
  477. {
  478.   uint32 n_points;
  479.   double x1, y1, x2, y2;
  480.   const char *data= m_data;
  481.   if (no_data(data, 4))
  482.     return 1;
  483.   n_points= uint4korr(data);
  484.   if (n_points == 1)
  485.   {
  486.     *closed=1;
  487.     return 0;
  488.   }
  489.   data+= 4;
  490.   if (no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
  491.     return 1;
  492.   /* Get first point */
  493.   get_point(&x1, &y1, data);
  494.   /* get last point */
  495.   data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE;
  496.   get_point(&x2, &y2, data);
  497.   *closed= (x1==x2) && (y1==y2);
  498.   return 0;
  499. }
  500. int Gis_line_string::num_points(uint32 *n_points) const
  501. {
  502.   *n_points= uint4korr(m_data);
  503.   return 0;
  504. }
  505. int Gis_line_string::start_point(String *result) const
  506. {
  507.   /* +4 is for skipping over number of points */
  508.   return create_point(result, m_data + 4);
  509. }
  510. int Gis_line_string::end_point(String *result) const
  511. {
  512.   uint32 n_points;
  513.   if (no_data(m_data, 4))
  514.     return 1;
  515.   n_points= uint4korr(m_data);
  516.   return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE);
  517. }
  518. int Gis_line_string::point_n(uint32 num, String *result) const
  519. {
  520.   uint32 n_points;
  521.   if (no_data(m_data, 4))
  522.     return 1;
  523.   n_points= uint4korr(m_data);
  524.   if ((uint32) (num - 1) >= n_points) // means (num > n_points || num < 1)
  525.     return 1;
  526.   return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE);
  527. }
  528. const Geometry::Class_info *Gis_line_string::get_class_info() const
  529. {
  530.   return &linestring_class;
  531. }
  532. /***************************** Polygon *******************************/
  533. uint32 Gis_polygon::get_data_size() const 
  534. {
  535.   uint32 n_linear_rings;
  536.   const char *data= m_data;
  537.   if (no_data(data, 4))
  538.     return GET_SIZE_ERROR;
  539.   n_linear_rings= uint4korr(data);
  540.   data+= 4;
  541.   while (n_linear_rings--)
  542.   {
  543.     if (no_data(data, 4))
  544.       return GET_SIZE_ERROR;
  545.     data+= 4 + uint4korr(data)*POINT_DATA_SIZE;
  546.   }
  547.   return (uint32) (data - m_data);
  548. }
  549. bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
  550. {
  551.   uint32 n_linear_rings= 0;
  552.   uint32 lr_pos= wkb->length();
  553.   int closed;
  554.   if (wkb->reserve(4, 512))
  555.     return 1;
  556.   wkb->length(wkb->length()+4); // Reserve space for points
  557.   for (;;)  
  558.   {
  559.     Gis_line_string ls;
  560.     uint32 ls_pos=wkb->length();
  561.     if (trs->check_next_symbol('(') ||
  562. ls.init_from_wkt(trs, wkb) ||
  563. trs->check_next_symbol(')'))
  564.       return 1;
  565.     ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
  566.     if (ls.is_closed(&closed) || !closed)
  567.     {
  568.       trs->set_error_msg("POLYGON's linear ring isn't closed");
  569.       return 1;
  570.     }
  571.     n_linear_rings++;
  572.     if (trs->skip_char(',')) // Didn't find ','
  573.       break;
  574.   }
  575.   wkb->write_at_position(lr_pos, n_linear_rings);
  576.   return 0;
  577. }
  578. uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
  579.                                 String *res)
  580. {
  581.   uint32 n_linear_rings;
  582.   const char *wkb_orig= wkb;
  583.   if (len < 4)
  584.     return 0;
  585.   n_linear_rings= wkb_get_uint(wkb, bo);
  586.   if (res->reserve(4, 512))
  587.     return 0;
  588.   wkb+= 4;
  589.   len-= 4;
  590.   res->q_append(n_linear_rings);
  591.   while (n_linear_rings--)
  592.   {
  593.     Gis_line_string ls;
  594.     uint32 ls_pos= res->length();
  595.     int ls_len;
  596.     int closed;
  597.     if (!(ls_len= ls.init_from_wkb(wkb, len, bo, res)))
  598.       return 0;
  599.     ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos);
  600.     if (ls.is_closed(&closed) || !closed)
  601.       return 0;
  602.     wkb+= ls_len;
  603.   }
  604.   return (uint) (wkb - wkb_orig);
  605. }
  606. bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
  607. {
  608.   uint32 n_linear_rings;
  609.   const char *data= m_data;
  610.   if (no_data(data, 4))
  611.     return 1;
  612.   n_linear_rings= uint4korr(data);
  613.   data+= 4;
  614.   while (n_linear_rings--)
  615.   {
  616.     uint32 n_points;
  617.     if (no_data(data, 4))
  618.       return 1;
  619.     n_points= uint4korr(data);
  620.     data+= 4;
  621.     if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) ||
  622. txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
  623.       return 1;
  624.     txt->qs_append('(');
  625.     data= append_points(txt, n_points, data, 0);
  626.     (*txt) [txt->length() - 1]= ')'; // Replace end ','
  627.     txt->qs_append(',');
  628.   }
  629.   txt->length(txt->length() - 1); // Remove end ','
  630.   *end= data;
  631.   return 0;
  632. }
  633. bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const
  634. {
  635.   uint32 n_linear_rings;
  636.   const char *data= m_data;
  637.   if (no_data(data, 4))
  638.     return 1;
  639.   n_linear_rings= uint4korr(data);
  640.   data+= 4;
  641.   while (n_linear_rings--)
  642.   {
  643.     if (!(data= get_mbr_for_points(mbr, data, 0)))
  644.       return 1;
  645.   }
  646.   *end= data;
  647.   return 0;
  648. }
  649. int Gis_polygon::area(double *ar, const char **end_of_data) const
  650. {
  651.   uint32 n_linear_rings;
  652.   double result= -1.0;
  653.   const char *data= m_data;
  654.   if (no_data(data, 4))
  655.     return 1;
  656.   n_linear_rings= uint4korr(data);
  657.   data+= 4;
  658.   while (n_linear_rings--)
  659.   {
  660.     double prev_x, prev_y;
  661.     double lr_area= 0;
  662.     uint32 n_points;
  663.     if (no_data(data, 4))
  664.       return 1;
  665.     n_points= uint4korr(data);
  666.     if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
  667.       return 1;
  668.     get_point(&prev_x, &prev_y, data+4);
  669.     data+= (4+SIZEOF_STORED_DOUBLE*2);
  670.     while (--n_points) // One point is already read
  671.     {
  672.       double x, y;
  673.       get_point(&x, &y, data);
  674.       data+= (SIZEOF_STORED_DOUBLE*2);
  675.       /* QQ: Is the following prev_x+x right ? */
  676.       lr_area+= (prev_x + x)* (prev_y - y);
  677.       prev_x= x;
  678.       prev_y= y;
  679.     }
  680.     lr_area= fabs(lr_area)/2;
  681.     if (result == -1.0)
  682.       result= lr_area;
  683.     else
  684.       result-= lr_area;
  685.   }
  686.   *ar= fabs(result);
  687.   *end_of_data= data;
  688.   return 0;
  689. }
  690. int Gis_polygon::exterior_ring(String *result) const
  691. {
  692.   uint32 n_points, length;
  693.   const char *data= m_data + 4; // skip n_linerings
  694.   if (no_data(data, 4))
  695.     return 1;
  696.   n_points= uint4korr(data);
  697.   data+= 4;
  698.   length= n_points * POINT_DATA_SIZE;
  699.   if (no_data(data, length) || result->reserve(1+4+4+ length))
  700.     return 1;
  701.   result->q_append((char) wkb_ndr);
  702.   result->q_append((uint32) wkb_linestring);
  703.   result->q_append(n_points);
  704.   result->q_append(data, n_points * POINT_DATA_SIZE); 
  705.   return 0;
  706. }
  707. int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const
  708. {
  709.   if (no_data(m_data, 4))
  710.     return 1;
  711.   *n_int_rings= uint4korr(m_data)-1;
  712.   return 0;
  713. }
  714. int Gis_polygon::interior_ring_n(uint32 num, String *result) const
  715. {
  716.   const char *data= m_data;
  717.   uint32 n_linear_rings;
  718.   uint32 n_points;
  719.   uint32 points_size;
  720.   if (no_data(data, 4))
  721.     return 1;
  722.   n_linear_rings= uint4korr(data);
  723.   data+= 4;
  724.   if (num >= n_linear_rings || num < 1)
  725.     return 1;
  726.   while (num--)
  727.   {
  728.     if (no_data(data, 4))
  729.       return 1;
  730.     data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
  731.   }
  732.   if (no_data(data, 4))
  733.     return 1;
  734.   n_points= uint4korr(data);
  735.   points_size= n_points * POINT_DATA_SIZE;
  736.   data+= 4;
  737.   if (no_data(data, points_size) || result->reserve(1+4+4+ points_size))
  738.     return 1;
  739.   result->q_append((char) wkb_ndr);
  740.   result->q_append((uint32) wkb_linestring);
  741.   result->q_append(n_points);
  742.   result->q_append(data, points_size); 
  743.   return 0;
  744. }
  745. int Gis_polygon::centroid_xy(double *x, double *y) const
  746. {
  747.   uint32 n_linear_rings;
  748.   double res_area;
  749.   double res_cx, res_cy;
  750.   const char *data= m_data;
  751.   bool first_loop= 1;
  752.   LINT_INIT(res_area);
  753.   LINT_INIT(res_cx);
  754.   LINT_INIT(res_cy);
  755.   if (no_data(data, 4))
  756.     return 1;
  757.   n_linear_rings= uint4korr(data);
  758.   data+= 4;
  759.   while (n_linear_rings--)
  760.   {
  761.     uint32 n_points, org_n_points;
  762.     double prev_x, prev_y;
  763.     double cur_area= 0;
  764.     double cur_cx= 0;
  765.     double cur_cy= 0;
  766.     if (no_data(data, 4))
  767.       return 1;
  768.     org_n_points= n_points= uint4korr(data);
  769.     data+= 4;
  770.     if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
  771.       return 1;
  772.     get_point(&prev_x, &prev_y, data);
  773.     data+= (SIZEOF_STORED_DOUBLE*2);
  774.     while (--n_points) // One point is already read
  775.     {
  776.       double x, y;
  777.       get_point(&x, &y, data);
  778.       data+= (SIZEOF_STORED_DOUBLE*2);
  779.       /* QQ: Is the following prev_x+x right ? */
  780.       cur_area+= (prev_x + x) * (prev_y - y);
  781.       cur_cx+= x;
  782.       cur_cy+= y;
  783.       prev_x= x;
  784.       prev_y= y;
  785.     }
  786.     cur_area= fabs(cur_area) / 2;
  787.     cur_cx= cur_cx / (org_n_points - 1);
  788.     cur_cy= cur_cy / (org_n_points - 1);
  789.     if (!first_loop)
  790.     {
  791.       double d_area= fabs(res_area - cur_area);
  792.       res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area;
  793.       res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area;
  794.     }
  795.     else
  796.     {
  797.       first_loop= 0;
  798.       res_area= cur_area;
  799.       res_cx= cur_cx;
  800.       res_cy= cur_cy;
  801.     }
  802.   }
  803.   *x= res_cx;
  804.   *y= res_cy;
  805.   return 0;
  806. }
  807. int Gis_polygon::centroid(String *result) const
  808. {
  809.   double x, y;
  810.   if (centroid_xy(&x, &y))
  811.     return 1;
  812.   return create_point(result, x, y);
  813. }
  814. const Geometry::Class_info *Gis_polygon::get_class_info() const
  815. {
  816.   return &polygon_class;
  817. }
  818. /***************************** MultiPoint *******************************/
  819. uint32 Gis_multi_point::get_data_size() const 
  820. {
  821.   if (no_data(m_data, 4))
  822.     return GET_SIZE_ERROR;
  823.   return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE);
  824. }
  825. bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
  826. {
  827.   uint32 n_points= 0;
  828.   uint32 np_pos= wkb->length();
  829.   Gis_point p;
  830.   if (wkb->reserve(4, 512))
  831.     return 1;
  832.   wkb->length(wkb->length()+4); // Reserve space for points
  833.   for (;;)
  834.   {
  835.     if (wkb->reserve(1+4, 512))
  836.       return 1;
  837.     wkb->q_append((char) wkb_ndr);
  838.     wkb->q_append((uint32) wkb_point);
  839.     if (p.init_from_wkt(trs, wkb))
  840.       return 1;
  841.     n_points++;
  842.     if (trs->skip_char(',')) // Didn't find ','
  843.       break;
  844.   }
  845.   wkb->write_at_position(np_pos, n_points); // Store number of found points
  846.   return 0;
  847. }
  848. uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
  849.                                     String *res)
  850. {
  851.   uint32 n_points;
  852.   uint proper_size;
  853.   Gis_point p;
  854.   const char *wkb_end;
  855.   if (len < 4)
  856.     return 0;
  857.   n_points= wkb_get_uint(wkb, bo);
  858.   proper_size= 4 + n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
  859.  
  860.   if (len < proper_size || res->reserve(proper_size))
  861.     return 0;
  862.     
  863.   res->q_append(n_points);
  864.   wkb_end= wkb + proper_size;
  865.   for (wkb+=4; wkb < wkb_end; wkb+= (WKB_HEADER_SIZE + POINT_DATA_SIZE))
  866.   {
  867.     res->q_append((char)wkb_ndr);
  868.     res->q_append((uint32)wkb_point);
  869.     if (!p.init_from_wkb(wkb + WKB_HEADER_SIZE,
  870.                          POINT_DATA_SIZE, (wkbByteOrder) wkb[0], res))
  871.       return 0;
  872.   }
  873.   return proper_size;
  874. }
  875. bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
  876. {
  877.   uint32 n_points;
  878.   if (no_data(m_data, 4))
  879.     return 1;
  880.   n_points= uint4korr(m_data);
  881.   if (no_data(m_data+4,
  882.       n_points * (SIZEOF_STORED_DOUBLE * 2 + WKB_HEADER_SIZE)) ||
  883.       txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
  884.     return 1;
  885.   *end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE);
  886.   txt->length(txt->length()-1); // Remove end ','
  887.   return 0;
  888. }
  889. bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const
  890. {
  891.   return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0;
  892. }
  893. int Gis_multi_point::num_geometries(uint32 *num) const
  894. {
  895.   *num= uint4korr(m_data);
  896.   return 0;
  897. }
  898. int Gis_multi_point::geometry_n(uint32 num, String *result) const
  899. {
  900.   const char *data= m_data;
  901.   uint32 n_points;
  902.   if (no_data(data, 4))
  903.     return 1;
  904.   n_points= uint4korr(data);
  905.   data+= 4+ (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
  906.   if (num > n_points || num < 1 ||
  907.       no_data(data, WKB_HEADER_SIZE + POINT_DATA_SIZE) ||
  908.       result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE))
  909.     return 1;
  910.   result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE);
  911.   return 0;
  912. }
  913. const Geometry::Class_info *Gis_multi_point::get_class_info() const
  914. {
  915.   return &multipoint_class;
  916. }
  917. /***************************** MultiLineString *******************************/
  918. uint32 Gis_multi_line_string::get_data_size() const 
  919. {
  920.   uint32 n_line_strings;
  921.   const char *data= m_data;
  922.   if (no_data(data, 4))
  923.     return GET_SIZE_ERROR;
  924.   n_line_strings= uint4korr(data);
  925.   data+= 4;
  926.   while (n_line_strings--)
  927.   {
  928.     if (no_data(data, WKB_HEADER_SIZE + 4))
  929.       return GET_SIZE_ERROR;
  930.     data+= (WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) *
  931.     POINT_DATA_SIZE);
  932.   }
  933.   return (uint32) (data - m_data);
  934. }
  935. bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
  936. {
  937.   uint32 n_line_strings= 0;
  938.   uint32 ls_pos= wkb->length();
  939.   if (wkb->reserve(4, 512))
  940.     return 1;
  941.   wkb->length(wkb->length()+4); // Reserve space for points
  942.   
  943.   for (;;)
  944.   {
  945.     Gis_line_string ls;
  946.     if (wkb->reserve(1+4, 512))
  947.       return 1;
  948.     wkb->q_append((char) wkb_ndr);
  949.     wkb->q_append((uint32) wkb_linestring);
  950.     if (trs->check_next_symbol('(') ||
  951. ls.init_from_wkt(trs, wkb) ||
  952. trs->check_next_symbol(')'))
  953.       return 1;
  954.     n_line_strings++;
  955.     if (trs->skip_char(',')) // Didn't find ','
  956.       break;
  957.   }
  958.   wkb->write_at_position(ls_pos, n_line_strings);
  959.   return 0;
  960. }
  961. uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
  962.                                           wkbByteOrder bo, String *res)
  963. {
  964.   uint32 n_line_strings;
  965.   const char *wkb_orig= wkb;
  966.   if (len < 4)
  967.     return 0;
  968.   n_line_strings= wkb_get_uint(wkb, bo);
  969.   if (res->reserve(4, 512))
  970.     return 0;
  971.   res->q_append(n_line_strings);
  972.   
  973.   wkb+= 4;
  974.   while (n_line_strings--)
  975.   {
  976.     Gis_line_string ls;
  977.     int ls_len;
  978.     if ((len < WKB_HEADER_SIZE) ||
  979.         res->reserve(WKB_HEADER_SIZE, 512))
  980.       return 0;
  981.     res->q_append((char) wkb_ndr);
  982.     res->q_append((uint32) wkb_linestring);
  983.     if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
  984.                                    (wkbByteOrder) wkb[0], res)))
  985.       return 0;
  986.     ls_len+= WKB_HEADER_SIZE;;
  987.     wkb+= ls_len;
  988.     len-= ls_len;
  989.   }
  990.   return (uint) (wkb - wkb_orig);
  991. }
  992. bool Gis_multi_line_string::get_data_as_wkt(String *txt, 
  993.      const char **end) const
  994. {
  995.   uint32 n_line_strings;
  996.   const char *data= m_data;
  997.   if (no_data(data, 4))
  998.     return 1;
  999.   n_line_strings= uint4korr(data);
  1000.   data+= 4;
  1001.   while (n_line_strings--)
  1002.   {
  1003.     uint32 n_points;
  1004.     if (no_data(data, (WKB_HEADER_SIZE + 4)))
  1005.       return 1;
  1006.     n_points= uint4korr(data + WKB_HEADER_SIZE);
  1007.     data+= WKB_HEADER_SIZE + 4;
  1008.     if (no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) ||
  1009. txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
  1010.       return 1;
  1011.     txt->qs_append('(');
  1012.     data= append_points(txt, n_points, data, 0);
  1013.     (*txt) [txt->length() - 1]= ')';
  1014.     txt->qs_append(',');
  1015.   }
  1016.   txt->length(txt->length() - 1);
  1017.   *end= data;
  1018.   return 0;
  1019. }
  1020. bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const
  1021. {
  1022.   uint32 n_line_strings;
  1023.   const char *data= m_data;
  1024.   if (no_data(data, 4))
  1025.     return 1;
  1026.   n_line_strings= uint4korr(data);
  1027.   data+= 4;
  1028.   while (n_line_strings--)
  1029.   {
  1030.     data+= WKB_HEADER_SIZE;
  1031.     if (!(data= get_mbr_for_points(mbr, data, 0)))
  1032.       return 1;
  1033.   }
  1034.   *end= data;
  1035.   return 0;
  1036. }
  1037. int Gis_multi_line_string::num_geometries(uint32 *num) const
  1038. {
  1039.   *num= uint4korr(m_data);
  1040.   return 0;
  1041. }
  1042. int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
  1043. {
  1044.   uint32 n_line_strings, n_points, length;
  1045.   const char *data= m_data;
  1046.   if (no_data(data, 4))
  1047.     return 1;
  1048.   n_line_strings= uint4korr(data);
  1049.   data+= 4;
  1050.   if ((num > n_line_strings) || (num < 1))
  1051.     return 1;
  1052.  
  1053.   for (;;)
  1054.   {
  1055.     if (no_data(data, WKB_HEADER_SIZE + 4))
  1056.       return 1;
  1057.     n_points= uint4korr(data + WKB_HEADER_SIZE);
  1058.     length= WKB_HEADER_SIZE + 4+ POINT_DATA_SIZE * n_points;
  1059.     if (no_data(data, length))
  1060.       return 1;
  1061.     if (!--num)
  1062.       break;
  1063.     data+= length;
  1064.   }
  1065.   return result->append(data, length, (uint32) 0);
  1066. }
  1067. int Gis_multi_line_string::length(double *len) const
  1068. {
  1069.   uint32 n_line_strings;
  1070.   const char *data= m_data;
  1071.   if (no_data(data, 4))
  1072.     return 1;
  1073.   n_line_strings= uint4korr(data);
  1074.   data+= 4;
  1075.   *len=0;
  1076.   while (n_line_strings--)
  1077.   {
  1078.     double ls_len;
  1079.     Gis_line_string ls;
  1080.     data+= WKB_HEADER_SIZE;
  1081.     ls.set_data_ptr(data, (uint32) (m_data_end - data));
  1082.     if (ls.length(&ls_len))
  1083.       return 1;
  1084.     *len+= ls_len;
  1085.     /*
  1086.       We know here that ls was ok, so we can call the trivial function
  1087.       Gis_line_string::get_data_size without error checking
  1088.     */
  1089.     data+= ls.get_data_size();
  1090.   }
  1091.   return 0;
  1092. }
  1093. int Gis_multi_line_string::is_closed(int *closed) const
  1094. {
  1095.   uint32 n_line_strings;
  1096.   const char *data= m_data;
  1097.   if (no_data(data, 4 + WKB_HEADER_SIZE))
  1098.     return 1;
  1099.   n_line_strings= uint4korr(data);
  1100.   data+= 4 + WKB_HEADER_SIZE;
  1101.   while (n_line_strings--)
  1102.   {
  1103.     Gis_line_string ls;
  1104.     if (no_data(data, 0))
  1105.       return 1;
  1106.     ls.set_data_ptr(data, (uint32) (m_data_end - data));
  1107.     if (ls.is_closed(closed))
  1108.       return 1;
  1109.     if (!*closed)
  1110.       return 0;
  1111.     /*
  1112.       We know here that ls was ok, so we can call the trivial function
  1113.       Gis_line_string::get_data_size without error checking
  1114.     */
  1115.     data+= ls.get_data_size() + WKB_HEADER_SIZE;
  1116.   }
  1117.   return 0;
  1118. }
  1119. const Geometry::Class_info *Gis_multi_line_string::get_class_info() const
  1120. {
  1121.   return &multilinestring_class;
  1122. }
  1123. /***************************** MultiPolygon *******************************/
  1124. uint32 Gis_multi_polygon::get_data_size() const 
  1125. {
  1126.   uint32 n_polygons;
  1127.   const char *data= m_data;
  1128.   if (no_data(data, 4))
  1129.     return GET_SIZE_ERROR;
  1130.   n_polygons= uint4korr(data);
  1131.   data+= 4;
  1132.   while (n_polygons--)
  1133.   {
  1134.     uint32 n_linear_rings;
  1135.     if (no_data(data, 4 + WKB_HEADER_SIZE))
  1136.       return GET_SIZE_ERROR;
  1137.     n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
  1138.     data+= 4 + WKB_HEADER_SIZE;
  1139.     while (n_linear_rings--)
  1140.     {
  1141.       if (no_data(data, 4))
  1142. return GET_SIZE_ERROR;
  1143.       data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
  1144.     }
  1145.   }
  1146.   return (uint32) (data - m_data);
  1147. }
  1148. bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
  1149. {
  1150.   uint32 n_polygons= 0;
  1151.   int np_pos= wkb->length();
  1152.   Gis_polygon p;
  1153.   if (wkb->reserve(4, 512))
  1154.     return 1;
  1155.   wkb->length(wkb->length()+4); // Reserve space for points
  1156.   for (;;)  
  1157.   {
  1158.     if (wkb->reserve(1+4, 512))
  1159.       return 1;
  1160.     wkb->q_append((char) wkb_ndr);
  1161.     wkb->q_append((uint32) wkb_polygon);
  1162.     if (trs->check_next_symbol('(') ||
  1163. p.init_from_wkt(trs, wkb) ||
  1164. trs->check_next_symbol(')'))
  1165.       return 1;
  1166.     n_polygons++;
  1167.     if (trs->skip_char(',')) // Didn't find ','
  1168.       break;
  1169.   }
  1170.   wkb->write_at_position(np_pos, n_polygons);
  1171.   return 0;
  1172. }
  1173. uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
  1174.                                       wkbByteOrder bo, String *res)
  1175. {
  1176.   uint32 n_poly;
  1177.   const char *wkb_orig= wkb;
  1178.   if (len < 4)
  1179.     return 0;
  1180.   n_poly= wkb_get_uint(wkb, bo);
  1181.   if (res->reserve(4, 512))
  1182.     return 0;
  1183.   res->q_append(n_poly);
  1184.   
  1185.   wkb+=4;
  1186.   while (n_poly--)
  1187.   {
  1188.     Gis_polygon p;
  1189.     int p_len;
  1190.     if (len < WKB_HEADER_SIZE ||
  1191.         res->reserve(WKB_HEADER_SIZE, 512))
  1192.       return 0;
  1193.     res->q_append((char) wkb_ndr);
  1194.     res->q_append((uint32) wkb_polygon);
  1195.     if (!(p_len= p.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
  1196.                                  (wkbByteOrder) wkb[0], res)))
  1197.       return 0;
  1198.     p_len+= WKB_HEADER_SIZE;
  1199.     wkb+= p_len;
  1200.     len-= p_len;
  1201.   }
  1202.   return (uint) (wkb - wkb_orig);
  1203. }
  1204. bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
  1205. {
  1206.   uint32 n_polygons;
  1207.   const char *data= m_data;
  1208.   if (no_data(data, 4))
  1209.     return 1;
  1210.   n_polygons= uint4korr(data);
  1211.   data+= 4;
  1212.   while (n_polygons--)
  1213.   {
  1214.     uint32 n_linear_rings;
  1215.     if (no_data(data, 4 + WKB_HEADER_SIZE) ||
  1216. txt->reserve(1, 512))
  1217.       return 1;
  1218.     n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
  1219.     data+= 4 + WKB_HEADER_SIZE;
  1220.     txt->q_append('(');
  1221.     while (n_linear_rings--)
  1222.     {
  1223.       if (no_data(data, 4))
  1224.         return 1;
  1225.       uint32 n_points= uint4korr(data);
  1226.       data+= 4;
  1227.       if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) ||
  1228.   txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
  1229.        512))
  1230. return 1;
  1231.       txt->qs_append('(');
  1232.       data= append_points(txt, n_points, data, 0);
  1233.       (*txt) [txt->length() - 1]= ')';
  1234.       txt->qs_append(',');
  1235.     }
  1236.     (*txt) [txt->length() - 1]= ')';
  1237.     txt->qs_append(',');
  1238.   }
  1239.   txt->length(txt->length() - 1);
  1240.   *end= data;
  1241.   return 0;
  1242. }
  1243. bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const
  1244. {
  1245.   uint32 n_polygons;
  1246.   const char *data= m_data;
  1247.   if (no_data(data, 4))
  1248.     return 1;
  1249.   n_polygons= uint4korr(data);
  1250.   data+= 4;
  1251.   while (n_polygons--)
  1252.   {
  1253.     uint32 n_linear_rings;
  1254.     if (no_data(data, 4+WKB_HEADER_SIZE))
  1255.       return 1;
  1256.     n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
  1257.     data+= WKB_HEADER_SIZE + 4;
  1258.     while (n_linear_rings--)
  1259.     {
  1260.       if (!(data= get_mbr_for_points(mbr, data, 0)))
  1261. return 1;
  1262.     }
  1263.   }
  1264.   *end= data;
  1265.   return 0;
  1266. }
  1267. int Gis_multi_polygon::num_geometries(uint32 *num) const
  1268. {
  1269.   *num= uint4korr(m_data);
  1270.   return 0;
  1271. }
  1272. int Gis_multi_polygon::geometry_n(uint32 num, String *result) const
  1273. {
  1274.   uint32 n_polygons;
  1275.   const char *data= m_data, *start_of_polygon;
  1276.   if (no_data(data, 4))
  1277.     return 1;
  1278.   n_polygons= uint4korr(data);
  1279.   data+= 4;
  1280.   if (num > n_polygons || num < 1)
  1281.     return -1;
  1282.   do
  1283.   {
  1284.     uint32 n_linear_rings;
  1285.     start_of_polygon= data;
  1286.     if (no_data(data, WKB_HEADER_SIZE + 4))
  1287.       return 1;
  1288.     n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
  1289.     data+= WKB_HEADER_SIZE + 4;
  1290.     while (n_linear_rings--)
  1291.     {
  1292.       uint32 n_points;
  1293.       if (no_data(data, 4))
  1294. return 1;
  1295.       n_points= uint4korr(data);
  1296.       data+= 4 + POINT_DATA_SIZE * n_points;
  1297.     }
  1298.   } while (--num);
  1299.   if (no_data(data, 0)) // We must check last segment
  1300.     return 1;
  1301.   return result->append(start_of_polygon, (uint32) (data - start_of_polygon),
  1302. (uint32) 0);
  1303. }
  1304. int Gis_multi_polygon::area(double *ar,  const char **end_of_data) const
  1305. {
  1306.   uint32 n_polygons;
  1307.   const char *data= m_data;
  1308.   double result= 0;
  1309.   if (no_data(data, 4))
  1310.     return 1;
  1311.   n_polygons= uint4korr(data);
  1312.   data+= 4;
  1313.   while (n_polygons--)
  1314.   {
  1315.     double p_area;
  1316.     Gis_polygon p;
  1317.     data+= WKB_HEADER_SIZE;
  1318.     p.set_data_ptr(data, (uint32) (m_data_end - data));
  1319.     if (p.area(&p_area, &data))
  1320.       return 1;
  1321.     result+= p_area;
  1322.   }
  1323.   *ar= result;
  1324.   *end_of_data= data;
  1325.   return 0;
  1326. }
  1327. int Gis_multi_polygon::centroid(String *result) const
  1328. {
  1329.   uint32 n_polygons;
  1330.   bool first_loop= 1;
  1331.   Gis_polygon p;
  1332.   double res_area, res_cx, res_cy;
  1333.   double cur_area, cur_cx, cur_cy;
  1334.   const char *data= m_data;
  1335.   LINT_INIT(res_area);
  1336.   LINT_INIT(res_cx);
  1337.   LINT_INIT(res_cy);
  1338.   if (no_data(data, 4))
  1339.     return 1;
  1340.   n_polygons= uint4korr(data);
  1341.   data+= 4;
  1342.   while (n_polygons--)
  1343.   {
  1344.     data+= WKB_HEADER_SIZE;
  1345.     p.set_data_ptr(data, (uint32) (m_data_end - data));
  1346.     if (p.area(&cur_area, &data) ||
  1347. p.centroid_xy(&cur_cx, &cur_cy))
  1348.       return 1;
  1349.     if (!first_loop)
  1350.     {
  1351.       double sum_area= res_area + cur_area;
  1352.       res_cx= (res_area * res_cx + cur_area * cur_cx) / sum_area;
  1353.       res_cy= (res_area * res_cy + cur_area * cur_cy) / sum_area;
  1354.     }
  1355.     else
  1356.     {
  1357.       first_loop= 0;
  1358.       res_area= cur_area;
  1359.       res_cx= cur_cx;
  1360.       res_cy= cur_cy;
  1361.     }
  1362.   }
  1363.   return create_point(result, res_cx, res_cy);
  1364. }
  1365. const Geometry::Class_info *Gis_multi_polygon::get_class_info() const
  1366. {
  1367.   return &multipolygon_class;
  1368. }
  1369. /************************* GeometryCollection ****************************/
  1370. uint32 Gis_geometry_collection::get_data_size() const 
  1371. {
  1372.   uint32 n_objects;
  1373.   const char *data= m_data;
  1374.   Geometry_buffer buffer;
  1375.   Geometry *geom;
  1376.   if (no_data(data, 4))
  1377.     return GET_SIZE_ERROR;
  1378.   n_objects= uint4korr(data);
  1379.   data+= 4;
  1380.   while (n_objects--)
  1381.   {
  1382.     uint32 wkb_type,object_size;
  1383.     if (no_data(data, WKB_HEADER_SIZE))
  1384.       return GET_SIZE_ERROR;
  1385.     wkb_type= uint4korr(data + 1);
  1386.     data+= WKB_HEADER_SIZE;
  1387.     if (!(geom= create_by_typeid(&buffer, wkb_type)))
  1388.       return GET_SIZE_ERROR;
  1389.     geom->set_data_ptr(data, (uint) (m_data_end - data));
  1390.     if ((object_size= geom->get_data_size()) == GET_SIZE_ERROR)
  1391.       return GET_SIZE_ERROR;
  1392.     data+= object_size;
  1393.   }
  1394.   return (uint32) (data - m_data);
  1395. }
  1396. bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
  1397. {
  1398.   uint32 n_objects= 0;
  1399.   uint32 no_pos= wkb->length();
  1400.   Geometry_buffer buffer;
  1401.   Geometry *g;
  1402.   if (wkb->reserve(4, 512))
  1403.     return 1;
  1404.   wkb->length(wkb->length()+4); // Reserve space for points
  1405.   for (;;)
  1406.   {
  1407.     if (!(g= create_from_wkt(&buffer, trs, wkb)))
  1408.       return 1;
  1409.     if (g->get_class_info()->m_type_id == wkb_geometrycollection)
  1410.     {
  1411.       trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
  1412.       return 1;
  1413.     }
  1414.     n_objects++;
  1415.     if (trs->skip_char(',')) // Didn't find ','
  1416.       break;
  1417.   }
  1418.   wkb->write_at_position(no_pos, n_objects);
  1419.   return 0;
  1420. }
  1421. uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
  1422.                                             wkbByteOrder bo, String *res)
  1423. {
  1424.   uint32 n_geom;
  1425.   const char *wkb_orig= wkb;
  1426.   if (len < 4)
  1427.     return 0;
  1428.   n_geom= wkb_get_uint(wkb, bo);
  1429.   if (res->reserve(4, 512))
  1430.     return 0;
  1431.   res->q_append(n_geom);
  1432.   
  1433.   wkb+= 4;
  1434.   while (n_geom--)
  1435.   {
  1436.     Geometry_buffer buffer;
  1437.     Geometry *geom;
  1438.     int g_len;
  1439.     uint32 wkb_type;
  1440.     if (len < WKB_HEADER_SIZE ||
  1441.         res->reserve(WKB_HEADER_SIZE, 512))
  1442.       return 0;
  1443.     res->q_append((char) wkb_ndr);
  1444.     wkb_type= wkb_get_uint(wkb+1, (wkbByteOrder) wkb[0]);
  1445.     res->q_append(wkb_type);
  1446.     if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
  1447.         !(g_len= geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len,
  1448.                                      (wkbByteOrder)  wkb[0], res)))
  1449.       return 0;
  1450.     g_len+= WKB_HEADER_SIZE;
  1451.     wkb+= g_len;
  1452.     len-= g_len;
  1453.   }
  1454.   return (uint) (wkb - wkb_orig);
  1455. }
  1456. bool Gis_geometry_collection::get_data_as_wkt(String *txt,
  1457.      const char **end) const
  1458. {
  1459.   uint32 n_objects;
  1460.   Geometry_buffer buffer;
  1461.   Geometry *geom;
  1462.   const char *data= m_data;
  1463.   if (no_data(data, 4))
  1464.     return 1;
  1465.   n_objects= uint4korr(data);
  1466.   data+= 4;
  1467.   while (n_objects--)
  1468.   {
  1469.     uint32 wkb_type;
  1470.     if (no_data(data, WKB_HEADER_SIZE))
  1471.       return 1;
  1472.     wkb_type= uint4korr(data + 1);
  1473.     data+= WKB_HEADER_SIZE;
  1474.     if (!(geom= create_by_typeid(&buffer, wkb_type)))
  1475.       return 1;
  1476.     geom->set_data_ptr(data, (uint) (m_data_end - data));
  1477.     if (geom->as_wkt(txt, &data))
  1478.       return 1;
  1479.     if (txt->append(",", 1, 512))
  1480.       return 1;
  1481.   }
  1482.   txt->length(txt->length() - 1);
  1483.   *end= data;
  1484.   return 0;
  1485. }
  1486. bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
  1487. {
  1488.   uint32 n_objects;
  1489.   const char *data= m_data;
  1490.   Geometry_buffer buffer;
  1491.   Geometry *geom;
  1492.   if (no_data(data, 4))
  1493.     return 1;
  1494.   n_objects= uint4korr(data);
  1495.   data+= 4;
  1496.   while (n_objects--)
  1497.   {
  1498.     uint32 wkb_type;
  1499.     if (no_data(data, WKB_HEADER_SIZE))
  1500.       return 1;
  1501.     wkb_type= uint4korr(data + 1);
  1502.     data+= WKB_HEADER_SIZE;
  1503.     if (!(geom= create_by_typeid(&buffer, wkb_type)))
  1504.       return 1;
  1505.     geom->set_data_ptr(data, (uint32) (m_data_end - data));
  1506.     if (geom->get_mbr(mbr, &data))
  1507.       return 1;
  1508.   }
  1509.   *end= data;
  1510.   return 0;
  1511. }
  1512. int Gis_geometry_collection::num_geometries(uint32 *num) const
  1513. {
  1514.   if (no_data(m_data, 4))
  1515.     return 1;
  1516.   *num= uint4korr(m_data);
  1517.   return 0;
  1518. }
  1519. int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
  1520. {
  1521.   uint32 n_objects, wkb_type, length;
  1522.   const char *data= m_data;
  1523.   Geometry_buffer buffer;
  1524.   Geometry *geom;
  1525.   if (no_data(data, 4))
  1526.     return 1;
  1527.   n_objects= uint4korr(data);
  1528.   data+= 4;
  1529.   if (num > n_objects || num < 1)
  1530.     return 1;
  1531.   do
  1532.   {
  1533.     if (no_data(data, WKB_HEADER_SIZE))
  1534.       return 1;
  1535.     wkb_type= uint4korr(data + 1);
  1536.     data+= WKB_HEADER_SIZE;
  1537.     if (!(geom= create_by_typeid(&buffer, wkb_type)))
  1538.       return 1;
  1539.     geom->set_data_ptr(data, (uint) (m_data_end - data));
  1540.     if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
  1541.       return 1;
  1542.     data+= length;
  1543.   } while (--num);
  1544.   /* Copy found object to result */
  1545.   if (result->reserve(1+4+length))
  1546.     return 1;
  1547.   result->q_append((char) wkb_ndr);
  1548.   result->q_append((uint32) wkb_type);
  1549.   result->q_append(data-length, length); // data-length = start_of_data
  1550.   return 0;
  1551. }
  1552. /*
  1553.   Return dimension for object
  1554.   SYNOPSIS
  1555.     dimension()
  1556.     res_dim Result dimension
  1557.     end End of object will be stored here. May be 0 for
  1558. simple objects!
  1559.   RETURN
  1560.     0 ok
  1561.     1 error
  1562. */
  1563. bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
  1564. {
  1565.   uint32 n_objects;
  1566.   const char *data= m_data;
  1567.   Geometry_buffer buffer;
  1568.   Geometry *geom;
  1569.   if (no_data(data, 4))
  1570.     return 1;
  1571.   n_objects= uint4korr(data);
  1572.   data+= 4;
  1573.   *res_dim= 0;
  1574.   while (n_objects--)
  1575.   {
  1576.     uint32 wkb_type, length, dim;
  1577.     const char *end_data;
  1578.     if (no_data(data, WKB_HEADER_SIZE))
  1579.       return 1;
  1580.     wkb_type= uint4korr(data + 1);
  1581.     data+= WKB_HEADER_SIZE;
  1582.     if (!(geom= create_by_typeid(&buffer, wkb_type)))
  1583.       return 1;
  1584.     geom->set_data_ptr(data, (uint32) (m_data_end - data));
  1585.     if (geom->dimension(&dim, &end_data))
  1586.       return 1;
  1587.     set_if_bigger(*res_dim, dim);
  1588.     if (end_data) // Complex object
  1589.       data= end_data;
  1590.     else if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
  1591.       return 1;
  1592.     else
  1593.       data+= length;
  1594.   }
  1595.   *end= data;
  1596.   return 0;
  1597. }
  1598. const Geometry::Class_info *Gis_geometry_collection::get_class_info() const
  1599. {
  1600.   return &geometrycollection_class;
  1601. }
  1602. #endif /*HAVE_SPATIAL*/