diff options
-rw-r--r-- | sql/gcalc_slicescan.cc | 106 | ||||
-rw-r--r-- | sql/gcalc_slicescan.h | 5 | ||||
-rw-r--r-- | sql/gcalc_tools.cc | 9 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 197 | ||||
-rw-r--r-- | sql/spatial.h | 7 |
5 files changed, 132 insertions, 192 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; + } } diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index 9fc4cea5199..55de497f1ee 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -229,7 +229,9 @@ public: Gcalc_dyn_list(blk_size, sizeof(Info)), m_hook(&m_first), m_n_points(0) {} + void set_extent(double xmin, double xmax, double ymin, double ymax); Info *new_point_info(double x, double y, gcalc_shape_info shape); + void free_point_info(Info *i, Gcalc_dyn_list::Item **i_hook); Info *new_intersection(const Info *p1, const Info *p2, const Info *p3, const Info *p4); void prepare_operation(); @@ -242,6 +244,8 @@ public: long double get_double(const Gcalc_internal_coord *c) const; #endif /*GCALC_CHECK_WITH_FLOAT*/ double coord_extent; + Gcalc_dyn_list::Item **get_cur_hook() { return m_hook; } + private: Gcalc_dyn_list::Item *m_first; Gcalc_dyn_list::Item **m_hook; @@ -269,6 +273,7 @@ class Gcalc_shape_transporter private: Gcalc_heap::Info *m_first; Gcalc_heap::Info *m_prev; + Gcalc_dyn_list::Item **m_prev_hook; int m_shape_started; void int_complete(); protected: diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 161fa385f16..8af94039c2d 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -650,15 +650,6 @@ Gcalc_operation_reducer(Gcalc_function *fn, modes mode, size_t blk_size) : } -#ifdef TMP_BLOCK -void Gcalc_operation_reducer::res_point::set(const Gcalc_scan_iterator *si) -{ - if ((intersection_point= si->intersection_step())) - ii= si->get_cur_ii(); - else - pi= si->get_cur_pi(); -} -#endif /*TMP_BLOCK*/ void Gcalc_operation_reducer::res_point::set(const Gcalc_scan_iterator *si) { intersection_point= si->intersection_step(); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index acaa50536ff..0c9ebc06749 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -657,140 +657,6 @@ static double distance_points(const Gcalc_heap::Info *a, } -/* - Calculates the distance between objects. -*/ - -#ifdef TMP_BLOCK -static int calc_distance(double *result, Gcalc_heap *collector, uint obj2_si, - Gcalc_function *func, Gcalc_scan_iterator *scan_it) -{ - bool above_cur_point, cur_point_edge; - const Gcalc_scan_iterator::point *evpos; - const Gcalc_heap::Info *cur_point= NULL; - const Gcalc_heap::Info *dist_point; - const Gcalc_scan_iterator::point *ev; - double t, distance, cur_distance; - double ex, ey, vx, vy, e_sqrlen; - int o1, o2; - - DBUG_ENTER("calc_distance"); - - above_cur_point= false; - distance= DBL_MAX; - - while (scan_it->more_points()) - { - if (scan_it->step()) - goto mem_error; - evpos= scan_it->get_event_position(); - ev= scan_it->get_events(); - cur_point= NULL; - - if (ev->simple_event()) - { - cur_point= ev->pi; - goto calculate_distance; - } - - /* - handling intersection we only need to check if it's the intersecion - of objects 1 and 2. In this case distance is 0 - */ - o1= 0; - o2= 0; - for (; ev; ev= ev->get_next()) - { - if (ev->event != scev_intersection) - cur_point= ev->pi; - if (ev->pi->shape >= obj2_si) - o2= 1; - else - o1= 1; - if (o1 && o2) - { - distance= 0; - goto exit; - } - } - if (!cur_point) - continue; - -#ifdef TO_REMOVE - goto calculate_distance; - /* - having these events we need to check for possible intersection - of objects - scev_thread | scev_two_threads | scev_single_point - */ - DBUG_ASSERT(ev & (scev_thread | scev_two_threads | scev_single_point)); - - func->clear_state(); - for (Gcalc_point_iterator pit(scan_it); pit.point() != evpos; ++pit) - { - gcalc_shape_info si= pit.point()->get_shape(); - if ((func->get_shape_kind(si) == Gcalc_function::shape_polygon)) - func->invert_state(si); - } - func->invert_state(evpos->get_shape()); - if (func->count()) - { - /* Point of one object is inside the other - intersection found */ - distance= 0; - goto exit; - } -#endif /*TO_REMOVE*/ - -calculate_distance: - if (cur_point->shape >= obj2_si) - continue; - cur_point_edge= !cur_point->is_bottom(); - - for (dist_point= collector->get_first(); dist_point; dist_point= dist_point->get_next()) - { - /* We only check vertices of object 2 */ - if (dist_point->shape < obj2_si) - continue; - - /* if we have an edge to check */ - if (dist_point->left) - { - t= count_edge_t(dist_point, dist_point->left, cur_point, - ex, ey, vx, vy, e_sqrlen); - if ((t > 0.0) && (t < 1.0)) - { - cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen); - if (distance > cur_distance) - distance= cur_distance; - } - } - if (cur_point_edge) - { - t= count_edge_t(cur_point, cur_point->left, dist_point, - ex, ey, vx, vy, e_sqrlen); - if ((t > 0.0) && (t < 1.0)) - { - cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen); - if (distance > cur_distance) - distance= cur_distance; - } - } - cur_distance= distance_points(cur_point, dist_point); - if (distance > cur_distance) - distance= cur_distance; - } - } - -exit: - *result= distance; - DBUG_RETURN(0); - -mem_error: - DBUG_RETURN(1); -} -#endif /*TMP_BLOCK*/ - - #define GIS_ZERO 0.00000000001 longlong Item_func_spatial_rel::val_int() @@ -804,6 +670,8 @@ longlong Item_func_spatial_rel::val_int() int result= 0; int mask= 0; uint shape_a, shape_b; + MBR umbr, mbr1, mbr2; + const char *c_end; res1= args[0]->val_str(&tmp_value1); res2= args[1]->val_str(&tmp_value2); @@ -818,19 +686,35 @@ longlong Item_func_spatial_rel::val_int() !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) goto exit; + g1->get_mbr(&mbr1, &c_end); + g2->get_mbr(&mbr2, &c_end); + + umbr= mbr1; + umbr.add_mbr(&mbr2); + collector.set_extent(umbr.xmin, umbr.xmax, umbr.ymin, umbr.ymax); + + mbr1.buffer(1e-5); + switch (spatial_rel) { case SP_CONTAINS_FUNC: + if (!mbr1.contains(&mbr2)) + goto exit; mask= 1; func.add_operation(Gcalc_function::op_difference, 2); /* Mind the g2 goes first. */ null_value= g2->store_shapes(&trn) || g1->store_shapes(&trn); break; case SP_WITHIN_FUNC: + mbr2.buffer(2e-5); + if (!mbr1.within(&mbr2)) + goto exit; mask= 1; func.add_operation(Gcalc_function::op_difference, 2); null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; case SP_EQUALS_FUNC: + if (!mbr1.contains(&mbr2)) + goto exit; mask= 1; func.add_operation(Gcalc_function::op_symdifference, 2); null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); @@ -841,6 +725,8 @@ longlong Item_func_spatial_rel::val_int() null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; case SP_INTERSECTS_FUNC: + if (!mbr1.intersects(&mbr2)) + goto exit; func.add_operation(Gcalc_function::op_intersection, 2); null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; @@ -898,15 +784,6 @@ longlong Item_func_spatial_rel::val_int() scan_it.init(&collector); scan_it.killed= (int *) &(current_thd->killed); -#ifdef TMP_BLOCK - if (spatial_rel == SP_EQUALS_FUNC) - { - result= (g1->get_class_info()->m_type_id == g1->get_class_info()->m_type_id) && - func_equals(); - goto exit; - } -#endif /*TMP_BLOCK*/ - if (func.alloc_states()) goto exit; @@ -935,6 +812,8 @@ String *Item_func_spatial_operation::val_str(String *str_value) Geometry *g1, *g2; uint32 srid= 0; Gcalc_operation_transporter trn(&func, &collector); + MBR mbr1, mbr2; + const char *c_end; if (func.reserve_op_buffer(1)) DBUG_RETURN(0); @@ -943,14 +822,23 @@ String *Item_func_spatial_operation::val_str(String *str_value) if ((null_value= (args[0]->null_value || args[1]->null_value || !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || - !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || - g1->store_shapes(&trn) || g2->store_shapes(&trn)))) + !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) { str_value= 0; goto exit; } + g1->get_mbr(&mbr1, &c_end); + g2->get_mbr(&mbr2, &c_end); + mbr1.add_mbr(&mbr2); + collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax); + if ((null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn))) + { + str_value= 0; + goto exit; + } + collector.prepare_operation(); if (func.alloc_states()) goto exit; @@ -1374,12 +1262,18 @@ String *Item_func_buffer::val_str(String *str_value) uint32 srid= 0; String *str_result= NULL; Transporter trn(&func, &collector, dist); + MBR mbr; + const char *c_end; null_value= 1; if (args[0]->null_value || args[1]->null_value || - !(g= Geometry::construct(&buffer, obj->ptr(), obj->length()))) + !(g= Geometry::construct(&buffer, obj->ptr(), obj->length())) || + g->get_mbr(&mbr, &c_end)) goto mem_error; + if (dist > 0.0) + mbr.buffer(dist); + collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); /* If the distance given is 0, the Buffer function is in fact NOOP, so it's natural just to return the argument1. @@ -1446,6 +1340,8 @@ longlong Item_func_issimple::val_int() Geometry *g; int result= 1; const Gcalc_scan_iterator::event_point *ev; + MBR mbr; + const char *c_end; DBUG_ENTER("Item_func_issimple::val_int"); DBUG_ASSERT(fixed == 1); @@ -1454,6 +1350,8 @@ longlong Item_func_issimple::val_int() !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))) DBUG_RETURN(0); + g->get_mbr(&mbr, &c_end); + collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); if (g->get_class_info()->m_type_id == Geometry::wkb_point) DBUG_RETURN(1); @@ -1682,6 +1580,8 @@ double Item_func_distance::val_real() String *res2= args[1]->val_str(&tmp_value2); Geometry_buffer buffer1, buffer2; Geometry *g1, *g2; + MBR mbr1, mbr2; + const char *c_end; if ((null_value= (args[0]->null_value || args[1]->null_value || @@ -1689,6 +1589,11 @@ double Item_func_distance::val_real() !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) goto mem_error; + g1->get_mbr(&mbr1, &c_end); + g2->get_mbr(&mbr2, &c_end); + mbr1.add_mbr(&mbr2); + collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax); + if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) && (g2->get_class_info()->m_type_id == Geometry::wkb_point)) { diff --git a/sql/spatial.h b/sql/spatial.h index d55fc639acc..3ca5ed9ae20 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -98,6 +98,13 @@ struct MBR if (mbr->ymax > ymax) ymax= mbr->ymax; } + void buffer(double d) + { + xmin-= d; + ymin-= d; + xmax+= d; + ymax+= d; + } int equals(const MBR *mbr) { |