675 lines
21 KiB
C++
675 lines
21 KiB
C++
/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software Foundation,
|
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
|
|
|
|
|
|
/**
|
|
@file
|
|
|
|
@brief
|
|
This file defines ST_Buffer function.
|
|
*/
|
|
#include "my_config.h"
|
|
#include "item_geofunc.h"
|
|
|
|
#include "sql_class.h" // THD
|
|
|
|
#include "item_geofunc_internal.h"
|
|
#include "gis_bg_traits.h"
|
|
|
|
|
|
static const char *const buffer_strategy_names []=
|
|
{
|
|
"invalid_strategy",
|
|
"end_round",
|
|
"end_flat",
|
|
"join_round",
|
|
"join_miter",
|
|
"point_circle",
|
|
"point_square"
|
|
};
|
|
|
|
template <typename Char_type>
|
|
inline int char_icmp(const Char_type a, const Char_type b)
|
|
{
|
|
const int a1= std::tolower(a);
|
|
const int b1= std::tolower(b);
|
|
return a1 > b1 ? 1 : (a1 < b1 ? -1 : 0);
|
|
}
|
|
|
|
/**
|
|
Case insensitive comparison of two ascii strings.
|
|
@param a '\0' ended string.
|
|
@param b '\0' ended string.
|
|
*/
|
|
template <typename Char_type>
|
|
int str_icmp(const Char_type *a, const Char_type *b)
|
|
{
|
|
int ret= 0, i;
|
|
|
|
for (i= 0; a[i] != 0 && b[i] != 0; i++)
|
|
if ((ret= char_icmp(a[i], b[i])))
|
|
return ret;
|
|
if (a[i] == 0 && b[i] != 0)
|
|
return -1;
|
|
if (a[i] != 0 && b[i] == 0)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Convert strategies stored in String objects into Strategy_setting objects.
|
|
*/
|
|
void Item_func_buffer::set_strategies()
|
|
{
|
|
for (int i= 0; i < num_strats; i++)
|
|
{
|
|
String *pstr= strategies[i];
|
|
const uchar *pstrat= pointer_cast<const uchar *>(pstr->ptr());
|
|
|
|
uint32 snum= 0;
|
|
|
|
if (pstr->length() != 12 ||
|
|
!((snum= uint4korr(pstrat)) > invalid_strategy && snum <= max_strategy))
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "st_buffer");
|
|
null_value= true;
|
|
return;
|
|
}
|
|
|
|
const enum_buffer_strategies strat= (enum_buffer_strategies)snum;
|
|
double value;
|
|
float8get(&value, pstrat + 4);
|
|
enum_buffer_strategy_types strategy_type= invalid_strategy_type;
|
|
|
|
switch (strat)
|
|
{
|
|
case end_round:
|
|
case end_flat:
|
|
strategy_type= end_strategy;
|
|
break;
|
|
case join_round:
|
|
case join_miter:
|
|
strategy_type= join_strategy;
|
|
break;
|
|
case point_circle:
|
|
case point_square:
|
|
strategy_type= point_strategy;
|
|
break;
|
|
default:
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "st_buffer");
|
|
null_value= true;
|
|
return;
|
|
break;
|
|
}
|
|
|
|
// Each strategy option can be set no more than once for every ST_Buffer()
|
|
// call.
|
|
if (settings[strategy_type].strategy != invalid_strategy)
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "st_buffer");
|
|
null_value= true;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
settings[strategy_type].strategy= (enum_buffer_strategies)snum;
|
|
settings[strategy_type].value= value;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Item_func_buffer_strategy::
|
|
Item_func_buffer_strategy(const POS &pos, PT_item_list *ilist)
|
|
:Item_str_func(pos, ilist)
|
|
{
|
|
// Here we want to use the String::set(const char*, ..) version.
|
|
const char *pbuf= tmp_buffer;
|
|
tmp_value.set(pbuf, 0, NULL);
|
|
}
|
|
|
|
|
|
void Item_func_buffer_strategy::fix_length_and_dec()
|
|
{
|
|
collation.set(&my_charset_bin);
|
|
decimals=0;
|
|
max_length= 16;
|
|
maybe_null= 1;
|
|
}
|
|
|
|
String *Item_func_buffer_strategy::val_str(String * /* str_arg */)
|
|
{
|
|
String str;
|
|
String *strat_name= args[0]->val_str_ascii(&str);
|
|
if ((null_value= args[0]->null_value))
|
|
{
|
|
DBUG_ASSERT(maybe_null);
|
|
return NULL;
|
|
}
|
|
|
|
// Get the NULL-terminated ascii string.
|
|
const char *pstrat_name= strat_name->c_ptr_safe();
|
|
|
|
bool found= false;
|
|
|
|
tmp_value.set_charset(&my_charset_bin);
|
|
// The tmp_value is supposed to always stores a {uint32,double} pair,
|
|
// and it uses a char tmp_buffer[16] array data member.
|
|
uchar *result_buf= const_cast<uchar *>(pointer_cast<const uchar *>
|
|
(tmp_value.ptr()));
|
|
|
|
// Although the result of this item node is never persisted, we still have to
|
|
// use portable endianess access otherwise unaligned access will crash
|
|
// on sparc CPUs.
|
|
for (uint32 i= 0; i <= Item_func_buffer::max_strategy; i++)
|
|
{
|
|
// The above var_str_ascii() call makes the strat_name an ascii string so
|
|
// we can do below comparison.
|
|
if (str_icmp(pstrat_name, buffer_strategy_names[i]) != 0)
|
|
continue;
|
|
|
|
int4store(result_buf, i);
|
|
result_buf+= 4;
|
|
Item_func_buffer::enum_buffer_strategies istrat=
|
|
static_cast<Item_func_buffer::enum_buffer_strategies>(i);
|
|
|
|
/*
|
|
The end_flat and point_square strategies must have no more arguments;
|
|
The rest strategies must have 2nd parameter which must be a positive
|
|
numeric value, and we will store it as a double.
|
|
We use float8store to ensure that the value is independent of endianness.
|
|
*/
|
|
if (istrat != Item_func_buffer::end_flat &&
|
|
istrat != Item_func_buffer::point_square)
|
|
{
|
|
if (arg_count != 2)
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
|
|
return error_str();
|
|
}
|
|
|
|
double val= args[1]->val_real();
|
|
if ((null_value= args[1]->null_value))
|
|
{
|
|
DBUG_ASSERT(maybe_null);
|
|
return NULL;
|
|
}
|
|
if (val <= 0)
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
|
|
return error_str();
|
|
}
|
|
|
|
if (istrat != Item_func_buffer::join_miter &&
|
|
val > current_thd->variables.max_points_in_geometry)
|
|
{
|
|
my_error(ER_GIS_MAX_POINTS_IN_GEOMETRY_OVERFLOWED, MYF(0),
|
|
"points_per_circle",
|
|
current_thd->variables.max_points_in_geometry,
|
|
func_name());
|
|
return error_str();
|
|
}
|
|
|
|
float8store(result_buf, val);
|
|
}
|
|
else if (arg_count != 1)
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
|
|
return error_str();
|
|
}
|
|
else
|
|
float8store(result_buf, 0.0);
|
|
|
|
found= true;
|
|
|
|
break;
|
|
}
|
|
|
|
// Unrecognized strategy names, report error.
|
|
if (!found)
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
|
|
return error_str();
|
|
}
|
|
tmp_value.length(12);
|
|
|
|
return &tmp_value;
|
|
}
|
|
|
|
|
|
#define CALL_BG_BUFFER(result, geom, geom_out, dist_strategy, side_strategy,\
|
|
join_strategy, end_strategy, point_strategy) do {\
|
|
(result)= false;\
|
|
switch ((geom)->get_type())\
|
|
{\
|
|
case Geometry::wkb_point:\
|
|
{\
|
|
BG_models<bgcs::cartesian>::Point\
|
|
bg((geom)->get_data_ptr(), (geom)->get_data_size(),\
|
|
(geom)->get_flags(), (geom)->get_srid());\
|
|
bg::buffer(bg, (geom_out), (dist_strategy), (side_strategy),\
|
|
(join_strategy), (end_strategy), (point_strategy));\
|
|
break;\
|
|
}\
|
|
case Geometry::wkb_multipoint:\
|
|
{\
|
|
BG_models<bgcs::cartesian>::Multipoint\
|
|
bg((geom)->get_data_ptr(), (geom)->get_data_size(),\
|
|
(geom)->get_flags(), (geom)->get_srid());\
|
|
bg::buffer(bg, (geom_out), (dist_strategy), (side_strategy),\
|
|
(join_strategy), (end_strategy), (point_strategy));\
|
|
break;\
|
|
}\
|
|
case Geometry::wkb_linestring:\
|
|
{\
|
|
BG_models<bgcs::cartesian>::Linestring\
|
|
bg((geom)->get_data_ptr(), (geom)->get_data_size(),\
|
|
(geom)->get_flags(), (geom)->get_srid());\
|
|
bg::buffer(bg, (geom_out), (dist_strategy), (side_strategy),\
|
|
(join_strategy), (end_strategy), (point_strategy));\
|
|
break;\
|
|
}\
|
|
case Geometry::wkb_multilinestring:\
|
|
{\
|
|
BG_models<bgcs::cartesian>::Multilinestring\
|
|
bg((geom)->get_data_ptr(), (geom)->get_data_size(),\
|
|
(geom)->get_flags(), (geom)->get_srid());\
|
|
bg::buffer(bg, (geom_out), (dist_strategy), (side_strategy),\
|
|
(join_strategy), (end_strategy), (point_strategy));\
|
|
break;\
|
|
}\
|
|
case Geometry::wkb_polygon:\
|
|
{\
|
|
const void *data_ptr= (geom)->normalize_ring_order();\
|
|
if (data_ptr == NULL)\
|
|
{\
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), "st_buffer");\
|
|
(result)= true;\
|
|
break; \
|
|
}\
|
|
BG_models<bgcs::cartesian>::Polygon\
|
|
bg(data_ptr, (geom)->get_data_size(),\
|
|
(geom)->get_flags(), (geom)->get_srid());\
|
|
bg::buffer(bg, (geom_out), (dist_strategy), (side_strategy),\
|
|
(join_strategy), (end_strategy), (point_strategy));\
|
|
break;\
|
|
}\
|
|
case Geometry::wkb_multipolygon:\
|
|
{\
|
|
const void *data_ptr= (geom)->normalize_ring_order();\
|
|
if (data_ptr == NULL)\
|
|
{\
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), "st_buffer");\
|
|
(result)= true;\
|
|
break; \
|
|
}\
|
|
BG_models<bgcs::cartesian>::Multipolygon\
|
|
bg(data_ptr, (geom)->get_data_size(),\
|
|
(geom)->get_flags(), (geom)->get_srid());\
|
|
bg::buffer(bg, (geom_out), (dist_strategy), (side_strategy),\
|
|
(join_strategy), (end_strategy), (point_strategy));\
|
|
break;\
|
|
}\
|
|
default:\
|
|
DBUG_ASSERT(false);\
|
|
break;\
|
|
}\
|
|
} while(0)
|
|
|
|
|
|
Item_func_buffer::Item_func_buffer(const POS &pos, PT_item_list *ilist)
|
|
:Item_geometry_func(pos, ilist)
|
|
{
|
|
num_strats= 0;
|
|
memset(settings, 0, sizeof(settings));
|
|
memset(strategies, 0, sizeof(strategies));
|
|
}
|
|
|
|
|
|
namespace bgst= boost::geometry::strategy::buffer;
|
|
|
|
String *Item_func_buffer::val_str(String *str_value_arg)
|
|
{
|
|
DBUG_ENTER("Item_func_buffer::val_str");
|
|
DBUG_ASSERT(fixed == 1);
|
|
String strat_bufs[side_strategy + 1];
|
|
String *obj= args[0]->val_str(&tmp_value);
|
|
double dist= args[1]->val_real();
|
|
Geometry_buffer buffer;
|
|
Geometry *geom;
|
|
String *str_result= str_value_arg;
|
|
|
|
null_value= false;
|
|
bg_resbuf_mgr.free_result_buffer();
|
|
|
|
if (!obj || args[0]->null_value || args[1]->null_value)
|
|
DBUG_RETURN(error_str());
|
|
|
|
// Reset the two arrays, set_strategies() requires the settings array to
|
|
// be brand new on every ST_Buffer() call.
|
|
memset(settings, 0, sizeof(settings));
|
|
memset(strategies, 0, sizeof(strategies));
|
|
|
|
// Strategies options start from 3rd argument, the 1st two arguments are
|
|
// never strategies: the 1st is input geometry, and the 2nd is distance.
|
|
num_strats= arg_count - 2;
|
|
for (uint i= 2; i < arg_count; i++)
|
|
{
|
|
strategies[i - 2]= args[i]->val_str(&strat_bufs[i]);
|
|
if (strategies[i - 2] == NULL || args[i]->null_value)
|
|
DBUG_RETURN(error_str());
|
|
}
|
|
|
|
/*
|
|
Do this before simplify_multi_geometry() in order to exclude invalid
|
|
WKB/WKT data.
|
|
*/
|
|
if (!(geom= Geometry::construct(&buffer, obj)))
|
|
{
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), func_name());
|
|
DBUG_RETURN(error_str());
|
|
}
|
|
|
|
/*
|
|
If the input geometry is a multi-geometry or geometry collection that has
|
|
only one component, extract that component as input argument.
|
|
*/
|
|
Geometry::wkbType geom_type= geom->get_type();
|
|
if (geom_type == Geometry::wkb_multipoint ||
|
|
geom_type == Geometry::wkb_multipolygon ||
|
|
geom_type == Geometry::wkb_multilinestring ||
|
|
geom_type == Geometry::wkb_geometrycollection)
|
|
{
|
|
/*
|
|
Make a copy of the geometry byte string argument to work on it,
|
|
don't modify the original one since it is assumed to be stable.
|
|
Simplifying the argument is worth the effort because buffer computation
|
|
is less expensive with simplified geometry.
|
|
|
|
The copy's buffer may be directly returned as result so it has to be a
|
|
data member.
|
|
|
|
Here we assume that if obj->is_alloced() is false, obj's referring to some
|
|
geometry data stored somewhere else so here we cache the simplified
|
|
version into m_tmp_geombuf without modifying obj's original referred copy;
|
|
otherwise we believe the geometry data
|
|
is solely owned by obj and that each call of this ST_Buffer() is given
|
|
a valid GEOMETRY byte string, i.e. it is structually valid and if it was
|
|
simplified before, the obj->m_length was correctly set to the new length
|
|
after the simplification operation.
|
|
*/
|
|
const bool use_buffer= !obj->is_alloced();
|
|
if (simplify_multi_geometry(obj, (use_buffer ? &m_tmp_geombuf : NULL)) &&
|
|
use_buffer)
|
|
obj= &m_tmp_geombuf;
|
|
|
|
if (!(geom= Geometry::construct(&buffer, obj)))
|
|
{
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), func_name());
|
|
DBUG_RETURN(error_str());
|
|
}
|
|
}
|
|
|
|
/*
|
|
If distance passed to ST_Buffer is too small, then we return the
|
|
original geometry as its buffer. This is needed to avoid division
|
|
overflow in buffer calculation, as well as for performance purposes.
|
|
*/
|
|
if (std::abs(dist) <= GIS_ZERO || is_empty_geocollection(geom))
|
|
{
|
|
null_value= 0;
|
|
str_result= obj;
|
|
DBUG_RETURN(str_result);
|
|
}
|
|
|
|
Geometry::wkbType gtype= geom->get_type();
|
|
if (dist < 0 && gtype != Geometry::wkb_polygon &&
|
|
gtype != Geometry::wkb_multipolygon &&
|
|
gtype != Geometry::wkb_geometrycollection)
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
|
|
DBUG_RETURN(error_str());
|
|
}
|
|
|
|
set_strategies();
|
|
if (null_value)
|
|
DBUG_RETURN(error_str());
|
|
|
|
/*
|
|
str_result will refer to BG object's memory directly if any, here we remove
|
|
last call's remainings so that if this call doesn't produce any result,
|
|
this call won't note down last address(already freed above) and
|
|
next call won't free already free'd memory.
|
|
*/
|
|
str_result->set(NullS, 0, &my_charset_bin);
|
|
bool had_except= false;
|
|
|
|
try
|
|
{
|
|
Strategy_setting ss1= settings[end_strategy];
|
|
Strategy_setting ss2= settings[join_strategy];
|
|
Strategy_setting ss3= settings[point_strategy];
|
|
|
|
const bool is_pts= (gtype == Geometry::wkb_point ||
|
|
gtype == Geometry::wkb_multipoint);
|
|
|
|
const bool is_plygn= (gtype == Geometry::wkb_polygon ||
|
|
gtype == Geometry::wkb_multipolygon);
|
|
const bool is_ls= (gtype == Geometry::wkb_linestring ||
|
|
gtype == Geometry::wkb_multilinestring);
|
|
|
|
/*
|
|
Some strategies can be applied to only part of the geometry types and
|
|
coordinate systems. For now we only have cartesian coordinate system
|
|
so no check for them.
|
|
*/
|
|
if ((is_pts && (ss1.strategy != invalid_strategy ||
|
|
ss2.strategy != invalid_strategy)) ||
|
|
(is_plygn && (ss1.strategy != invalid_strategy ||
|
|
ss3.strategy != invalid_strategy)) ||
|
|
(is_ls && ss3.strategy != invalid_strategy))
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
|
|
DBUG_RETURN(error_str());
|
|
}
|
|
|
|
bgst::distance_symmetric<double> dist_strat(dist);
|
|
bgst::side_straight side_strat;
|
|
bgst::end_round bgst_end_round(ss1.strategy ==
|
|
invalid_strategy ? 32 : ss1.value);
|
|
bgst::end_flat bgst_end_flat;
|
|
bgst::join_round bgst_join_round(ss2.strategy ==
|
|
invalid_strategy ? 32 : ss2.value);
|
|
bgst::join_miter bgst_join_miter(ss2.value);
|
|
bgst::point_circle bgst_point_circle(ss3.strategy ==
|
|
invalid_strategy ? 32 : ss3.value);
|
|
bgst::point_square bgst_point_square;
|
|
|
|
/*
|
|
Default strategies if not specified:
|
|
end_round(32), join_round(32), point_circle(32)
|
|
The order of enum items in enum enum_buffer_strategies is crucial for
|
|
this setting to be correct, don't modify it.
|
|
|
|
Although point strategy isn't needed for linear and areal geometries,
|
|
we have to specify it because of bg::buffer interface, and BG will
|
|
silently ignore it. Similarly for other strategies.
|
|
*/
|
|
int strats_combination= 0;
|
|
if (ss1.strategy == end_flat)
|
|
strats_combination|= 1;
|
|
if (ss2.strategy == join_miter)
|
|
strats_combination|= 2;
|
|
if (ss3.strategy == point_square)
|
|
strats_combination|= 4;
|
|
|
|
BG_models<bgcs::cartesian>::Multipolygon result;
|
|
result.set_srid(geom->get_srid());
|
|
|
|
if (geom->get_type() != Geometry::wkb_geometrycollection)
|
|
{
|
|
bool ret= false;
|
|
switch (strats_combination)
|
|
{
|
|
case 0:
|
|
CALL_BG_BUFFER(ret, geom, result, dist_strat, side_strat,
|
|
bgst_join_round, bgst_end_round, bgst_point_circle);
|
|
break;
|
|
case 1:
|
|
CALL_BG_BUFFER(ret, geom, result, dist_strat, side_strat,
|
|
bgst_join_round, bgst_end_flat, bgst_point_circle);
|
|
break;
|
|
case 2:
|
|
CALL_BG_BUFFER(ret, geom, result, dist_strat, side_strat,
|
|
bgst_join_miter, bgst_end_round, bgst_point_circle);
|
|
break;
|
|
case 3:
|
|
CALL_BG_BUFFER(ret, geom, result, dist_strat, side_strat,
|
|
bgst_join_miter, bgst_end_flat, bgst_point_circle);
|
|
break;
|
|
case 4:
|
|
CALL_BG_BUFFER(ret, geom, result, dist_strat, side_strat,
|
|
bgst_join_round, bgst_end_round, bgst_point_square);
|
|
break;
|
|
case 5:
|
|
CALL_BG_BUFFER(ret, geom, result, dist_strat, side_strat,
|
|
bgst_join_round, bgst_end_flat, bgst_point_square);
|
|
break;
|
|
case 6:
|
|
CALL_BG_BUFFER(ret, geom, result, dist_strat, side_strat,
|
|
bgst_join_miter, bgst_end_round, bgst_point_square);
|
|
break;
|
|
case 7:
|
|
CALL_BG_BUFFER(ret, geom, result, dist_strat, side_strat,
|
|
bgst_join_miter, bgst_end_flat, bgst_point_square);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
if (ret)
|
|
DBUG_RETURN(error_str());
|
|
|
|
if (result.size() == 0)
|
|
{
|
|
str_result->reserve(GEOM_HEADER_SIZE + 4);
|
|
write_geometry_header(str_result, geom->get_srid(),
|
|
Geometry::wkb_geometrycollection, 0);
|
|
DBUG_RETURN(str_result);
|
|
}
|
|
else if (post_fix_result(&bg_resbuf_mgr, result, str_result))
|
|
DBUG_RETURN(error_str());
|
|
bg_resbuf_mgr.set_result_buffer(const_cast<char *>(str_result->ptr()));
|
|
}
|
|
else
|
|
{
|
|
// Compute buffer for a geometry collection(GC). We first compute buffer
|
|
// for each component of the GC, and put the buffer polygons into another
|
|
// collection, finally merge components of the collection.
|
|
BG_geometry_collection bggc, bggc2;
|
|
bggc.fill(geom);
|
|
|
|
for (BG_geometry_collection::Geometry_list::iterator
|
|
i= bggc.get_geometries().begin();
|
|
i != bggc.get_geometries().end(); ++i)
|
|
{
|
|
|
|
BG_models<bgcs::cartesian>::Multipolygon res;
|
|
String temp_result;
|
|
|
|
res.set_srid((*i)->get_srid());
|
|
Geometry::wkbType gtype= (*i)->get_type();
|
|
if (dist < 0 && gtype != Geometry::wkb_multipolygon &&
|
|
gtype != Geometry::wkb_polygon)
|
|
{
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
|
|
DBUG_RETURN(error_str());
|
|
}
|
|
|
|
bool ret= false;
|
|
switch (strats_combination)
|
|
{
|
|
case 0:
|
|
CALL_BG_BUFFER(ret, *i, res, dist_strat, side_strat,
|
|
bgst_join_round, bgst_end_round, bgst_point_circle);
|
|
break;
|
|
case 1:
|
|
CALL_BG_BUFFER(ret, *i, res, dist_strat, side_strat,
|
|
bgst_join_round, bgst_end_flat, bgst_point_circle);
|
|
break;
|
|
case 2:
|
|
CALL_BG_BUFFER(ret, *i, res, dist_strat, side_strat,
|
|
bgst_join_miter, bgst_end_round, bgst_point_circle);
|
|
break;
|
|
case 3:
|
|
CALL_BG_BUFFER(ret, *i, res, dist_strat, side_strat,
|
|
bgst_join_miter, bgst_end_flat, bgst_point_circle);
|
|
break;
|
|
case 4:
|
|
CALL_BG_BUFFER(ret, *i, res, dist_strat, side_strat,
|
|
bgst_join_round, bgst_end_round, bgst_point_square);
|
|
break;
|
|
case 5:
|
|
CALL_BG_BUFFER(ret, *i, res, dist_strat, side_strat,
|
|
bgst_join_round, bgst_end_flat, bgst_point_square);
|
|
break;
|
|
case 6:
|
|
CALL_BG_BUFFER(ret, *i, res, dist_strat, side_strat,
|
|
bgst_join_miter, bgst_end_round, bgst_point_square);
|
|
break;
|
|
case 7:
|
|
CALL_BG_BUFFER(ret, *i, res, dist_strat, side_strat,
|
|
bgst_join_miter, bgst_end_flat, bgst_point_square);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
if (ret)
|
|
DBUG_RETURN(error_str());
|
|
if (res.size() == 0)
|
|
continue;
|
|
if (post_fix_result(&bg_resbuf_mgr, res, &temp_result))
|
|
DBUG_RETURN(error_str());
|
|
|
|
// A single component's buffer is computed above and stored here.
|
|
bggc2.fill(&res);
|
|
}
|
|
|
|
// Merge the accumulated polygons because they may overlap.
|
|
bggc2.merge_components<bgcs::cartesian>(&null_value);
|
|
Gis_geometry_collection *gc= bggc2.as_geometry_collection(str_result);
|
|
delete gc;
|
|
}
|
|
|
|
/*
|
|
If the result geometry is a multi-geometry or geometry collection that has
|
|
only one component, extract that component as result.
|
|
*/
|
|
simplify_multi_geometry(str_result, NULL);
|
|
}
|
|
catch (...)
|
|
{
|
|
had_except= true;
|
|
handle_gis_exception("st_buffer");
|
|
}
|
|
|
|
if (had_except)
|
|
DBUG_RETURN(error_str());
|
|
DBUG_RETURN(str_result);
|
|
}
|