mirror of
https://github.com/MariaDB/server.git
synced 2026-04-22 08:15:31 +02:00
bug #901655 ST_BUFFER asserts with a coplicated shape.
Coinciding nodes can appear as a result of DOUBLE inaccuracy.
We should test that before we start the loop.
Also the spatial relations can be calculated faster if we check
MBR relations first. And we do have the shape's MBR-s now.
per-file comments:
sql/gcalc_slicescan.cc
set_extent() method added.
bug #901655 ST_BUFFER asserts with a coplicated shape.
sql/gcalc_slicescan.h
set_extent() method declared.
bug #901655 ST_BUFFER asserts with a coplicated shape.
sql/gcalc_tools.cc
bug #901655 ST_BUFFER asserts with a coplicated shape.
checks for equal nodes added.
sql/item_geofunc.cc
bug #901655 ST_BUFFER asserts with a coplicated shape.
MBR for the shapes calculated, and MBR checks added before we
start the heavy calculations.
sql/spatial.h
bug #901655 ST_BUFFER asserts with a coplicated shape.
MBR::buffer() method implemented.
This commit is contained in:
parent
ae480437ce
commit
fc9d34cabf
5 changed files with 132 additions and 192 deletions
|
|
@ -406,7 +406,7 @@ static int de_weak_check(long double a, long double b, long double ex)
|
|||
|
||||
static int de_check(long double a, long double b)
|
||||
{
|
||||
return de_weak_check(a, b, (long double) 1e-10);
|
||||
return de_weak_check(a, b, (long double) 1e-9);
|
||||
}
|
||||
#endif /*GCALC_CHECK_WITH_FLOAT*/
|
||||
|
||||
|
|
@ -792,10 +792,51 @@ static int cmp_intersections(const Gcalc_heap::Info *i1,
|
|||
/* Internal coordinates implementation end */
|
||||
|
||||
|
||||
#define GCALC_SCALE_1 1e18
|
||||
|
||||
static double find_scale(double extent)
|
||||
{
|
||||
double scale= 1e-2;
|
||||
while (scale < extent)
|
||||
scale*= (double ) 10;
|
||||
return GCALC_SCALE_1 / scale / 10;
|
||||
}
|
||||
|
||||
|
||||
void Gcalc_heap::set_extent(double xmin, double xmax, double ymin, double ymax)
|
||||
{
|
||||
xmin= fabs(xmin);
|
||||
xmax= fabs(xmax);
|
||||
ymin= fabs(ymin);
|
||||
ymax= fabs(ymax);
|
||||
|
||||
if (xmax < xmin)
|
||||
xmax= xmin;
|
||||
if (ymax < ymin)
|
||||
ymax= ymin;
|
||||
|
||||
coord_extent= xmax > ymax ? xmax : ymax;
|
||||
coord_extent= find_scale(coord_extent);
|
||||
#ifdef GCALC_CHECK_WITH_FLOAT
|
||||
gcalc_coord_extent= &coord_extent;
|
||||
#endif /*GCALC_CHECK_WITH_FLOAT*/
|
||||
}
|
||||
|
||||
|
||||
void Gcalc_heap::free_point_info(Gcalc_heap::Info *i,
|
||||
Gcalc_dyn_list::Item **i_hook)
|
||||
{
|
||||
if (m_hook == &i->next)
|
||||
m_hook= i_hook;
|
||||
*i_hook= i->next;
|
||||
free_item(i);
|
||||
m_n_points--;
|
||||
}
|
||||
|
||||
|
||||
Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y,
|
||||
gcalc_shape_info shape)
|
||||
{
|
||||
double abs= fabs(x);
|
||||
Info *result= (Info *)new_item();
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
|
@ -806,17 +847,8 @@ Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y,
|
|||
result->shape= shape;
|
||||
result->top_node= 1;
|
||||
result->type= nt_shape_node;
|
||||
if (m_n_points)
|
||||
{
|
||||
if (abs > coord_extent)
|
||||
coord_extent= abs;
|
||||
}
|
||||
else
|
||||
coord_extent= abs;
|
||||
|
||||
abs= fabs(y);
|
||||
if (abs > coord_extent)
|
||||
coord_extent= abs;
|
||||
gcalc_set_double(result->ix, x, coord_extent);
|
||||
gcalc_set_double(result->iy, y, coord_extent);
|
||||
|
||||
m_n_points++;
|
||||
return result;
|
||||
|
|
@ -927,32 +959,12 @@ static int compare_point_info(const void *e0, const void *e1)
|
|||
}
|
||||
|
||||
|
||||
#define GCALC_SCALE_1 1e18
|
||||
|
||||
static double find_scale(double extent)
|
||||
{
|
||||
double scale= 1e-2;
|
||||
while (scale < extent)
|
||||
scale*= (double ) 10;
|
||||
return GCALC_SCALE_1 / scale / 10;
|
||||
}
|
||||
|
||||
|
||||
void Gcalc_heap::prepare_operation()
|
||||
{
|
||||
Info *cur;
|
||||
GCALC_DBUG_ASSERT(m_hook);
|
||||
coord_extent= find_scale(coord_extent);
|
||||
#ifdef GCALC_CHECK_WITH_FLOAT
|
||||
gcalc_coord_extent= &coord_extent;
|
||||
#endif /*GCALC_CHECK_WITH_FLOAT*/
|
||||
*m_hook= NULL;
|
||||
m_hook= NULL; /* just to check it's not called twice */
|
||||
for (cur= get_first(); cur; cur= cur->get_next())
|
||||
{
|
||||
gcalc_set_double(cur->ix, cur->x, coord_extent);
|
||||
gcalc_set_double(cur->iy, cur->y, coord_extent);
|
||||
}
|
||||
m_first= sort_list(compare_point_info, m_first, m_n_points);
|
||||
|
||||
/* TODO - move this to the 'normal_scan' loop */
|
||||
|
|
@ -990,18 +1002,28 @@ int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info,
|
|||
double x, double y)
|
||||
{
|
||||
Gcalc_heap::Info *point;
|
||||
GCALC_DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y);
|
||||
Gcalc_dyn_list::Item **hook;
|
||||
|
||||
hook= m_heap->get_cur_hook();
|
||||
|
||||
if (!(point= m_heap->new_point_info(x, y, Info)))
|
||||
return 1;
|
||||
if (m_first)
|
||||
{
|
||||
if (cmp_point_info(m_prev, point) == 0)
|
||||
{
|
||||
/* Coinciding points, do nothing */
|
||||
m_heap->free_point_info(point, hook);
|
||||
return 0;
|
||||
}
|
||||
GCALC_DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y);
|
||||
m_prev->left= point;
|
||||
point->right= m_prev;
|
||||
}
|
||||
else
|
||||
m_first= point;
|
||||
m_prev= point;
|
||||
m_prev_hook= hook;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1029,10 +1051,20 @@ void Gcalc_shape_transporter::int_complete()
|
|||
return;
|
||||
}
|
||||
|
||||
GCALC_DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y);
|
||||
/* polygon */
|
||||
m_first->right= m_prev;
|
||||
m_prev->left= m_first;
|
||||
if (cmp_point_info(m_first, m_prev) == 0)
|
||||
{
|
||||
/* Coinciding points, remove the last one from the list */
|
||||
m_prev->right->left= m_first;
|
||||
m_first->right= m_prev->right;
|
||||
m_heap->free_point_info(m_prev, m_prev_hook);
|
||||
}
|
||||
else
|
||||
{
|
||||
GCALC_DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y);
|
||||
m_first->right= m_prev;
|
||||
m_prev->left= m_first;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue