spatial.cc   spatial.cc 
/* /*
Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reser ved. Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reser ved.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
skipping to change at line 128 skipping to change at line 128
static Geometry::Class_info static Geometry::Class_info
multilinestring_class("MULTILINESTRING", multilinestring_class("MULTILINESTRING",
Geometry::wkb_multilinestring, create_multilinestring) ; Geometry::wkb_multilinestring, create_multilinestring) ;
static Geometry::Class_info multipolygon_class("MULTIPOLYGON", static Geometry::Class_info multipolygon_class("MULTIPOLYGON",
Geometry::wkb_multipolygo n, Geometry::wkb_multipolygo n,
create_multipolygon); create_multipolygon);
static Geometry::Class_info static Geometry::Class_info
geometrycollection_class("GEOMETRYCOLLECTION",Geometry::wkb_geometrycollect ion, geometrycollection_class("GEOMETRYCOLLECTION",Geometry::wkb_geometrycollect ion,
create_geometrycollection); create_geometrycollection);
static void get_point(double *x, double *y, const char *data)
{
float8get(*x, data);
float8get(*y, data + SIZEOF_STORED_DOUBLE);
}
/***************************** Geometry *******************************/ /***************************** Geometry *******************************/
Geometry::Class_info *Geometry::find_class(const char *name, uint32 len) Geometry::Class_info *Geometry::find_class(const char *name, uint32 len)
{ {
for (Class_info **cur_rt= ci_collection; for (Class_info **cur_rt= ci_collection;
cur_rt < ci_collection_end; cur_rt++) cur_rt < ci_collection_end; cur_rt++)
{ {
if (*cur_rt && if (*cur_rt &&
((*cur_rt)->m_name.length == len) && ((*cur_rt)->m_name.length == len) &&
(my_strnncoll(&my_charset_latin1, (my_strnncoll(&my_charset_latin1,
skipping to change at line 171 skipping to change at line 165
{ {
uint32 geom_type; uint32 geom_type;
Geometry *result; Geometry *result;
if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4) if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4)
return NULL; return NULL;
/* + 1 to skip the byte order (stored in position SRID_SIZE). */ /* + 1 to skip the byte order (stored in position SRID_SIZE). */
geom_type= uint4korr(data + SRID_SIZE + 1); geom_type= uint4korr(data + SRID_SIZE + 1);
if (!(result= create_by_typeid(buffer, (int) geom_type))) if (!(result= create_by_typeid(buffer, (int) geom_type)))
return NULL; return NULL;
result->m_data= data+ SRID_SIZE + WKB_HEADER_SIZE; result->set_data_ptr(data + SRID_SIZE + WKB_HEADER_SIZE,
result->m_data_end= data + data_len; data_len - SRID_SIZE - WKB_HEADER_SIZE);
return result; return result;
} }
Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer, Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
Gis_read_stream *trs, String *wkt, Gis_read_stream *trs, String *wkt,
bool init_stream) bool init_stream)
{ {
LEX_STRING name; LEX_STRING name;
Class_info *ci; Class_info *ci;
if (trs->get_next_word(&name)) if (trs->get_next_word(&name))
{ {
trs->set_error_msg("Geometry name expected"); trs->set_error_msg("Geometry name expected");
return NULL; return NULL;
} }
if (!(ci= find_class(name.str, name.length)) || if (!(ci= find_class(name.str, name.length)) ||
wkt->reserve(1 + 4, 512)) wkt->reserve(WKB_HEADER_SIZE, 512))
return NULL; return NULL;
Geometry *result= (*ci->m_create_func)(buffer->data); Geometry *result= (*ci->m_create_func)(buffer->data);
wkt->q_append((char) wkb_ndr); wkt->q_append((char) wkb_ndr);
wkt->q_append((uint32) result->get_class_info()->m_type_id); wkt->q_append((uint32) result->get_class_info()->m_type_id);
if (trs->check_next_symbol('(') || if (trs->check_next_symbol('(') ||
result->init_from_wkt(trs, wkt) || result->init_from_wkt(trs, wkt) ||
trs->check_next_symbol(')')) trs->check_next_symbol(')'))
return NULL; return NULL;
if (init_stream) if (init_stream)
{ result->set_data_ptr(wkt->ptr() + WKB_HEADER_SIZE,
result->set_data_ptr(wkt->ptr(), wkt->length()); wkt->length() - WKB_HEADER_SIZE);
result->shift_wkb_header();
}
return result; return result;
} }
static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo) static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
{ {
double res; double res;
if (bo != Geometry::wkb_xdr) if (bo != Geometry::wkb_xdr)
{ {
float8get(res, ptr); float8get(res, ptr);
} }
skipping to change at line 281 skipping to change at line 273
return 1; return 1;
res->q_append((char) wkb_ndr); res->q_append((char) wkb_ndr);
res->q_append(geom_type); res->q_append(geom_type);
return obj->init_from_opresult(res, rr.result(), rr.length()); return obj->init_from_opresult(res, rr.result(), rr.length());
} }
bool Geometry::envelope(String *result) const bool Geometry::envelope(String *result) const
{ {
MBR mbr; MBR mbr;
const char *end; wkb_parser wkb(&m_wkb_data);
if (get_mbr(&mbr, &end) || if (get_mbr(&mbr, &wkb) ||
result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10)) result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10))
return 1; return true;
result->q_append((char) wkb_ndr); result->q_append((char) wkb_ndr);
result->q_append((uint32) wkb_polygon); result->q_append((uint32) wkb_polygon);
result->q_append((uint32) 1); result->q_append((uint32) 1);
result->q_append((uint32) 5); result->q_append((uint32) 5);
result->q_append(mbr.xmin); result->q_append(mbr.xmin);
result->q_append(mbr.ymin); result->q_append(mbr.ymin);
result->q_append(mbr.xmax); result->q_append(mbr.xmax);
result->q_append(mbr.ymin); result->q_append(mbr.ymin);
result->q_append(mbr.xmax); result->q_append(mbr.xmax);
result->q_append(mbr.ymax); result->q_append(mbr.ymax);
result->q_append(mbr.xmin); result->q_append(mbr.xmin);
result->q_append(mbr.ymax); result->q_append(mbr.ymax);
result->q_append(mbr.xmin); result->q_append(mbr.xmin);
result->q_append(mbr.ymin); result->q_append(mbr.ymin);
return 0; return false;
} }
/* /**
Create a point from data. Create a point from data.
SYNPOSIS @param OUT result Put result here
create_point() @param wkb Data for point is here.
result Put result here
data Data for point is here.
RETURN @return false on success, true on error
0 ok
1 Can't reallocate 'result'
*/ */
bool Geometry::create_point(String *result, const char *data) const bool Geometry::create_point(String *result, wkb_parser *wkb) const
{ {
if (no_data(data, POINT_DATA_SIZE) || if (wkb->no_data(POINT_DATA_SIZE) ||
result->reserve(1 + 4 + POINT_DATA_SIZE)) result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE))
return 1; return true;
result->q_append((char) wkb_ndr); result->q_append((char) wkb_ndr);
result->q_append((uint32) wkb_point); result->q_append((uint32) wkb_point);
/* Copy two double in same format */ /* Copy two double in same format */
result->q_append(data, POINT_DATA_SIZE); result->q_append(wkb->data(), POINT_DATA_SIZE);
return 0; return false;
} }
/* /**
Create a point from coordinates. Create a point from coordinates.
SYNPOSIS @param OUT result
create_point() @param x x coordinate for point
result Put result here @param y y coordinate for point
x x coordinate for point
y y coordinate for point
RETURN @return false on success, true on error
0 ok
1 Can't reallocate 'result'
*/ */
bool Geometry::create_point(String *result, double x, double y) const bool Geometry::create_point(String *result, point_xy p) const
{ {
if (result->reserve(1 + 4 + POINT_DATA_SIZE)) if (result->reserve(1 + 4 + POINT_DATA_SIZE))
return 1; return true;
result->q_append((char) wkb_ndr); result->q_append((char) wkb_ndr);
result->q_append((uint32) wkb_point); result->q_append((uint32) wkb_point);
result->q_append(x); result->q_append(p.x);
result->q_append(y); result->q_append(p.y);
return 0; return false;
} }
/* /**
Append N points from packed format to text Append N points from packed format to text
SYNOPSIS @param OUT txt Append points here
append_points() @param n_points Number of points
txt Append points here @param wkb Packed data
n_points Number of points @param offset Offset between points
data Packed data
offset Offset between points
RETURN
# end of data
*/ */
const char *Geometry::append_points(String *txt, uint32 n_points, void Geometry::append_points(String *txt, uint32 n_points,
const char *data, uint32 offset) const wkb_parser *wkb, uint32 offset) const
{ {
while (n_points--) while (n_points--)
{ {
double x,y; point_xy p;
data+= offset; wkb->skip_unsafe(offset);
get_point(&x, &y, data); wkb->scan_xy_unsafe(&p);
data+= POINT_DATA_SIZE; txt->qs_append(p.x);
txt->qs_append(x);
txt->qs_append(' '); txt->qs_append(' ');
txt->qs_append(y); txt->qs_append(p.y);
txt->qs_append(','); txt->qs_append(',');
} }
return data;
} }
/* /**
Get most bounding rectangle (mbr) for X points Get most bounding rectangle (mbr) for X points
SYNOPSIS @param OUT mbr Result
get_mbr_for_points() @param wkb Data for point is here.
mbr MBR (store rectangle here) @param offset Offset between points
points Number of points
data Packed data
offset Offset between points
RETURN @return false on success, true on error
0 Wrong data
# end of data
*/ */
const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, bool Geometry::get_mbr_for_points(MBR *mbr, wkb_parser *wkb,
uint offset) const uint offset) const
{ {
uint32 points; uint32 n_points;
/* read number of points */
if (no_data(data, 4))
return 0;
points= uint4korr(data);
data+= 4;
if (no_data(data, (POINT_DATA_SIZE + offset) * points)) if (wkb->scan_n_points_and_check_data(&n_points, offset))
return 0; return true;
/* Calculate MBR for points */ /* Calculate MBR for points */
while (points--) while (n_points--)
{ {
data+= offset; wkb->skip_unsafe(offset);
mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE); mbr->add_xy(wkb->data(), wkb->data() + SIZEOF_STORED_DOUBLE);
data+= POINT_DATA_SIZE; wkb->skip_unsafe(POINT_DATA_SIZE);
} }
return data; return false;
} }
int Geometry::collection_store_shapes(Gcalc_shape_transporter *trn, int Geometry::collection_store_shapes(Gcalc_shape_transporter *trn,
Gcalc_shape_status *st, Gcalc_shape_status *st,
Geometry *collection_item) const Geometry *collection_item) const
{ {
uint32 n_objects; uint32 n_objects;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
Geometry_buffer buffer; Geometry_buffer buffer;
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_objects) ||
return 1; trn->start_collection(st, n_objects))
n_objects= uint4korr(data);
data+= 4;
if (trn->start_collection(st, n_objects))
return 1; return 1;
while (n_objects--) while (n_objects--)
{ {
if (no_data(data, WKB_HEADER_SIZE))
return 1;
Geometry *geom; Geometry *geom;
if (!(geom= collection_item)) if (!(geom= collection_item))
{ {
/* /*
Item type is not known in advance, e.g. GeometryCollection. Item type is not known in advance, e.g. GeometryCollection.
Create an item object in every iteration, Create an item object in every iteration,
according to the current wkb type. according to the current wkb type.
*/ */
uint32 wkb_type= uint4korr(data + 1); if (!(geom= scan_header_and_create(&wkb, &buffer)))
if (!(geom= create_by_typeid(&buffer, wkb_type))) return 1;
}
else
{
if (wkb.skip_wkb_header())
return 1; return 1;
geom->set_data_ptr(&wkb);
} }
data+= WKB_HEADER_SIZE;
geom->set_data_ptr(data, (uint32) (m_data_end - data));
Gcalc_shape_status item_status; Gcalc_shape_status item_status;
if (geom->store_shapes(trn, &item_status)) if (geom->store_shapes(trn, &item_status) ||
return 1; trn->collection_add_item(st, &item_status))
if (trn->collection_add_item(st, &item_status))
return 1; return 1;
data+= geom->get_data_size(); wkb.skip_unsafe(geom->get_data_size());
} }
trn->complete_collection(st); trn->complete_collection(st);
return 0; return 0;
} }
int Geometry::collection_area(double *ar, const char **end_of_data, bool Geometry::collection_area(double *ar, wkb_parser *wkb,
Geometry *collection_item) const Geometry *collection_item) const
{ {
uint32 n_objects; uint32 n_objects;
const char *data= m_data;
Geometry_buffer buffer; Geometry_buffer buffer;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_objects))
return 1; return true;
n_objects= uint4korr(data);
data+= 4;
for (*ar= 0; n_objects; n_objects--) for (*ar= 0; n_objects; n_objects--)
{ {
if (no_data(data, WKB_HEADER_SIZE))
return 1;
Geometry *geom; Geometry *geom;
if (!(geom= collection_item)) if (!(geom= collection_item))
{ {
/* /*
Item type is not known in advance, e.g. GeometryCollection. Item type is not known in advance, e.g. GeometryCollection.
Create an item object according to the wkb type. Create an item object according to the wkb type.
*/ */
uint32 wkb_type= uint4korr(data + 1); if (!(geom= scan_header_and_create(wkb, &buffer)))
if (!(geom= create_by_typeid(&buffer, wkb_type))) return true;
return 1; }
else
{
if (wkb->skip_wkb_header())
return true;
geom->set_data_ptr(wkb);
} }
data+= WKB_HEADER_SIZE;
geom->set_data_ptr(data, (uint32) (m_data_end - data));
double item_area; double item_area;
if (geom->area(&item_area, &data)) if (geom->area(&item_area, wkb))
return 1; return true;
*ar+= item_area; *ar+= item_area;
} }
*end_of_data= data; return false;
return 0;
} }
uint Geometry::collection_init_from_opresult(String *bin, uint Geometry::collection_init_from_opresult(String *bin,
const char *opres, const char *opres,
uint opres_length, uint opres_length,
Geometry *collection_item) Geometry *collection_item)
{ {
Geometry_buffer buffer; Geometry_buffer buffer;
const char *opres_orig= opres; const char *opres_orig= opres;
int n_items_offs= bin->length(); int n_items_offs= bin->length();
skipping to change at line 590 skipping to change at line 548
uint32 Gis_point::get_data_size() const uint32 Gis_point::get_data_size() const
{ {
return POINT_DATA_SIZE; return POINT_DATA_SIZE;
} }
bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb) bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
{ {
double x, y; double x, y;
if (trs->get_next_number(&x) || trs->get_next_number(&y) || if (trs->get_next_number(&x) || trs->get_next_number(&y) ||
wkb->reserve(POINT_DATA_SIZE)) wkb->reserve(POINT_DATA_SIZE))
return 1; return true;
wkb->q_append(x); wkb->q_append(x);
wkb->q_append(y); wkb->q_append(y);
return 0; return false;
} }
uint Gis_point::init_from_wkb(const char *wkb, uint len, uint Gis_point::init_from_wkb(const char *wkb, uint len,
wkbByteOrder bo, String *res) wkbByteOrder bo, String *res)
{ {
double x, y; double x, y;
if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE)) if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE))
return 0; return 0;
x= wkb_get_double(wkb, bo); x= wkb_get_double(wkb, bo);
y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo); y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
res->q_append(x); res->q_append(x);
res->q_append(y); res->q_append(y);
return POINT_DATA_SIZE; return POINT_DATA_SIZE;
} }
bool Gis_point::get_data_as_wkt(String *txt, const char **end) const bool Gis_point::get_data_as_wkt(String *txt, wkb_parser *wkb) const
{ {
double x, y; point_xy p;
if (get_xy(&x, &y)) if (wkb->scan_xy(&p))
return 1; return true;
if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1)) if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
return 1; return true;
txt->qs_append(x); txt->qs_append(p.x);
txt->qs_append(' '); txt->qs_append(' ');
txt->qs_append(y); txt->qs_append(p.y);
*end= m_data+ POINT_DATA_SIZE; return false;
return 0;
} }
bool Gis_point::get_mbr(MBR *mbr, const char **end) const bool Gis_point::get_mbr(MBR *mbr, wkb_parser *wkb) const
{ {
double x, y; point_xy p;
if (get_xy(&x, &y)) if (wkb->scan_xy(&p))
return 1; return true;
mbr->add_xy(x, y); mbr->add_xy(p);
*end= m_data+ POINT_DATA_SIZE; return false;
return 0;
} }
int Gis_point::store_shapes(Gcalc_shape_transporter *trn, int Gis_point::store_shapes(Gcalc_shape_transporter *trn,
Gcalc_shape_status *st) const Gcalc_shape_status *st) const
{ {
if (trn->skip_point()) if (trn->skip_point())
return 0; return 0;
double x, y; wkb_parser wkb(&m_wkb_data);
return get_xy(&x, &y) || trn->single_point(st, x, y); point_xy p;
return wkb.scan_xy(&p) || trn->single_point(st, p.x, p.y);
} }
const Geometry::Class_info *Gis_point::get_class_info() const const Geometry::Class_info *Gis_point::get_class_info() const
{ {
return &point_class; return &point_class;
} }
/***************************** LineString *******************************/ /***************************** LineString *******************************/
uint32 Gis_line_string::get_data_size() const uint32 Gis_line_string::get_data_size() const
{ {
if (no_data(m_data, 4)) uint32 n_points;
wkb_parser wkb(&m_wkb_data);
if (wkb.scan_n_points_and_check_data(&n_points))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
return 4 + uint4korr(m_data) * POINT_DATA_SIZE;
return 4 + n_points * POINT_DATA_SIZE;
} }
bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
{ {
uint32 n_points= 0; uint32 n_points= 0;
uint32 np_pos= wkb->length(); uint32 np_pos= wkb->length();
Gis_point p; Gis_point p;
if (wkb->reserve(4, 512)) if (wkb->reserve(4, 512))
return 1; return true;
wkb->length(wkb->length()+4); // Reserve space for points wkb->length(wkb->length()+4); // Reserve space for points
for (;;) for (;;)
{ {
if (p.init_from_wkt(trs, wkb)) if (p.init_from_wkt(trs, wkb))
return 1; return true;
n_points++; n_points++;
if (trs->skip_char(',')) // Didn't find ',' if (trs->skip_char(',')) // Didn't find ','
break; break;
} }
if (n_points < 1) if (n_points < 1)
{ {
trs->set_error_msg("Too few points in LINESTRING"); trs->set_error_msg("Too few points in LINESTRING");
return 1; return true;
} }
wkb->write_at_position(np_pos, n_points); wkb->write_at_position(np_pos, n_points);
return 0; return false;
} }
uint Gis_line_string::init_from_wkb(const char *wkb, uint len, uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
wkbByteOrder bo, String *res) wkbByteOrder bo, String *res)
{ {
uint32 n_points, proper_length; uint32 n_points, proper_length;
const char *wkb_end; const char *wkb_end;
Gis_point p; Gis_point p;
if (len < 4 || if (len < 4 ||
skipping to change at line 710 skipping to change at line 670
wkb_end= wkb + proper_length; wkb_end= wkb + proper_length;
for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE) for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE)
{ {
if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res)) if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res))
return 0; return 0;
} }
return proper_length; return proper_length;
} }
bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const bool Gis_line_string::get_data_as_wkt(String *txt, wkb_parser *wkb) const
{ {
uint32 n_points; uint32 n_points;
const char *data= m_data; if (wkb->scan_n_points_and_check_data(&n_points) ||
txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
if (no_data(data, 4)) return true;
return 1;
n_points= uint4korr(data);
data += 4;
if (n_points < 1 ||
no_data(data, POINT_DATA_SIZE * n_points) ||
txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
return 1;
while (n_points--) while (n_points--)
{ {
double x, y; point_xy p;
get_point(&x, &y, data); wkb->scan_xy_unsafe(&p);
data+= POINT_DATA_SIZE; txt->qs_append(p.x);
txt->qs_append(x);
txt->qs_append(' '); txt->qs_append(' ');
txt->qs_append(y); txt->qs_append(p.y);
txt->qs_append(','); txt->qs_append(',');
} }
txt->length(txt->length() - 1); // Remove end ',' txt->length(txt->length() - 1); // Remove end ','
*end= data; return false;
return 0;
} }
bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const bool Gis_line_string::get_mbr(MBR *mbr, wkb_parser *wkb) const
{ {
return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0; return get_mbr_for_points(mbr, wkb, 0);
} }
int Gis_line_string::geom_length(double *len) const int Gis_line_string::geom_length(double *len) const
{ {
uint32 n_points; uint32 n_points;
double prev_x, prev_y; wkb_parser wkb(&m_wkb_data);
const char *data= m_data;
*len= 0; // In case of errors *len= 0; // In case of errors
if (no_data(data, 4)) if (wkb.scan_n_points_and_check_data(&n_points))
return 1;
n_points= uint4korr(data);
data+= 4;
if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points))
return 1; return 1;
get_point(&prev_x, &prev_y, data); point_xy prev;
data+= POINT_DATA_SIZE; wkb.scan_xy_unsafe(&prev);
while (--n_points) while (--n_points)
{ {
double x, y; point_xy p;
get_point(&x, &y, data); wkb.scan_xy_unsafe(&p);
data+= POINT_DATA_SIZE; *len+= prev.distance(p);
*len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2)); prev= p;
prev_x= x;
prev_y= y;
} }
return 0; return 0;
} }
int Gis_line_string::is_closed(int *closed) const int Gis_line_string::is_closed(int *closed) const
{ {
uint32 n_points; uint32 n_points;
double x1, y1, x2, y2; wkb_parser wkb(&m_wkb_data);
const char *data= m_data;
if (no_data(data, 4)) if (wkb.scan_n_points_and_check_data(&n_points))
return 1; return 1;
n_points= uint4korr(data);
if (n_points == 1) if (n_points == 1)
{ {
*closed=1; *closed=1;
return 0; return 0;
} }
data+= 4;
if (n_points == 0 ||
no_data(data, POINT_DATA_SIZE * n_points))
return 1;
/* Get first point */ point_xy p1, p2;
get_point(&x1, &y1, data);
/* get last point */ /* Get first point. */
data+= POINT_DATA_SIZE + (n_points-2)*POINT_DATA_SIZE; wkb.scan_xy_unsafe(&p1);
get_point(&x2, &y2, data);
*closed= (x1==x2) && (y1==y2); /* Get last point. */
wkb.skip_unsafe((n_points - 2) * POINT_DATA_SIZE);
wkb.scan_xy_unsafe(&p2);
*closed= p1.eq(p2);
return 0; return 0;
} }
int Gis_line_string::num_points(uint32 *n_points) const int Gis_line_string::num_points(uint32 *n_points) const
{ {
*n_points= uint4korr(m_data); wkb_parser wkb(&m_wkb_data);
return 0; return wkb.scan_uint4(n_points) ? 1 : 0;
} }
int Gis_line_string::start_point(String *result) const int Gis_line_string::start_point(String *result) const
{ {
/* +4 is for skipping over number of points */ uint32 n_points;
return create_point(result, m_data + 4); wkb_parser wkb(&m_wkb_data);
if (wkb.scan_n_points_and_check_data(&n_points))
return 1;
return create_point(result, &wkb);
} }
int Gis_line_string::end_point(String *result) const int Gis_line_string::end_point(String *result) const
{ {
uint32 n_points; uint32 n_points;
if (no_data(m_data, 4)) wkb_parser wkb(&m_wkb_data);
if (wkb.scan_n_points_and_check_data(&n_points))
return 1; return 1;
n_points= uint4korr(m_data); wkb.skip_unsafe((n_points - 1) * POINT_DATA_SIZE);
return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE return create_point(result, &wkb);
);
} }
int Gis_line_string::point_n(uint32 num, String *result) const int Gis_line_string::point_n(uint32 num, String *result) const
{ {
uint32 n_points; uint32 n_points;
if (no_data(m_data, 4)) wkb_parser wkb(&m_wkb_data);
return 1; if (num < 1 ||
n_points= uint4korr(m_data); wkb.scan_n_points_and_check_data(&n_points) ||
if ((uint32) (num - 1) >= n_points) // means (num > n_points || num < 1) num > n_points)
return 1; return 1;
wkb.skip_unsafe((num - 1) * POINT_DATA_SIZE);
return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE); return create_point(result, &wkb);
} }
int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn, int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn,
Gcalc_shape_status *st) const Gcalc_shape_status *st) const
{ {
uint32 n_points; uint32 n_points;
double x, y; wkb_parser wkb(&m_wkb_data);
const char *data= m_data;
if (trn->skip_line_string()) if (trn->skip_line_string())
return 0; return 0;
if (no_data(m_data, 4)) if (wkb.scan_n_points_and_check_data(&n_points))
return 1;
n_points= uint4korr(data);
data+= 4;
if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points))
return 1; return 1;
trn->start_line(st); trn->start_line(st);
while (n_points--) while (n_points--)
{ {
get_point(&x, &y, data); point_xy p;
data+= POINT_DATA_SIZE; wkb.scan_xy_unsafe(&p);
if (trn->add_point(st, x, y)) if (trn->add_point(st, p.x, p.y))
return 1; return 1;
} }
return trn->complete_line(st); return trn->complete_line(st);
} }
const Geometry::Class_info *Gis_line_string::get_class_info() const const Geometry::Class_info *Gis_line_string::get_class_info() const
{ {
return &linestring_class; return &linestring_class;
} }
/***************************** Polygon *******************************/ /***************************** Polygon *******************************/
uint32 Gis_polygon::get_data_size() const uint32 Gis_polygon::get_data_size() const
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_linear_rings))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
n_linear_rings= uint4korr(data);
data+= 4;
while (n_linear_rings--) while (n_linear_rings--)
{ {
if (no_data(data, 4)) uint32 n_points;
if (wkb.scan_n_points_and_check_data(&n_points))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
data+= 4 + uint4korr(data)*POINT_DATA_SIZE; wkb.skip_unsafe(n_points * POINT_DATA_SIZE);
} }
return (uint32) (data - m_data); return (uint32) (wkb.data() - m_wkb_data.data());
} }
bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
{ {
uint32 n_linear_rings= 0; uint32 n_linear_rings= 0;
uint32 lr_pos= wkb->length(); uint32 lr_pos= wkb->length();
int closed; int closed;
if (wkb->reserve(4, 512)) if (wkb->reserve(4, 512))
return 1; return true;
wkb->length(wkb->length()+4); // Reserve space for points wkb->length(wkb->length()+4); // Reserve space for points
for (;;) for (;;)
{ {
Gis_line_string ls; Gis_line_string ls;
uint32 ls_pos=wkb->length(); uint32 ls_pos=wkb->length();
if (trs->check_next_symbol('(') || if (trs->check_next_symbol('(') ||
ls.init_from_wkt(trs, wkb) || ls.init_from_wkt(trs, wkb) ||
trs->check_next_symbol(')')) trs->check_next_symbol(')'))
return 1; return true;
ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos); ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
if (ls.is_closed(&closed) || !closed) if (ls.is_closed(&closed) || !closed)
{ {
trs->set_error_msg("POLYGON's linear ring isn't closed"); trs->set_error_msg("POLYGON's linear ring isn't closed");
return 1; return true;
} }
n_linear_rings++; n_linear_rings++;
if (trs->skip_char(',')) // Didn't find ',' if (trs->skip_char(',')) // Didn't find ','
break; break;
} }
wkb->write_at_position(lr_pos, n_linear_rings); wkb->write_at_position(lr_pos, n_linear_rings);
return 0; return false;
} }
uint Gis_polygon::init_from_opresult(String *bin, uint Gis_polygon::init_from_opresult(String *bin,
const char *opres, uint opres_length) const char *opres, uint opres_length)
{ {
const char *opres_orig= opres; const char *opres_orig= opres;
const char *opres_end= opres + opres_length; const char *opres_end= opres + opres_length;
uint32 position= bin->length(); uint32 position= bin->length();
uint32 poly_shapes= 0; uint32 poly_shapes= 0;
skipping to change at line 977 skipping to change at line 915
uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
String *res) String *res)
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
const char *wkb_orig= wkb; const char *wkb_orig= wkb;
if (len < 4) if (len < 4)
return 0; return 0;
n_linear_rings= wkb_get_uint(wkb, bo); if (0 == (n_linear_rings= wkb_get_uint(wkb, bo)) ||
if (res->reserve(4, 512)) res->reserve(4, 512))
return 0; return 0;
wkb+= 4; wkb+= 4;
len-= 4; len-= 4;
res->q_append(n_linear_rings); res->q_append(n_linear_rings);
while (n_linear_rings--) while (n_linear_rings--)
{ {
Gis_line_string ls; Gis_line_string ls;
uint32 ls_pos= res->length(); uint32 ls_pos= res->length();
int ls_len; int ls_len;
skipping to change at line 1004 skipping to change at line 942
ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos); ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos);
if (ls.is_closed(&closed) || !closed) if (ls.is_closed(&closed) || !closed)
return 0; return 0;
wkb+= ls_len; wkb+= ls_len;
} }
return (uint) (wkb - wkb_orig); return (uint) (wkb - wkb_orig);
} }
bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const bool Gis_polygon::get_data_as_wkt(String *txt, wkb_parser *wkb) const
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
const char *data= m_data;
if (no_data(data, 4))
return 1;
n_linear_rings= uint4korr(data); if (wkb->scan_non_zero_uint4(&n_linear_rings))
data+= 4; return true;
while (n_linear_rings--) while (n_linear_rings--)
{ {
uint32 n_points; uint32 n_points;
if (no_data(data, 4)) if (wkb->scan_n_points_and_check_data(&n_points) ||
return 1;
n_points= uint4korr(data);
data+= 4;
if (no_data(data, POINT_DATA_SIZE * n_points) ||
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
return 1; return true;
txt->qs_append('('); txt->qs_append('(');
data= append_points(txt, n_points, data, 0); append_points(txt, n_points, wkb, 0);
(*txt) [txt->length() - 1]= ')'; // Replace end ',' (*txt) [txt->length() - 1]= ')'; // Replace end ','
txt->qs_append(','); txt->qs_append(',');
} }
txt->length(txt->length() - 1); // Remove end ',' txt->length(txt->length() - 1); // Remove end ','
*end= data; return false;
return 0;
} }
bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const bool Gis_polygon::get_mbr(MBR *mbr, wkb_parser *wkb) const
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
const char *data= m_data;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_linear_rings))
return 1; return true;
n_linear_rings= uint4korr(data);
data+= 4;
while (n_linear_rings--) while (n_linear_rings--)
{ {
if (!(data= get_mbr_for_points(mbr, data, 0))) if (get_mbr_for_points(mbr, wkb, 0))
return 1; return true;
} }
*end= data; return false;
return 0;
} }
int Gis_polygon::area(double *ar, const char **end_of_data) const bool Gis_polygon::area(double *ar, wkb_parser *wkb) const
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
double result= -1.0; double result= -1.0;
const char *data= m_data;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_linear_rings))
return 1; return true;
n_linear_rings= uint4korr(data);
data+= 4;
while (n_linear_rings--) while (n_linear_rings--)
{ {
double prev_x, prev_y;
double lr_area= 0; double lr_area= 0;
uint32 n_points; uint32 n_points;
if (no_data(data, 4)) if (wkb->scan_n_points_and_check_data(&n_points))
return 1; return true;
n_points= uint4korr(data); point_xy prev;
if (no_data(data, POINT_DATA_SIZE * n_points)) wkb->scan_xy_unsafe(&prev);
return 1;
get_point(&prev_x, &prev_y, data+4);
data+= (4+POINT_DATA_SIZE);
while (--n_points) // One point is already read while (--n_points) // One point is already read
{ {
double x, y; point_xy p;
get_point(&x, &y, data); wkb->scan_xy_unsafe(&p);
data+= POINT_DATA_SIZE; lr_area+= (prev.x + p.x) * (prev.y - p.y);
lr_area+= (prev_x + x)* (prev_y - y); prev= p;
prev_x= x;
prev_y= y;
} }
lr_area= fabs(lr_area)/2; lr_area= fabs(lr_area)/2;
if (result == -1.0) if (result == -1.0)
result= lr_area; result= lr_area;
else else
result-= lr_area; result-= lr_area;
} }
*ar= fabs(result); *ar= fabs(result);
*end_of_data= data; return false;
return 0;
} }
int Gis_polygon::exterior_ring(String *result) const int Gis_polygon::exterior_ring(String *result) const
{ {
uint32 n_points, length; uint32 n_points, n_linear_rings, length;
const char *data= m_data + 4; // skip n_linerings wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_linear_rings) ||
wkb.scan_n_points_and_check_data(&n_points))
return 1; return 1;
n_points= uint4korr(data);
data+= 4;
length= n_points * POINT_DATA_SIZE; length= n_points * POINT_DATA_SIZE;
if (no_data(data, length) || result->reserve(1 + 4 + 4 + length)) if (result->reserve(1 + 4 + 4 + length))
return 1; return 1;
result->q_append((char) wkb_ndr); result->q_append((char) wkb_ndr);
result->q_append((uint32) wkb_linestring); result->q_append((uint32) wkb_linestring);
result->q_append(n_points); result->q_append(n_points);
result->q_append(data, n_points * POINT_DATA_SIZE); result->q_append(wkb.data(), length);
return 0; return 0;
} }
int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const
{ {
if (no_data(m_data, 4)) wkb_parser wkb(&m_wkb_data);
if (wkb.scan_non_zero_uint4(n_int_rings))
return 1; return 1;
*n_int_rings= uint4korr(m_data)-1; *n_int_rings-= 1;
return 0; return 0;
} }
int Gis_polygon::interior_ring_n(uint32 num, String *result) const int Gis_polygon::interior_ring_n(uint32 num, String *result) const
{ {
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
uint32 n_linear_rings; uint32 n_linear_rings;
uint32 n_points; uint32 n_points;
uint32 points_size; uint32 points_size;
if (no_data(data, 4)) if (num < 1 ||
return 1; wkb.scan_non_zero_uint4(&n_linear_rings) ||
n_linear_rings= uint4korr(data); num >= n_linear_rings)
data+= 4;
if (num >= n_linear_rings || num < 1)
return 1; return 1;
while (num--) while (num--)
{ {
if (no_data(data, 4)) if (wkb.scan_n_points_and_check_data(&n_points))
return 1; return 1;
data+= 4 + uint4korr(data) * POINT_DATA_SIZE; wkb.skip_unsafe(n_points * POINT_DATA_SIZE);
} }
if (no_data(data, 4)) if (wkb.scan_n_points_and_check_data(&n_points))
return 1; return 1;
n_points= uint4korr(data);
points_size= n_points * POINT_DATA_SIZE; points_size= n_points * POINT_DATA_SIZE;
data+= 4; if (result->reserve(1 + 4 + 4 + points_size))
if (no_data(data, points_size) || result->reserve(1 + 4 + 4 + points_size
))
return 1; return 1;
result->q_append((char) wkb_ndr); result->q_append((char) wkb_ndr);
result->q_append((uint32) wkb_linestring); result->q_append((uint32) wkb_linestring);
result->q_append(n_points); result->q_append(n_points);
result->q_append(data, points_size); result->q_append(wkb.data(), points_size);
return 0; return 0;
} }
int Gis_polygon::centroid_xy(double *x, double *y) const bool Gis_polygon::centroid_xy(point_xy *p) const
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
double UNINIT_VAR(res_area); double UNINIT_VAR(res_area);
double UNINIT_VAR(res_cx), UNINIT_VAR(res_cy); point_xy res(0, 0); // Initialized only to make compiler hap
const char *data= m_data; py
wkb_parser wkb(&m_wkb_data);
bool first_loop= 1; bool first_loop= 1;
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_linear_rings))
return 1; return true;
n_linear_rings= uint4korr(data);
data+= 4;
DBUG_ASSERT(n_linear_rings > 0);
while (n_linear_rings--) while (n_linear_rings--)
{ {
uint32 n_points, org_n_points; uint32 n_points, org_n_points;
double prev_x, prev_y;
double cur_area= 0; double cur_area= 0;
double cur_cx= 0; point_xy prev, cur(0, 0);
double cur_cy= 0;
if (no_data(data, 4)) if (wkb.scan_n_points_and_check_data(&n_points))
return 1; return true;
org_n_points= n_points= uint4korr(data);
data+= 4; org_n_points= n_points - 1;
if (no_data(data, POINT_DATA_SIZE * n_points)) wkb.scan_xy_unsafe(&prev);
return 1;
get_point(&prev_x, &prev_y, data);
data+= POINT_DATA_SIZE;
while (--n_points) // One point is already read while (--n_points) // One point is already read
{ {
double tmp_x, tmp_y; point_xy tmp;
get_point(&tmp_x, &tmp_y, data); wkb.scan_xy_unsafe(&tmp);
data+= POINT_DATA_SIZE; cur_area+= (prev.x + tmp.x) * (prev.y - tmp.y);
cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y); cur.x+= tmp.x;
cur_cx+= tmp_x; cur.y+= tmp.y;
cur_cy+= tmp_y; prev= tmp;
prev_x= tmp_x;
prev_y= tmp_y;
} }
cur_area= fabs(cur_area) / 2; cur_area= fabs(cur_area) / 2;
cur_cx= cur_cx / (org_n_points - 1); cur.x= cur.x / org_n_points;
cur_cy= cur_cy / (org_n_points - 1); cur.y= cur.y / org_n_points;
if (!first_loop) if (!first_loop)
{ {
double d_area= fabs(res_area - cur_area); double d_area= fabs(res_area - cur_area);
res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area; res.x= (res_area * res.x - cur_area * cur.x) / d_area;
res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area; res.y= (res_area * res.y - cur_area * cur.y) / d_area;
} }
else else
{ {
first_loop= 0; first_loop= 0;
res_area= cur_area; res_area= cur_area;
res_cx= cur_cx; res= cur;
res_cy= cur_cy;
} }
} }
*x= res_cx; *p= res;
*y= res_cy; return false;
return 0;
} }
int Gis_polygon::centroid(String *result) const int Gis_polygon::centroid(String *result) const
{ {
double x, y; point_xy p;
if (centroid_xy(&x, &y)) if (centroid_xy(&p))
return 1; return 1;
return create_point(result, x, y); return create_point(result, p);
} }
int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn, int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn,
Gcalc_shape_status *st) const Gcalc_shape_status *st) const
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
if (trn->skip_poly()) if (trn->skip_poly())
return 0; return 0;
if (trn->start_poly(st)) if (trn->start_poly(st))
return 1; return 1;
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_linear_rings))
return 1; return 1;
n_linear_rings= uint4korr(data);
data+= 4;
while (n_linear_rings--) while (n_linear_rings--)
{ {
uint32 n_points; uint32 n_points;
if (no_data(data, 4)) if (wkb.scan_n_points_and_check_data(&n_points))
return 1;
n_points= uint4korr(data);
data+= 4;
if (!n_points || no_data(data, POINT_DATA_SIZE * n_points))
return 1; return 1;
trn->start_ring(st); trn->start_ring(st);
while (--n_points) while (--n_points)
{ {
double x, y; point_xy p;
get_point(&x, &y, data); wkb.scan_xy_unsafe(&p);
data+= POINT_DATA_SIZE; if (trn->add_point(st, p.x, p.y))
if (trn->add_point(st, x, y))
return 1; return 1;
} }
data+= POINT_DATA_SIZE; wkb.skip_unsafe(POINT_DATA_SIZE); // Skip the last point in the ring.
trn->complete_ring(st); trn->complete_ring(st);
} }
trn->complete_poly(st); trn->complete_poly(st);
return 0; return 0;
} }
const Geometry::Class_info *Gis_polygon::get_class_info() const const Geometry::Class_info *Gis_polygon::get_class_info() const
{ {
return &polygon_class; return &polygon_class;
} }
/***************************** MultiPoint *******************************/ /***************************** MultiPoint *******************************/
uint32 Gis_multi_point::get_data_size() const uint32 Gis_multi_point::get_data_size() const
{ {
if (no_data(m_data, 4)) uint32 n_points;
wkb_parser wkb(&m_wkb_data);
if (wkb.scan_n_points_and_check_data(&n_points, WKB_HEADER_SIZE))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE);
return 4 + n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE);
} }
bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
{ {
uint32 n_points= 0; uint32 n_points= 0;
uint32 np_pos= wkb->length(); uint32 np_pos= wkb->length();
Gis_point p; Gis_point p;
if (wkb->reserve(4, 512)) if (wkb->reserve(4, 512))
return 1; return true;
wkb->length(wkb->length()+4); // Reserve space for points wkb->length(wkb->length()+4); // Reserve space for points
for (;;) for (;;)
{ {
if (wkb->reserve(1 + 4, 512)) if (wkb->reserve(1 + 4, 512))
return 1; return 1;
wkb->q_append((char) wkb_ndr); wkb->q_append((char) wkb_ndr);
wkb->q_append((uint32) wkb_point); wkb->q_append((uint32) wkb_point);
if (p.init_from_wkt(trs, wkb)) if (p.init_from_wkt(trs, wkb))
return 1; return true;
n_points++; n_points++;
if (trs->skip_char(',')) // Didn't find ',' if (trs->skip_char(',')) // Didn't find ','
break; break;
} }
wkb->write_at_position(np_pos, n_points); // Store number of found poi nts wkb->write_at_position(np_pos, n_points); // Store number of found poi nts
return 0; return false;
} }
uint Gis_multi_point::init_from_opresult(String *bin, uint Gis_multi_point::init_from_opresult(String *bin,
const char *opres, uint opres_leng th) const char *opres, uint opres_leng th)
{ {
uint bin_size, n_points; uint bin_size, n_points;
Gis_point p; Gis_point p;
const char *opres_end; const char *opres_end;
n_points= opres_length / (4 + 8 * 2); n_points= opres_length / (4 + 8 * 2);
skipping to change at line 1378 skipping to change at line 1270
{ {
res->q_append((char)wkb_ndr); res->q_append((char)wkb_ndr);
res->q_append((uint32)wkb_point); res->q_append((uint32)wkb_point);
if (!p.init_from_wkb(wkb + WKB_HEADER_SIZE, if (!p.init_from_wkb(wkb + WKB_HEADER_SIZE,
POINT_DATA_SIZE, (wkbByteOrder) wkb[0], res)) POINT_DATA_SIZE, (wkbByteOrder) wkb[0], res))
return 0; return 0;
} }
return proper_size; return proper_size;
} }
bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const bool Gis_multi_point::get_data_as_wkt(String *txt, wkb_parser *wkb) const
{ {
uint32 n_points; uint32 n_points;
if (no_data(m_data, 4))
return 1;
n_points= uint4korr(m_data); if (wkb->scan_n_points_and_check_data(&n_points, WKB_HEADER_SIZE) ||
if (no_data(m_data+4,
n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE)) ||
txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
return 1; return true;
*end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE);
append_points(txt, n_points, wkb, WKB_HEADER_SIZE);
txt->length(txt->length()-1); // Remove end ',' txt->length(txt->length()-1); // Remove end ','
return 0; return false;
} }
bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const bool Gis_multi_point::get_mbr(MBR *mbr, wkb_parser *wkb) const
{ {
return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0; return get_mbr_for_points(mbr, wkb, WKB_HEADER_SIZE);
} }
int Gis_multi_point::num_geometries(uint32 *num) const int Gis_multi_point::num_geometries(uint32 *num) const
{ {
*num= uint4korr(m_data); wkb_parser wkb(&m_wkb_data);
return 0; return wkb.scan_non_zero_uint4(num) ? 1 : 0;
} }
int Gis_multi_point::geometry_n(uint32 num, String *result) const int Gis_multi_point::geometry_n(uint32 num, String *result) const
{ {
const char *data= m_data;
uint32 n_points; uint32 n_points;
wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4)) if (num < 1 ||
return 1; wkb.scan_n_points_and_check_data(&n_points, WKB_HEADER_SIZE) ||
n_points= uint4korr(data); num > n_points ||
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)) result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE))
return 1; return 1;
wkb.skip_unsafe((num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE));
result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE); result->q_append(wkb.data(), WKB_HEADER_SIZE + POINT_DATA_SIZE);
return 0; return 0;
} }
int Gis_multi_point::store_shapes(Gcalc_shape_transporter *trn, int Gis_multi_point::store_shapes(Gcalc_shape_transporter *trn,
Gcalc_shape_status *st) const Gcalc_shape_status *st) const
{ {
if (trn->skip_point()) if (trn->skip_point())
return 0; return 0;
Gis_point pt; Gis_point pt;
return collection_store_shapes(trn, st, &pt); return collection_store_shapes(trn, st, &pt);
skipping to change at line 1443 skipping to change at line 1329
const Geometry::Class_info *Gis_multi_point::get_class_info() const const Geometry::Class_info *Gis_multi_point::get_class_info() const
{ {
return &multipoint_class; return &multipoint_class;
} }
/***************************** MultiLineString **************************** ***/ /***************************** MultiLineString **************************** ***/
uint32 Gis_multi_line_string::get_data_size() const uint32 Gis_multi_line_string::get_data_size() const
{ {
uint32 n_line_strings; uint32 n_line_strings;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_line_strings))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
n_line_strings= uint4korr(data);
data+= 4;
while (n_line_strings--) while (n_line_strings--)
{ {
if (no_data(data, WKB_HEADER_SIZE + 4)) uint32 n_points;
if (wkb.skip_wkb_header() ||
wkb.scan_n_points_and_check_data(&n_points))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
data+= (WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) *
POINT_DATA_SIZE); wkb.skip_unsafe(n_points * POINT_DATA_SIZE);
} }
return (uint32) (data - m_data); return (uint32) (wkb.data() - m_wkb_data.data());
} }
bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb ) bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb )
{ {
uint32 n_line_strings= 0; uint32 n_line_strings= 0;
uint32 ls_pos= wkb->length(); uint32 ls_pos= wkb->length();
if (wkb->reserve(4, 512)) if (wkb->reserve(4, 512))
return 1; return true;
wkb->length(wkb->length()+4); // Reserve space for points wkb->length(wkb->length()+4); // Reserve space for points
for (;;) for (;;)
{ {
Gis_line_string ls; Gis_line_string ls;
if (wkb->reserve(1 + 4, 512)) if (wkb->reserve(1 + 4, 512))
return 1; return true;
wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_linestring); wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_linestring);
if (trs->check_next_symbol('(') || if (trs->check_next_symbol('(') ||
ls.init_from_wkt(trs, wkb) || ls.init_from_wkt(trs, wkb) ||
trs->check_next_symbol(')')) trs->check_next_symbol(')'))
return 1; return true;
n_line_strings++; n_line_strings++;
if (trs->skip_char(',')) // Didn't find ',' if (trs->skip_char(',')) // Didn't find ','
break; break;
} }
wkb->write_at_position(ls_pos, n_line_strings); wkb->write_at_position(ls_pos, n_line_strings);
return 0; return false;
} }
uint Gis_multi_line_string::init_from_opresult(String *bin, uint Gis_multi_line_string::init_from_opresult(String *bin,
const char *opres, const char *opres,
uint opres_length) uint opres_length)
{ {
Gis_line_string item; Gis_line_string item;
return collection_init_from_opresult(bin, opres, opres_length, &item); return collection_init_from_opresult(bin, opres, opres_length, &item);
} }
skipping to change at line 1534 skipping to change at line 1421
if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len, if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
(wkbByteOrder) wkb[0], res))) (wkbByteOrder) wkb[0], res)))
return 0; return 0;
ls_len+= WKB_HEADER_SIZE;; ls_len+= WKB_HEADER_SIZE;;
wkb+= ls_len; wkb+= ls_len;
len-= ls_len; len-= ls_len;
} }
return (uint) (wkb - wkb_orig); return (uint) (wkb - wkb_orig);
} }
bool Gis_multi_line_string::get_data_as_wkt(String *txt, bool Gis_multi_line_string::get_data_as_wkt(String *txt, wkb_parser *wkb) c
const char **end) const onst
{ {
uint32 n_line_strings; uint32 n_line_strings;
const char *data= m_data;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_line_strings))
return 1; return true;
n_line_strings= uint4korr(data);
data+= 4;
while (n_line_strings--) while (n_line_strings--)
{ {
uint32 n_points; uint32 n_points;
if (no_data(data, (WKB_HEADER_SIZE + 4)))
return 1; if (wkb->skip_wkb_header() ||
n_points= uint4korr(data + WKB_HEADER_SIZE); wkb->scan_n_points_and_check_data(&n_points) ||
data+= WKB_HEADER_SIZE + 4;
if (no_data(data, n_points * POINT_DATA_SIZE) ||
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
return 1; return true;
txt->qs_append('('); txt->qs_append('(');
data= append_points(txt, n_points, data, 0); append_points(txt, n_points, wkb, 0);
(*txt) [txt->length() - 1]= ')'; (*txt) [txt->length() - 1]= ')';
txt->qs_append(','); txt->qs_append(',');
} }
txt->length(txt->length() - 1); txt->length(txt->length() - 1);
*end= data; return false;
return 0;
} }
bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const bool Gis_multi_line_string::get_mbr(MBR *mbr, wkb_parser *wkb) const
{ {
uint32 n_line_strings; uint32 n_line_strings;
const char *data= m_data;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_line_strings))
return 1; return true;
n_line_strings= uint4korr(data);
data+= 4;
while (n_line_strings--) while (n_line_strings--)
{ {
data+= WKB_HEADER_SIZE; if (wkb->skip_wkb_header() ||
if (!(data= get_mbr_for_points(mbr, data, 0))) get_mbr_for_points(mbr, wkb, 0))
return 1; return true;
} }
*end= data; return false;
return 0;
} }
int Gis_multi_line_string::num_geometries(uint32 *num) const int Gis_multi_line_string::num_geometries(uint32 *num) const
{ {
*num= uint4korr(m_data); wkb_parser wkb(&m_wkb_data);
return 0; return wkb.scan_non_zero_uint4(num) ? 1 : 0;
} }
int Gis_multi_line_string::geometry_n(uint32 num, String *result) const int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
{ {
uint32 n_line_strings, n_points, length; uint32 n_line_strings, n_points, length;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_line_strings))
return 1; return 1;
n_line_strings= uint4korr(data);
data+= 4;
if ((num > n_line_strings) || (num < 1)) if ((num > n_line_strings) || (num < 1))
return 1; return 1;
for (;;) for (;;)
{ {
if (no_data(data, WKB_HEADER_SIZE + 4)) if (wkb.skip_wkb_header() ||
return 1; wkb.scan_n_points_and_check_data(&n_points))
n_points= uint4korr(data + WKB_HEADER_SIZE);
length= WKB_HEADER_SIZE + 4+ POINT_DATA_SIZE * n_points;
if (no_data(data, length))
return 1; return 1;
length= POINT_DATA_SIZE * n_points;
if (!--num) if (!--num)
break; break;
data+= length; wkb.skip_unsafe(length);
} }
return result->append(data, length, (uint32) 0); return result->append(wkb.data() - 4 - WKB_HEADER_SIZE,
length + 4 + WKB_HEADER_SIZE, (uint32) 0);
} }
int Gis_multi_line_string::geom_length(double *len) const int Gis_multi_line_string::geom_length(double *len) const
{ {
uint32 n_line_strings; uint32 n_line_strings;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_line_strings))
return 1; return 1;
n_line_strings= uint4korr(data);
data+= 4;
*len=0; *len=0;
while (n_line_strings--) while (n_line_strings--)
{ {
double ls_len; double ls_len;
Gis_line_string ls; Gis_line_string ls;
data+= WKB_HEADER_SIZE; if (wkb.skip_wkb_header())
ls.set_data_ptr(data, (uint32) (m_data_end - data)); return 1;
ls.set_data_ptr(&wkb);
if (ls.geom_length(&ls_len)) if (ls.geom_length(&ls_len))
return 1; return 1;
*len+= ls_len; *len+= ls_len;
/* /*
We know here that ls was ok, so we can call the trivial function We know here that ls was ok, so we can call the trivial function
Gis_line_string::get_data_size without error checking Gis_line_string::get_data_size without error checking
*/ */
data+= ls.get_data_size(); wkb.skip_unsafe(ls.get_data_size());
} }
return 0; return 0;
} }
int Gis_multi_line_string::is_closed(int *closed) const int Gis_multi_line_string::is_closed(int *closed) const
{ {
uint32 n_line_strings; uint32 n_line_strings;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4 + WKB_HEADER_SIZE)) if (wkb.scan_non_zero_uint4(&n_line_strings))
return 1; return 1;
n_line_strings= uint4korr(data);
data+= 4 + WKB_HEADER_SIZE;
while (n_line_strings--) while (n_line_strings--)
{ {
Gis_line_string ls; Gis_line_string ls;
if (no_data(data, 0)) if (wkb.skip_wkb_header())
return 1; return 1;
ls.set_data_ptr(data, (uint32) (m_data_end - data)); ls.set_data_ptr(&wkb);
if (ls.is_closed(closed)) if (ls.is_closed(closed))
return 1; return 1;
if (!*closed) if (!*closed)
return 0; return 0;
/* wkb.skip_unsafe(ls.get_data_size());
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;
} }
return 0; return 0;
} }
int Gis_multi_line_string::store_shapes(Gcalc_shape_transporter *trn, int Gis_multi_line_string::store_shapes(Gcalc_shape_transporter *trn,
Gcalc_shape_status *st) const Gcalc_shape_status *st) const
{ {
if (trn->skip_line_string()) if (trn->skip_line_string())
return 0; return 0;
Gis_line_string ls; Gis_line_string ls;
skipping to change at line 1696 skipping to change at line 1562
const Geometry::Class_info *Gis_multi_line_string::get_class_info() const const Geometry::Class_info *Gis_multi_line_string::get_class_info() const
{ {
return &multilinestring_class; return &multilinestring_class;
} }
/***************************** MultiPolygon ******************************* / /***************************** MultiPolygon ******************************* /
uint32 Gis_multi_polygon::get_data_size() const uint32 Gis_multi_polygon::get_data_size() const
{ {
uint32 n_polygons; uint32 n_polygons;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_polygons))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
n_polygons= uint4korr(data);
data+= 4;
while (n_polygons--) while (n_polygons--)
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
if (no_data(data, 4 + WKB_HEADER_SIZE)) if (wkb.skip_wkb_header() ||
wkb.scan_non_zero_uint4(&n_linear_rings))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
data+= 4 + WKB_HEADER_SIZE;
while (n_linear_rings--) while (n_linear_rings--)
{ {
if (no_data(data, 4)) uint32 n_points;
return GET_SIZE_ERROR;
data+= 4 + uint4korr(data) * POINT_DATA_SIZE; if (wkb.scan_n_points_and_check_data(&n_points))
return GET_SIZE_ERROR;
wkb.skip_unsafe(n_points * POINT_DATA_SIZE);
} }
} }
return (uint32) (data - m_data); return (uint32) (wkb.data() - m_wkb_data.data());
} }
bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
{ {
uint32 n_polygons= 0; uint32 n_polygons= 0;
int np_pos= wkb->length(); int np_pos= wkb->length();
Gis_polygon p; Gis_polygon p;
if (wkb->reserve(4, 512)) if (wkb->reserve(4, 512))
return 1; return true;
wkb->length(wkb->length()+4); // Reserve space for points wkb->length(wkb->length()+4); // Reserve space for points
for (;;) for (;;)
{ {
if (wkb->reserve(1 + 4, 512)) if (wkb->reserve(1 + 4, 512))
return 1; return true;
wkb->q_append((char) wkb_ndr); wkb->q_append((char) wkb_ndr);
wkb->q_append((uint32) wkb_polygon); wkb->q_append((uint32) wkb_polygon);
if (trs->check_next_symbol('(') || if (trs->check_next_symbol('(') ||
p.init_from_wkt(trs, wkb) || p.init_from_wkt(trs, wkb) ||
trs->check_next_symbol(')')) trs->check_next_symbol(')'))
return 1; return true;
n_polygons++; n_polygons++;
if (trs->skip_char(',')) // Didn't find ',' if (trs->skip_char(',')) // Didn't find ','
break; break;
} }
wkb->write_at_position(np_pos, n_polygons); wkb->write_at_position(np_pos, n_polygons);
return 0; return false;
} }
uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len, uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
wkbByteOrder bo, String *res) wkbByteOrder bo, String *res)
{ {
uint32 n_poly; uint32 n_poly;
const char *wkb_orig= wkb; const char *wkb_orig= wkb;
if (len < 4) if (len < 4)
return 0; return 0;
skipping to change at line 1794 skipping to change at line 1659
return (uint) (wkb - wkb_orig); return (uint) (wkb - wkb_orig);
} }
uint Gis_multi_polygon::init_from_opresult(String *bin, uint Gis_multi_polygon::init_from_opresult(String *bin,
const char *opres, uint opres_le ngth) const char *opres, uint opres_le ngth)
{ {
Gis_polygon item; Gis_polygon item;
return collection_init_from_opresult(bin, opres, opres_length, &item); return collection_init_from_opresult(bin, opres, opres_length, &item);
} }
bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) cons t bool Gis_multi_polygon::get_data_as_wkt(String *txt, wkb_parser *wkb) const
{ {
uint32 n_polygons; uint32 n_polygons;
const char *data= m_data;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_polygons))
return 1; return true;
n_polygons= uint4korr(data);
data+= 4;
while (n_polygons--) while (n_polygons--)
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
if (no_data(data, 4 + WKB_HEADER_SIZE) ||
txt->reserve(1, 512)) if (wkb->skip_wkb_header() ||
return 1; wkb->scan_non_zero_uint4(&n_linear_rings) ||
n_linear_rings= uint4korr(data+WKB_HEADER_SIZE); txt->reserve(1, 512))
data+= 4 + WKB_HEADER_SIZE; return true;
txt->q_append('('); txt->q_append('(');
while (n_linear_rings--) while (n_linear_rings--)
{ {
if (no_data(data, 4)) uint32 n_points;
return 1; if (wkb->scan_n_points_and_check_data(&n_points) ||
uint32 n_points= uint4korr(data); txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
data+= 4; 512))
if (no_data(data, POINT_DATA_SIZE * n_points) || return true;
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
512))
return 1;
txt->qs_append('('); txt->qs_append('(');
data= append_points(txt, n_points, data, 0); append_points(txt, n_points, wkb, 0);
(*txt) [txt->length() - 1]= ')'; (*txt) [txt->length() - 1]= ')';
txt->qs_append(','); txt->qs_append(',');
} }
(*txt) [txt->length() - 1]= ')'; (*txt) [txt->length() - 1]= ')';
txt->qs_append(','); txt->qs_append(',');
} }
txt->length(txt->length() - 1); txt->length(txt->length() - 1);
*end= data; return false;
return 0;
} }
bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const bool Gis_multi_polygon::get_mbr(MBR *mbr, wkb_parser *wkb) const
{ {
uint32 n_polygons; uint32 n_polygons;
const char *data= m_data;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_polygons))
return 1; return true;
n_polygons= uint4korr(data);
data+= 4;
while (n_polygons--) while (n_polygons--)
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
if (no_data(data, 4+WKB_HEADER_SIZE)) if (wkb->skip_wkb_header() ||
return 1; wkb->scan_non_zero_uint4(&n_linear_rings))
n_linear_rings= uint4korr(data + WKB_HEADER_SIZE); return true;
data+= WKB_HEADER_SIZE + 4;
while (n_linear_rings--) while (n_linear_rings--)
{ {
if (!(data= get_mbr_for_points(mbr, data, 0))) if (get_mbr_for_points(mbr, wkb, 0))
return 1; return true;
} }
} }
*end= data; return false;
return 0;
} }
int Gis_multi_polygon::num_geometries(uint32 *num) const int Gis_multi_polygon::num_geometries(uint32 *num) const
{ {
*num= uint4korr(m_data); wkb_parser wkb(&m_wkb_data);
return 0; return wkb.scan_non_zero_uint4(num) ? 1 : 0;
} }
int Gis_multi_polygon::geometry_n(uint32 num, String *result) const int Gis_multi_polygon::geometry_n(uint32 num, String *result) const
{ {
uint32 n_polygons; uint32 n_polygons;
const char *data= m_data, *start_of_polygon; wkb_parser wkb(&m_wkb_data);
const char *start_of_polygon= wkb.data();
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_polygons))
return 1; return 1;
n_polygons= uint4korr(data);
data+= 4;
if (num > n_polygons || num < 1) if (num > n_polygons || num < 1)
return -1; return -1;
do do
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
start_of_polygon= data; start_of_polygon= wkb.data();
if (no_data(data, WKB_HEADER_SIZE + 4)) if (wkb.skip_wkb_header() ||
wkb.scan_non_zero_uint4(&n_linear_rings))
return 1; return 1;
n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
data+= WKB_HEADER_SIZE + 4;
while (n_linear_rings--) while (n_linear_rings--)
{ {
uint32 n_points; uint32 n_points;
if (no_data(data, 4)) if (wkb.scan_n_points_and_check_data(&n_points))
return 1; return 1;
n_points= uint4korr(data); wkb.skip_unsafe(POINT_DATA_SIZE * n_points);
data+= 4 + POINT_DATA_SIZE * n_points;
} }
} while (--num); } while (--num);
if (no_data(data, 0)) // We must check las t segment if (wkb.no_data(0)) // We must check last segmen t
return 1; return 1;
return result->append(start_of_polygon, (uint32) (data - start_of_polygon return result->append(start_of_polygon,
), (uint32) (wkb.data() - start_of_polygon),
(uint32) 0); (uint32) 0);
} }
int Gis_multi_polygon::area(double *ar, const char **end_of_data) const bool Gis_multi_polygon::area(double *ar, wkb_parser *wkb) const
{ {
Gis_polygon p; Gis_polygon p;
return collection_area(ar, end_of_data, &p); return collection_area(ar, wkb, &p);
} }
int Gis_multi_polygon::centroid(String *result) const int Gis_multi_polygon::centroid(String *result) const
{ {
uint32 n_polygons; uint32 n_polygons;
bool first_loop= 1; bool first_loop= 1;
Gis_polygon p; Gis_polygon p;
double UNINIT_VAR(res_area), UNINIT_VAR(res_cx), UNINIT_VAR(res_cy); double UNINIT_VAR(res_area);
double cur_area, cur_cx, cur_cy; point_xy res(0, 0); // Initialized only to make compiler hap
const char *data= m_data; py
wkb_parser wkb(&m_wkb_data);
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_polygons))
return 1; return 1;
n_polygons= uint4korr(data);
data+= 4;
while (n_polygons--) while (n_polygons--)
{ {
data+= WKB_HEADER_SIZE; double cur_area;
p.set_data_ptr(data, (uint32) (m_data_end - data)); point_xy cur;
if (p.area(&cur_area, &data) || if (wkb.skip_wkb_header())
p.centroid_xy(&cur_cx, &cur_cy)) return 1;
p.set_data_ptr(&wkb);
if (p.area(&cur_area, &wkb) ||
p.centroid_xy(&cur))
return 1; return 1;
if (!first_loop) if (!first_loop)
{ {
double sum_area= res_area + cur_area; double sum_area= res_area + cur_area;
res_cx= (res_area * res_cx + cur_area * cur_cx) / sum_area; res.x= (res_area * res.x + cur_area * cur.x) / sum_area;
res_cy= (res_area * res_cy + cur_area * cur_cy) / sum_area; res.y= (res_area * res.y + cur_area * cur.y) / sum_area;
} }
else else
{ {
first_loop= 0; first_loop= 0;
res_area= cur_area; res_area= cur_area;
res_cx= cur_cx; res= cur;
res_cy= cur_cy;
} }
} }
return create_point(result, res);
return create_point(result, res_cx, res_cy);
} }
int Gis_multi_polygon::store_shapes(Gcalc_shape_transporter *trn, int Gis_multi_polygon::store_shapes(Gcalc_shape_transporter *trn,
Gcalc_shape_status *st) const Gcalc_shape_status *st) const
{ {
if (trn->skip_poly()) if (trn->skip_poly())
return 0; return 0;
Gis_polygon p; Gis_polygon p;
return collection_store_shapes(trn, st, &p); return collection_store_shapes(trn, st, &p);
} }
skipping to change at line 1974 skipping to change at line 1823
const Geometry::Class_info *Gis_multi_polygon::get_class_info() const const Geometry::Class_info *Gis_multi_polygon::get_class_info() const
{ {
return &multipolygon_class; return &multipolygon_class;
} }
/************************* GeometryCollection ****************************/ /************************* GeometryCollection ****************************/
uint32 Gis_geometry_collection::get_data_size() const uint32 Gis_geometry_collection::get_data_size() const
{ {
uint32 n_objects; uint32 n_objects;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
Geometry_buffer buffer; Geometry_buffer buffer;
Geometry *geom; Geometry *geom;
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_objects))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
n_objects= uint4korr(data);
data+= 4;
while (n_objects--) while (n_objects--)
{ {
uint32 wkb_type,object_size; if (!(geom= scan_header_and_create(&wkb, &buffer)))
if (no_data(data, WKB_HEADER_SIZE))
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
wkb_type= uint4korr(data + 1);
data+= WKB_HEADER_SIZE;
if (!(geom= create_by_typeid(&buffer, wkb_type))) uint32 object_size;
return GET_SIZE_ERROR;
geom->set_data_ptr(data, (uint) (m_data_end - data));
if ((object_size= geom->get_data_size()) == GET_SIZE_ERROR) if ((object_size= geom->get_data_size()) == GET_SIZE_ERROR)
return GET_SIZE_ERROR; return GET_SIZE_ERROR;
data+= object_size; wkb.skip_unsafe(object_size);
} }
return (uint32) (data - m_data); return (uint32) (wkb.data() - m_wkb_data.data());
} }
bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *w kb) bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *w kb)
{ {
uint32 n_objects= 0; uint32 n_objects= 0;
uint32 no_pos= wkb->length(); uint32 no_pos= wkb->length();
Geometry_buffer buffer; Geometry_buffer buffer;
Geometry *g; Geometry *g;
if (wkb->reserve(4, 512)) if (wkb->reserve(4, 512))
return 1; return true;
wkb->length(wkb->length()+4); // Reserve space for points wkb->length(wkb->length()+4); // Reserve space for points
for (;;) for (;;)
{ {
if (!(g= create_from_wkt(&buffer, trs, wkb))) if (!(g= create_from_wkt(&buffer, trs, wkb)))
return 1; return true;
if (g->get_class_info()->m_type_id == wkb_geometrycollection) if (g->get_class_info()->m_type_id == wkb_geometrycollection)
{ {
trs->set_error_msg("Unexpected GEOMETRYCOLLECTION"); trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
return 1; return true;
} }
n_objects++; n_objects++;
if (trs->skip_char(',')) // Didn't find ',' if (trs->skip_char(',')) // Didn't find ','
break; break;
} }
wkb->write_at_position(no_pos, n_objects); wkb->write_at_position(no_pos, n_objects);
return 0; return false;
} }
uint Gis_geometry_collection::init_from_opresult(String *bin, uint Gis_geometry_collection::init_from_opresult(String *bin,
const char *opres, const char *opres,
uint opres_length) uint opres_length)
{ {
return collection_init_from_opresult(bin, opres, opres_length, NULL); return collection_init_from_opresult(bin, opres, opres_length, NULL);
} }
uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len, uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
skipping to change at line 2081 skipping to change at line 1922
(wkbByteOrder) wkb[0], res))) (wkbByteOrder) wkb[0], res)))
return 0; return 0;
g_len+= WKB_HEADER_SIZE; g_len+= WKB_HEADER_SIZE;
wkb+= g_len; wkb+= g_len;
len-= g_len; len-= g_len;
} }
return (uint) (wkb - wkb_orig); return (uint) (wkb - wkb_orig);
} }
bool Gis_geometry_collection::get_data_as_wkt(String *txt, bool Gis_geometry_collection::get_data_as_wkt(String *txt,
const char **end) const wkb_parser *wkb) const
{ {
uint32 n_objects; uint32 n_objects;
Geometry_buffer buffer; Geometry_buffer buffer;
Geometry *geom; Geometry *geom;
const char *data= m_data;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_objects))
return 1; return true;
n_objects= uint4korr(data);
data+= 4;
while (n_objects--) while (n_objects--)
{ {
uint32 wkb_type; if (!(geom= scan_header_and_create(wkb, &buffer)) ||
geom->as_wkt(txt, wkb) ||
if (no_data(data, WKB_HEADER_SIZE)) txt->append(STRING_WITH_LEN(","), 512))
return 1; return true;
wkb_type= uint4korr(data + 1);
data+= WKB_HEADER_SIZE;
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1;
geom->set_data_ptr(data, (uint) (m_data_end - data));
if (geom->as_wkt(txt, &data))
return 1;
if (txt->append(STRING_WITH_LEN(","), 512))
return 1;
} }
txt->length(txt->length() - 1); txt->length(txt->length() - 1);
*end= data; return false;
return 0;
} }
bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const bool Gis_geometry_collection::get_mbr(MBR *mbr, wkb_parser *wkb) const
{ {
uint32 n_objects; uint32 n_objects;
const char *data= m_data;
Geometry_buffer buffer; Geometry_buffer buffer;
Geometry *geom; Geometry *geom;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_objects))
return 1; return true;
n_objects= uint4korr(data);
data+= 4;
while (n_objects--) while (n_objects--)
{ {
uint32 wkb_type; if (!(geom= scan_header_and_create(wkb, &buffer)) ||
geom->get_mbr(mbr, wkb))
if (no_data(data, WKB_HEADER_SIZE)) return true;
return 1;
wkb_type= uint4korr(data + 1);
data+= WKB_HEADER_SIZE;
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1;
geom->set_data_ptr(data, (uint32) (m_data_end - data));
if (geom->get_mbr(mbr, &data))
return 1;
} }
*end= data; return false;
return 0;
} }
int Gis_geometry_collection::area(double *ar, const char **end_of_data) con st bool Gis_geometry_collection::area(double *ar, wkb_parser *wkb) const
{ {
return collection_area(ar, end_of_data, NULL); return collection_area(ar, wkb, NULL);
} }
int Gis_geometry_collection::num_geometries(uint32 *num) const int Gis_geometry_collection::num_geometries(uint32 *num) const
{ {
if (no_data(m_data, 4)) wkb_parser wkb(&m_wkb_data);
return 1; return wkb.scan_non_zero_uint4(num) ? 1 : 0;
*num= uint4korr(m_data);
return 0;
} }
int Gis_geometry_collection::geometry_n(uint32 num, String *result) const int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
{ {
uint32 n_objects, wkb_type, length; uint32 n_objects, length;
const char *data= m_data; wkb_parser wkb(&m_wkb_data);
Geometry_buffer buffer; Geometry_buffer buffer;
Geometry *geom; Geometry *geom;
if (no_data(data, 4)) if (wkb.scan_non_zero_uint4(&n_objects))
return 1; return 1;
n_objects= uint4korr(data);
data+= 4;
if (num > n_objects || num < 1) if (num > n_objects || num < 1)
return 1; return 1;
wkb_header header;
do do
{ {
if (no_data(data, WKB_HEADER_SIZE)) if (wkb.scan_wkb_header(&header) ||
return 1; !(geom= create_by_typeid(&buffer, header.wkb_type)))
wkb_type= uint4korr(data + 1);
data+= WKB_HEADER_SIZE;
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1; return 1;
geom->set_data_ptr(data, (uint) (m_data_end - data)); geom->set_data_ptr(&wkb);
if ((length= geom->get_data_size()) == GET_SIZE_ERROR) if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
return 1; return 1;
data+= length; wkb.skip_unsafe(length);
} while (--num); } while (--num);
/* Copy found object to result */ /* Copy found object to result */
if (result->reserve(1 + 4 + length)) if (result->reserve(1 + 4 + length))
return 1; return 1;
result->q_append((char) wkb_ndr); result->q_append((char) wkb_ndr);
result->q_append((uint32) wkb_type); result->q_append((uint32) header.wkb_type);
result->q_append(data-length, length); // data-length = start_of_da result->q_append(wkb.data() - length, length); // data-length = start_of_
ta data
return 0; return 0;
} }
/* /*
Return dimension for object Return dimension for object
SYNOPSIS SYNOPSIS
dimension() dimension()
res_dim Result dimension res_dim Result dimension
end End of object will be stored here. May be 0 for end End of object will be stored here. May be 0 for
simple objects! simple objects!
RETURN RETURN
0 ok 0 ok
1 error 1 error
*/ */
bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) bool Gis_geometry_collection::dimension(uint32 *res_dim,
const wkb_parser *wkb) const
{ {
uint32 n_objects; uint32 n_objects;
const char *data= m_data;
Geometry_buffer buffer; Geometry_buffer buffer;
Geometry *geom; Geometry *geom;
if (no_data(data, 4)) if (wkb->scan_non_zero_uint4(&n_objects))
return 1; return true;
n_objects= uint4korr(data);
data+= 4;
*res_dim= 0; *res_dim= 0;
while (n_objects--) while (n_objects--)
{ {
uint32 wkb_type, length, dim; uint32 dim;
const char *end_data; if (!(geom= scan_header_and_create(wkb, &buffer)) ||
geom->dimension(&dim, wkb))
if (no_data(data, WKB_HEADER_SIZE)) return true;
return 1;
wkb_type= uint4korr(data + 1);
data+= WKB_HEADER_SIZE;
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1;
geom->set_data_ptr(data, (uint32) (m_data_end - data));
if (geom->dimension(&dim, &end_data))
return 1;
set_if_bigger(*res_dim, dim); set_if_bigger(*res_dim, dim);
if (end_data) // Complex object
data= end_data;
else if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
return 1;
else
data+= length;
} }
*end= data; return false;
return 0;
} }
int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn, int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn,
Gcalc_shape_status *st) const Gcalc_shape_status *st) const
{ {
return collection_store_shapes(trn, st, NULL); return collection_store_shapes(trn, st, NULL);
} }
const Geometry::Class_info *Gis_geometry_collection::get_class_info() const const Geometry::Class_info *Gis_geometry_collection::get_class_info() const
{ {
 End of changes. 300 change blocks. 
661 lines changed or deleted 452 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/