summaryrefslogtreecommitdiff
path: root/sql/gcalc_slicescan.cc
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2011-12-08 16:29:45 +0400
committerAlexey Botchkov <holyfoot@askmonty.org>2011-12-08 16:29:45 +0400
commitfc9d34cabf06038f930db356d53ed76dab5fdf0d (patch)
tree6572df0814ada1d7cdf7df86bd662d6abcbf7118 /sql/gcalc_slicescan.cc
parentae480437ce98bbba8624e52833b8edbcc495b014 (diff)
downloadmariadb-git-fc9d34cabf06038f930db356d53ed76dab5fdf0d.tar.gz
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.
Diffstat (limited to 'sql/gcalc_slicescan.cc')
-rw-r--r--sql/gcalc_slicescan.cc106
1 files changed, 69 insertions, 37 deletions
diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc
index 7021902ffb7..3c02bf62e53 100644
--- a/sql/gcalc_slicescan.cc
+++ b/sql/gcalc_slicescan.cc
@@ -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;
+ }
}