From 788043cd0b20e01fc07f8a4673de678404938240 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 4 May 2011 23:20:17 +0500 Subject: [PATCH 01/40] Precise GIS functions added. --- libmysqld/CMakeLists.txt | 1 + libmysqld/Makefile.am | 1 + mysql-test/r/gis-rtree.result | 468 ++++++++++++- mysql-test/r/gis.result | 436 ++++++++++++- mysql-test/t/gis-rtree.test | 12 - mysql-test/t/gis.test | 595 ++++++++++++++++- sql/CMakeLists.txt | 1 + sql/Makefile.am | 2 + sql/gcalc_slicescan.cc | 762 ++++++++++++++++++++++ sql/gcalc_slicescan.h | 433 ++++++++++++ sql/gcalc_tools.cc | 1156 +++++++++++++++++++++++++++++++++ sql/gcalc_tools.h | 306 +++++++++ sql/item_create.cc | 357 +++++++++- sql/item_geofunc.cc | 1112 ++++++++++++++++++++++++++++++- sql/item_geofunc.h | 227 +++++-- sql/plistsort.c | 166 +++++ sql/spatial.cc | 481 ++++++++++++-- sql/spatial.h | 42 +- 18 files changed, 6333 insertions(+), 225 deletions(-) create mode 100644 sql/gcalc_slicescan.cc create mode 100644 sql/gcalc_slicescan.h create mode 100644 sql/gcalc_tools.cc create mode 100644 sql/gcalc_tools.h create mode 100644 sql/plistsort.c diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 2898bf3a659..c5662993072 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -136,6 +136,7 @@ SET(LIBMYSQLD_SOURCES libmysqld.c emb_qcache.cc lib_sql.cc ../sql/sql_tablespace.cc ../sql/sql_table.cc ../sql/sql_test.cc ../sql/sql_trigger.cc ../sql/sql_udf.cc ../sql/sql_union.cc ../sql/sql_update.cc ../sql/sql_view.cc ../sql/sql_profile.cc + ../sql/gcalc_tools.cc ../sql/gcalc_slicescan.cc ../sql/strfunc.cc ../sql/table.cc ../sql/thr_malloc.cc ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc ../sql/partition_info.cc ../sql/sql_connect.cc diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 682fae81c59..e54082b84a8 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -62,6 +62,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ opt_sum.cc procedure.cc records.cc sql_acl.cc \ sql_load.cc discover.cc sql_locale.cc \ sql_profile.cc \ + gcalc_slicescan.cc gcalc_tools.cc \ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \ sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \ sql_join_cache.cc \ diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index a28f537b2de..21193cd8ec2 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -12,6 +12,156 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`fid`), SPATIAL KEY `g` (`g`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(148 148, 152 152)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(147 147, 153 153)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(146 146, 154 154)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(145 145, 155 155)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(144 144, 156 156)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(143 143, 157 157)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(142 142, 158 158)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(141 141, 159 159)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(140 140, 160 160)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(139 139, 161 161)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(138 138, 162 162)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(137 137, 163 163)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(136 136, 164 164)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(135 135, 165 165)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(134 134, 166 166)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(133 133, 167 167)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(132 132, 168 168)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(131 131, 169 169)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(130 130, 170 170)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(129 129, 171 171)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(128 128, 172 172)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(127 127, 173 173)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(126 126, 174 174)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(125 125, 175 175)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(124 124, 176 176)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(123 123, 177 177)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(122 122, 178 178)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(121 121, 179 179)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(120 120, 180 180)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(119 119, 181 181)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(118 118, 182 182)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(117 117, 183 183)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(116 116, 184 184)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(115 115, 185 185)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(114 114, 186 186)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(113 113, 187 187)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(112 112, 188 188)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(111 111, 189 189)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(110 110, 190 190)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(109 109, 191 191)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(108 108, 192 192)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(107 107, 193 193)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(106 106, 194 194)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(105 105, 195 195)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(104 104, 196 196)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(103 103, 197 197)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(102 102, 198 198)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(101 101, 199 199)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(100 100, 200 200)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(99 99, 201 201)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(98 98, 202 202)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(97 97, 203 203)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(96 96, 204 204)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(95 95, 205 205)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(94 94, 206 206)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(93 93, 207 207)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(92 92, 208 208)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(91 91, 209 209)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(90 90, 210 210)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(89 89, 211 211)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(88 88, 212 212)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(87 87, 213 213)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(86 86, 214 214)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(85 85, 215 215)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(84 84, 216 216)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(83 83, 217 217)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(82 82, 218 218)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(81 81, 219 219)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(80 80, 220 220)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(79 79, 221 221)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(78 78, 222 222)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(77 77, 223 223)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(76 76, 224 224)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(75 75, 225 225)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(74 74, 226 226)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(73 73, 227 227)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(72 72, 228 228)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(71 71, 229 229)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(70 70, 230 230)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(69 69, 231 231)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(68 68, 232 232)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(67 67, 233 233)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(66 66, 234 234)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(65 65, 235 235)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(64 64, 236 236)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(63 63, 237 237)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(62 62, 238 238)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(61 61, 239 239)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(60 60, 240 240)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(59 59, 241 241)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(58 58, 242 242)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(57 57, 243 243)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(56 56, 244 244)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(55 55, 245 245)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(54 54, 246 246)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(53 53, 247 247)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(52 52, 248 248)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(51 51, 249 249)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(50 50, 250 250)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(49 49, 251 251)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(48 48, 252 252)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(47 47, 253 253)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(46 46, 254 254)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(45 45, 255 255)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(44 44, 256 256)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(43 43, 257 257)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(42 42, 258 258)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(41 41, 259 259)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(40 40, 260 260)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(39 39, 261 261)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(38 38, 262 262)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(37 37, 263 263)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(36 36, 264 264)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(35 35, 265 265)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(34 34, 266 266)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(33 33, 267 267)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(32 32, 268 268)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(31 31, 269 269)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(30 30, 270 270)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(29 29, 271 271)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(28 28, 272 272)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(27 27, 273 273)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(26 26, 274 274)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(25 25, 275 275)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(24 24, 276 276)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(23 23, 277 277)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(22 22, 278 278)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(21 21, 279 279)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(20 20, 280 280)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(19 19, 281 281)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(18 18, 282 282)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(17 17, 283 283)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(16 16, 284 284)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(15 15, 285 285)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(14 14, 286 286)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(13 13, 287 287)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(12 12, 288 288)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(11 11, 289 289)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(10 10, 290 290)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(9 9, 291 291)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(8 8, 292 292)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(7 7, 293 293)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(6 6, 294 294)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(5 5, 295 295)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(4 4, 296 296)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(3 3, 297 297)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(2 2, 298 298)')); +INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 1, 299 299)')); SELECT count(*) FROM t1; count(*) 150 @@ -20,22 +170,112 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range g g 34 NULL 8 Using where SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); fid AsText(g) -1 LINESTRING(150 150,150 150) -3 LINESTRING(148 148,152 152) -4 LINESTRING(147 147,153 153) -5 LINESTRING(146 146,154 154) -6 LINESTRING(145 145,155 155) -7 LINESTRING(144 144,156 156) -8 LINESTRING(143 143,157 157) -9 LINESTRING(142 142,158 158) -10 LINESTRING(141 141,159 159) 11 LINESTRING(140 140,160 160) -2 LINESTRING(149 149,151 151) DROP TABLE t1; CREATE TABLE t2 ( fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, g GEOMETRY NOT NULL ) ENGINE=MyISAM; +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))); +INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))); ALTER TABLE t2 ADD SPATIAL KEY(g); SHOW CREATE TABLE t2; Table Create Table @@ -51,218 +291,414 @@ count(*) EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g, GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))')); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range g g 34 NULL 4 Using where +1 SIMPLE t2 range g g 34 NULL 1 Using where SELECT fid, AsText(g) FROM t2 WHERE Within(g, GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))')); fid AsText(g) -46 LINESTRING(51 41,60 50) -56 LINESTRING(41 41,50 50) -45 LINESTRING(51 51,60 60) -55 LINESTRING(41 51,50 60) +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10)))); +SELECT count(*) FROM t2; count(*) 100 +DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10)))); +SELECT count(*) FROM t2; count(*) 100 DROP TABLE t2; drop table if exists t1; Warnings: -Note 1051 Unknown table 't1' +Note 1051 Unknown table 'test.t1' CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a)); INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)")); INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)")); diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index beb1331563e..daf66b16d62 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -228,7 +228,7 @@ explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelo id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 21 100.00 Warnings: -Note 1003 select dimension(`test`.`gis_geometry`.`g`) AS `Dimension(g)`,geometrytype(`test`.`gis_geometry`.`g`) AS `GeometryType(g)`,isempty(`test`.`gis_geometry`.`g`) AS `IsEmpty(g)`,astext(envelope(`test`.`gis_geometry`.`g`)) AS `AsText(Envelope(g))` from `test`.`gis_geometry` +Note 1003 select st_dimension(`test`.`gis_geometry`.`g`) AS `Dimension(g)`,st_geometrytype(`test`.`gis_geometry`.`g`) AS `GeometryType(g)`,st_isempty(`test`.`gis_geometry`.`g`) AS `IsEmpty(g)`,st_astext(st_envelope(`test`.`gis_geometry`.`g`)) AS `AsText(Envelope(g))` from `test`.`gis_geometry` SELECT fid, X(g) FROM gis_point; fid X(g) 101 10 @@ -245,7 +245,7 @@ explain extended select X(g),Y(g) FROM gis_point; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_point ALL NULL NULL NULL NULL 4 100.00 Warnings: -Note 1003 select x(`test`.`gis_point`.`g`) AS `X(g)`,y(`test`.`gis_point`.`g`) AS `Y(g)` from `test`.`gis_point` +Note 1003 select st_x(`test`.`gis_point`.`g`) AS `X(g)`,st_y(`test`.`gis_point`.`g`) AS `Y(g)` from `test`.`gis_point` SELECT fid, AsText(StartPoint(g)) FROM gis_line; fid AsText(StartPoint(g)) 105 POINT(0 0) @@ -258,7 +258,7 @@ fid AsText(EndPoint(g)) 107 POINT(40 10) SELECT fid, GLength(g) FROM gis_line; fid GLength(g) -105 24.142135623731 +105 24.14213562373095 106 40 107 30 SELECT fid, NumPoints(g) FROM gis_line; @@ -280,11 +280,11 @@ explain extended select AsText(StartPoint(g)),AsText(EndPoint(g)),GLength(g),Num id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_line ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select astext(startpoint(`test`.`gis_line`.`g`)) AS `AsText(StartPoint(g))`,astext(endpoint(`test`.`gis_line`.`g`)) AS `AsText(EndPoint(g))`,glength(`test`.`gis_line`.`g`) AS `GLength(g)`,numpoints(`test`.`gis_line`.`g`) AS `NumPoints(g)`,astext(pointn(`test`.`gis_line`.`g`,2)) AS `AsText(PointN(g, 2))`,isclosed(`test`.`gis_line`.`g`) AS `IsClosed(g)` from `test`.`gis_line` +Note 1003 select st_astext(st_startpoint(`test`.`gis_line`.`g`)) AS `AsText(StartPoint(g))`,st_astext(st_endpoint(`test`.`gis_line`.`g`)) AS `AsText(EndPoint(g))`,st_length(`test`.`gis_line`.`g`) AS `GLength(g)`,st_numpoints(`test`.`gis_line`.`g`) AS `NumPoints(g)`,st_astext(st_pointn(`test`.`gis_line`.`g`,2)) AS `AsText(PointN(g, 2))`,st_isclosed(`test`.`gis_line`.`g`) AS `IsClosed(g)` from `test`.`gis_line` SELECT fid, AsText(Centroid(g)) FROM gis_polygon; fid AsText(Centroid(g)) 108 POINT(15 15) -109 POINT(25.4166666666667 25.4166666666667) +109 POINT(25.416666666666668 25.416666666666668) 110 POINT(20 10) SELECT fid, Area(g) FROM gis_polygon; fid Area(g) @@ -310,7 +310,7 @@ explain extended select AsText(Centroid(g)),Area(g),AsText(ExteriorRing(g)),NumI id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_polygon ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select astext(centroid(`test`.`gis_polygon`.`g`)) AS `AsText(Centroid(g))`,area(`test`.`gis_polygon`.`g`) AS `Area(g)`,astext(exteriorring(`test`.`gis_polygon`.`g`)) AS `AsText(ExteriorRing(g))`,numinteriorrings(`test`.`gis_polygon`.`g`) AS `NumInteriorRings(g)`,astext(interiorringn(`test`.`gis_polygon`.`g`,1)) AS `AsText(InteriorRingN(g, 1))` from `test`.`gis_polygon` +Note 1003 select st_astext(st_centroid(`test`.`gis_polygon`.`g`)) AS `AsText(Centroid(g))`,st_area(`test`.`gis_polygon`.`g`) AS `Area(g)`,st_astext(st_exteriorring(`test`.`gis_polygon`.`g`)) AS `AsText(ExteriorRing(g))`,st_numinteriorrings(`test`.`gis_polygon`.`g`) AS `NumInteriorRings(g)`,st_astext(st_interiorringn(`test`.`gis_polygon`.`g`,1)) AS `AsText(InteriorRingN(g, 1))` from `test`.`gis_polygon` SELECT fid, IsClosed(g) FROM gis_multi_line; fid IsClosed(g) 114 0 @@ -318,8 +318,8 @@ fid IsClosed(g) 116 0 SELECT fid, AsText(Centroid(g)) FROM gis_multi_polygon; fid AsText(Centroid(g)) -117 POINT(55.5885277530424 17.426536064114) -118 POINT(55.5885277530424 17.426536064114) +117 POINT(55.58852775304245 17.426536064113982) +118 POINT(55.58852775304245 17.426536064113982) 119 POINT(2 2) SELECT fid, Area(g) FROM gis_multi_polygon; fid Area(g) @@ -349,7 +349,7 @@ explain extended SELECT fid, NumGeometries(g) from gis_multi_point; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,numgeometries(`test`.`gis_multi_point`.`g`) AS `NumGeometries(g)` from `test`.`gis_multi_point` +Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,st_numgeometries(`test`.`gis_multi_point`.`g`) AS `NumGeometries(g)` from `test`.`gis_multi_point` SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point; fid AsText(GeometryN(g, 2)) 111 POINT(10 10) @@ -377,17 +377,17 @@ explain extended SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,astext(geometryn(`test`.`gis_multi_point`.`g`,2)) AS `AsText(GeometryN(g, 2))` from `test`.`gis_multi_point` +Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,st_astext(st_geometryn(`test`.`gis_multi_point`.`g`,2)) AS `AsText(GeometryN(g, 2))` from `test`.`gis_multi_point` SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; first second w c o e d t i r -120 120 1 1 0 1 0 0 1 0 +120 120 1 1 0 1 0 1 1 0 120 121 0 0 1 0 0 0 1 0 121 120 0 0 1 0 0 0 1 0 -121 121 1 1 0 1 0 0 1 0 +121 121 1 1 0 1 0 1 1 0 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -395,9 +395,9 @@ Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE g1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort -1 SIMPLE g2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join) +1 SIMPLE g2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (BNL, regular buffers) Warnings: -Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,within(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,contains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,overlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,equals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,disjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,intersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid` +Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,mbrwithin(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,mbrcontains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,mbroverlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,mbrequals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,mbrdisjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,st_touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,mbrintersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,st_crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid` DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry; CREATE TABLE t1 ( gp point, @@ -439,12 +439,12 @@ explain extended SELECT AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4 id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select astext(geometryfromwkb(aswkb(geometryfromtext('POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)'))))` +Note 1003 select st_astext(st_geometryfromwkb(st_aswkb(st_geometryfromtext('POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)'))))` explain extended SELECT AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)')))); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select astext(geometryfromwkb(aswkb(geometryfromtext('POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)'))))` +Note 1003 select st_astext(st_geometryfromwkb(st_aswkb(st_geometryfromtext('POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)'))))` SELECT SRID(GeomFromText('LineString(1 1,2 2)',101)); SRID(GeomFromText('LineString(1 1,2 2)',101)) 101 @@ -452,12 +452,12 @@ explain extended SELECT SRID(GeomFromText('LineString(1 1,2 2)',101)); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select srid(geometryfromtext('LineString(1 1,2 2)',101)) AS `SRID(GeomFromText('LineString(1 1,2 2)',101))` +Note 1003 select srid(st_geometryfromtext('LineString(1 1,2 2)',101)) AS `SRID(GeomFromText('LineString(1 1,2 2)',101))` explain extended select issimple(MultiPoint(Point(3, 6), Point(4, 10))), issimple(Point(3, 6)); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select issimple(multipoint(point(3,6),point(4,10))) AS `issimple(MultiPoint(Point(3, 6), Point(4, 10)))`,issimple(point(3,6)) AS `issimple(Point(3, 6))` +Note 1003 select st_issimple(st_multipoint(st_point(3,6),st_point(4,10))) AS `issimple(MultiPoint(Point(3, 6), Point(4, 10)))`,st_issimple(st_point(3,6)) AS `issimple(Point(3, 6))` create table t1 (a geometry not null); insert into t1 values (GeomFromText('Point(1 2)')); insert into t1 values ('Garbage'); @@ -651,11 +651,11 @@ insert into t1 values ('85984',GeomFromText('MULTIPOLYGON(((-115.006363 select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from t1 where object_id=85998; object_id geometrytype(geo) ISSIMPLE(GEO) ASTEXT(centroid(geo)) -85998 MULTIPOLYGON 0 POINT(115.318773152032 -36.2374728210215) +85998 MULTIPOLYGON 1 POINT(115.31877315203187 -36.23747282102153) select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from t1 where object_id=85984; object_id geometrytype(geo) ISSIMPLE(GEO) ASTEXT(centroid(geo)) -85984 MULTIPOLYGON 0 POINT(-114.877871869233 36.3310176346905) +85984 MULTIPOLYGON 1 POINT(-114.87787186923313 36.33101763469059) drop table t1; create table t1 (fl geometry not null); insert into t1 values (1); @@ -1014,12 +1014,392 @@ SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000 SET @a=POLYFROMWKB(@a); SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; SET @a=POLYFROMWKB(@a); -create table t1(a polygon NOT NULL)engine=myisam; -insert into t1 values (geomfromtext("point(0 1)")); -insert into t1 values (geomfromtext("point(1 0)")); -select * from (select polygon(t1.a) as p from t1 order by t1.a) d; -p -NULL -NULL -drop table t1; End of 5.1 tests +CREATE TABLE t1( +col0 BINARY NOT NULL, +col2 TIMESTAMP, +SPATIAL INDEX i1 (col0) +) ENGINE=MyISAM; +ERROR 42000: A SPATIAL index may only contain a geometrical type column +CREATE TABLE t1 ( +col0 BINARY NOT NULL, +col2 TIMESTAMP +) ENGINE=MyISAM; +CREATE SPATIAL INDEX idx0 ON t1(col0); +ERROR 42000: A SPATIAL index may only contain a geometrical type column +ALTER TABLE t1 ADD SPATIAL INDEX i1 (col0); +ERROR 42000: A SPATIAL index may only contain a geometrical type column +CREATE TABLE t2 ( +col0 INTEGER NOT NULL, +col1 POINT, +col2 POINT +); +CREATE SPATIAL INDEX idx0 ON t2 (col1, col2); +ERROR HY000: Incorrect arguments to SPATIAL INDEX +CREATE TABLE t3 ( +col0 INTEGER NOT NULL, +col1 POINT, +col2 LINESTRING, +SPATIAL INDEX i1 (col1, col2) +); +ERROR HY000: Incorrect arguments to SPATIAL INDEX +DROP TABLE t1; +DROP TABLE t2; +DROP DATABASE IF EXISTS gis_ogs; +CREATE DATABASE gis_ogs; +USE gis_ogs; +# +# C.3.3.1 Geometry types and functions schema construction +# +CREATE TABLE lakes ( +fid INTEGER NOT NULL PRIMARY KEY, +name CHARACTER VARYING(64), +shore POLYGON); +CREATE TABLE road_segments ( +fid INTEGER NOT NULL PRIMARY KEY, +name CHARACTER VARYING(64), +aliases CHARACTER VARYING(64), +num_lanes INTEGER, +centerline LINESTRING); +CREATE TABLE divided_routes ( +fid INTEGER NOT NULL PRIMARY KEY, +name CHARACTER VARYING(64), +num_lanes INTEGER, +centerlines MULTILINESTRING); +CREATE TABLE forests ( +fid INTEGER NOT NULL PRIMARY KEY, +name CHARACTER VARYING(64), +boundary MULTIPOLYGON); +CREATE TABLE bridges ( +fid INTEGER NOT NULL PRIMARY KEY, +name CHARACTER VARYING(64), +position POINT); +CREATE TABLE streams ( +fid INTEGER NOT NULL PRIMARY KEY, +name CHARACTER VARYING(64), +centerline LINESTRING); +CREATE TABLE buildings ( +fid INTEGER NOT NULL PRIMARY KEY, +address CHARACTER VARYING(64), +position POINT, +footprint POLYGON); +CREATE TABLE ponds ( +fid INTEGER NOT NULL PRIMARY KEY, +name CHARACTER VARYING(64), +type CHARACTER VARYING(64), +shores MULTIPOLYGON); +CREATE TABLE named_places ( +fid INTEGER NOT NULL PRIMARY KEY, +name CHARACTER VARYING(64), +boundary POLYGON); +CREATE TABLE map_neatlines ( +fid INTEGER NOT NULL PRIMARY KEY, +neatline POLYGON); +# +# C.3.3.2 Geometry types and functions schema data loading +# +# Lakes +INSERT INTO lakes VALUES ( +101, 'BLUE LAKE', +PolyFromText( +'POLYGON( +(52 18,66 23,73 9,48 6,52 18), +(59 18,67 18,67 13,59 13,59 18) +)', +101)); +# Road Segments +INSERT INTO road_segments VALUES(102, 'Route 5', NULL, 2, +LineFromText( +'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101)); +INSERT INTO road_segments VALUES(103, 'Route 5', 'Main Street', 4, +LineFromText( +'LINESTRING( 44 31, 56 34, 70 38 )' ,101)); +INSERT INTO road_segments VALUES(104, 'Route 5', NULL, 2, +LineFromText( +'LINESTRING( 70 38, 72 48 )' ,101)); +INSERT INTO road_segments VALUES(105, 'Main Street', NULL, 4, +LineFromText( +'LINESTRING( 70 38, 84 42 )' ,101)); +INSERT INTO road_segments VALUES(106, 'Dirt Road by Green Forest', NULL, +1, +LineFromText( +'LINESTRING( 28 26, 28 0 )',101)); +# DividedRoutes +INSERT INTO divided_routes VALUES(119, 'Route 75', 4, +MLineFromText( +'MULTILINESTRING((10 48,10 21,10 0), +(16 0,16 23,16 48))', 101)); +# Forests +INSERT INTO forests VALUES(109, 'Green Forest', +MPolyFromText( +'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26), +(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))', +101)); +# Bridges +INSERT INTO bridges VALUES(110, 'Cam Bridge', PointFromText( +'POINT( 44 31 )', 101)); +# Streams +INSERT INTO streams VALUES(111, 'Cam Stream', +LineFromText( +'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101)); +INSERT INTO streams VALUES(112, NULL, +LineFromText( +'LINESTRING( 76 0, 78 4, 73 9 )', 101)); +# Buildings +INSERT INTO buildings VALUES(113, '123 Main Street', +PointFromText( +'POINT( 52 30 )', 101), +PolyFromText( +'POLYGON( ( 50 31, 54 31, 54 29, 50 29, 50 31) )', 101)); +INSERT INTO buildings VALUES(114, '215 Main Street', +PointFromText( +'POINT( 64 33 )', 101), +PolyFromText( +'POLYGON( ( 66 34, 62 34, 62 32, 66 32, 66 34) )', 101)); +# Ponds +INSERT INTO ponds VALUES(120, NULL, 'Stock Pond', +MPolyFromText( +'MULTIPOLYGON( ( ( 24 44, 22 42, 24 40, 24 44) ), +( ( 26 44, 26 40, 28 42, 26 44) ) )', 101)); +# Named Places +INSERT INTO named_places VALUES(117, 'Ashton', +PolyFromText( +'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101)); +INSERT INTO named_places VALUES(118, 'Goose Island', +PolyFromText( +'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101)); +# Map Neatlines +INSERT INTO map_neatlines VALUES(115, +PolyFromText( +'POLYGON( ( 0 0, 0 48, 84 48, 84 0, 0 0 ) )', 101)); +# +# C.3.3.3 Geometry types and functions schema test queries + +# Conformance Item T6 +SELECT Dimension(shore) +FROM lakes +WHERE name = 'Blue Lake'; +Dimension(shore) +2 +# Conformance Item T7 +SELECT GeometryType(centerlines) +FROM divided_routes +WHERE name = 'Route 75'; +GeometryType(centerlines) +MULTILINESTRING +# Conformance Item T8 +SELECT AsText(boundary) +FROM named_places +WHERE name = 'Goose Island'; +AsText(boundary) +POLYGON((67 13,67 18,59 18,59 13,67 13)) +# Conformance Item T9 +SELECT AsText(PolyFromWKB(AsBinary(boundary),101)) +FROM named_places +WHERE name = 'Goose Island'; +AsText(PolyFromWKB(AsBinary(boundary),101)) +POLYGON((67 13,67 18,59 18,59 13,67 13)) +# Conformance Item T10 +SELECT SRID(boundary) +FROM named_places +WHERE name = 'Goose Island'; +SRID(boundary) +101 +# Conformance Item T11 +SELECT IsEmpty(centerline) +FROM road_segments +WHERE name = 'Route 5' +AND aliases = 'Main Street'; +IsEmpty(centerline) +0 +# Conformance Item T14 +SELECT AsText(Envelope(boundary)) +FROM named_places +WHERE name = 'Goose Island'; +AsText(Envelope(boundary)) +POLYGON((59 13,67 13,67 18,59 18,59 13)) +# Conformance Item T15 +SELECT X(position) +FROM bridges +WHERE name = 'Cam Bridge'; +X(position) +44 +# Conformance Item T16 +SELECT Y(position) +FROM bridges +WHERE name = 'Cam Bridge'; +Y(position) +31 +# Conformance Item T17 +SELECT AsText(StartPoint(centerline)) +FROM road_segments +WHERE fid = 102; +AsText(StartPoint(centerline)) +POINT(0 18) +# Conformance Item T18 +SELECT AsText(EndPoint(centerline)) +FROM road_segments +WHERE fid = 102; +AsText(EndPoint(centerline)) +POINT(44 31) +# Conformance Item T21 +SELECT GLength(centerline) +FROM road_segments +WHERE fid = 106; +GLength(centerline) +26 +# Conformance Item T22 +SELECT NumPoints(centerline) +FROM road_segments +WHERE fid = 102; +NumPoints(centerline) +5 +# Conformance Item T23 +SELECT AsText(PointN(centerline, 1)) +FROM road_segments +WHERE fid = 102; +AsText(PointN(centerline, 1)) +POINT(0 18) +# Conformance Item T24 +SELECT AsText(Centroid(boundary)) +FROM named_places +WHERE name = 'Goose Island'; +AsText(Centroid(boundary)) +POINT(63 15.5) +# Conformance Item T26 +SELECT Area(boundary) +FROM named_places +WHERE name = 'Goose Island'; +Area(boundary) +40 +# Conformance Item T27 +SELECT AsText(ExteriorRing(shore)) +FROM lakes +WHERE name = 'Blue Lake'; +AsText(ExteriorRing(shore)) +LINESTRING(52 18,66 23,73 9,48 6,52 18) +# Conformance Item T28 +SELECT NumInteriorRings(shore) +FROM lakes +WHERE name = 'Blue Lake'; +NumInteriorRings(shore) +1 +# Conformance Item T29 +SELECT AsText(InteriorRingN(shore, 1)) +FROM lakes +WHERE name = 'Blue Lake'; +AsText(InteriorRingN(shore, 1)) +LINESTRING(59 18,67 18,67 13,59 13,59 18) +# Conformance Item T30 +SELECT NumGeometries(centerlines) +FROM divided_routes +WHERE name = 'Route 75'; +NumGeometries(centerlines) +2 +# Conformance Item T31 +SELECT AsText(GeometryN(centerlines, 2)) +FROM divided_routes +WHERE name = 'Route 75'; +AsText(GeometryN(centerlines, 2)) +LINESTRING(16 0,16 23,16 48) +# Conformance Item T32 +SELECT IsClosed(centerlines) +FROM divided_routes +WHERE name = 'Route 75'; +IsClosed(centerlines) +0 +# Conformance Item T33 +SELECT GLength(centerlines) +FROM divided_routes +WHERE name = 'Route 75'; +GLength(centerlines) +96 +# Conformance Item T34 +SELECT AsText(Centroid(shores)) +FROM ponds +WHERE fid = 120; +AsText(Centroid(shores)) +POINT(25 42) +# Conformance Item T36 +SELECT Area(shores) +FROM ponds +WHERE fid = 120; +Area(shores) +8 +# Conformance Item T37 +SELECT ST_Equals(boundary, +PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1)) +FROM named_places +WHERE name = 'Goose Island'; +ST_Equals(boundary, +PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1)) +1 +# Conformance Item T38 +SELECT ST_Disjoint(centerlines, boundary) +FROM divided_routes, named_places +WHERE divided_routes.name = 'Route 75' +AND named_places.name = 'Ashton'; +ST_Disjoint(centerlines, boundary) +1 +# Conformance Item T39 +SELECT ST_Touches(centerline, shore) +FROM streams, lakes +WHERE streams.name = 'Cam Stream' +AND lakes.name = 'Blue Lake'; +ST_Touches(centerline, shore) +1 +# Conformance Item T42 +SELECT Crosses(road_segments.centerline, divided_routes.centerlines) +FROM road_segments, divided_routes +WHERE road_segments.fid = 102 +AND divided_routes.name = 'Route 75'; +Crosses(road_segments.centerline, divided_routes.centerlines) +1 +# Conformance Item T43 +SELECT ST_Intersects(road_segments.centerline, divided_routes.centerlines) +FROM road_segments, divided_routes +WHERE road_segments.fid = 102 +AND divided_routes.name = 'Route 75'; +ST_Intersects(road_segments.centerline, divided_routes.centerlines) +1 +# Conformance Item T44 +SELECT ST_Contains(forests.boundary, named_places.boundary) +FROM forests, named_places +WHERE forests.name = 'Green Forest' +AND named_places.name = 'Ashton'; +ST_Contains(forests.boundary, named_places.boundary) +0 +# Conformance Item T46 +SELECT ST_Distance(position, boundary) +FROM bridges, named_places +WHERE bridges.name = 'Cam Bridge' +AND named_places.name = 'Ashton'; +ST_Distance(position, boundary) +12 +# Conformance Item T48 +SELECT AsText(ST_Difference(named_places.boundary, forests.boundary)) +FROM named_places, forests +WHERE named_places.name = 'Ashton' +AND forests.name = 'Green Forest'; +AsText(ST_Difference(named_places.boundary, forests.boundary)) +POLYGON((56 34,62 48,84 48,84 42,56 34)) +SELECT AsText(ST_Union(shore, boundary)) +FROM lakes, named_places +WHERE lakes.name = 'Blue Lake' +AND named_places.name = 'Goose Island'; +AsText(ST_Union(shore, boundary)) +POLYGON((48 6,52 18,66 23,73 9,48 6)) +# Conformance Item T50 +SELECT AsText(ST_SymDifference(shore, boundary)) +FROM lakes, named_places +WHERE lakes.name = 'Blue Lake' +AND named_places.name = 'Ashton'; +AsText(ST_SymDifference(shore, boundary)) +MULTIPOLYGON(((48 6,52 18,66 23,73 9,48 6),(67 13,59 13,59 18,67 18,67 13)),((56 30,56 34,62 48,84 48,84 30,56 30))) +# Conformance Item T51 +SELECT count(*) +FROM buildings, bridges +WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; +count(*) +1 +DROP DATABASE gis_ogs; diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index 9e6002a1faf..b006096528e 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -17,16 +17,12 @@ SHOW CREATE TABLE t1; let $1=150; let $2=150; ---disable_query_log -begin; while ($1) { eval INSERT INTO t1 (g) VALUES (GeomFromText('LineString($1 $1, $2 $2)')); dec $1; inc $2; } -commit; ---enable_query_log SELECT count(*) FROM t1; EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); @@ -39,8 +35,6 @@ CREATE TABLE t2 ( g GEOMETRY NOT NULL ) ENGINE=MyISAM; ---disable_query_log -begin; let $1=10; while ($1) { @@ -52,8 +46,6 @@ while ($1) } dec $1; } -commit; ---enable_query_log ALTER TABLE t2 ADD SPATIAL KEY(g); SHOW CREATE TABLE t2; @@ -63,8 +55,6 @@ EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g, SELECT fid, AsText(g) FROM t2 WHERE Within(g, GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))')); ---disable_query_log -begin; let $1=10; while ($1) { @@ -77,8 +67,6 @@ while ($1) } dec $1; } -commit; ---enable_query_log DROP TABLE t2; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 97fc6f94b6a..416a40630bc 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -353,6 +353,9 @@ insert into t1 values ('85984',GeomFromText('MULTIPOLYGON(((-115.006363 36.248666,-115.263639 36.247466,-115.263839 36.252766,-115.261439 36.252666,-115.261439 36.247366,-115.247239 36.247066)))')); +# Expected result is 115.31877315203187, but IA64 returns 115.31877315203188 +# due to fused multiply-add instructions. +--replace_result 115.31877315203188 115.31877315203187 select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from t1 where object_id=85998; @@ -535,18 +538,6 @@ create table t1 (g geometry not null); insert into t1 values(default); drop table t1; -# -# Bug #27300: create view with geometry functions lost columns types -# -CREATE TABLE t1 (a GEOMETRY); -CREATE VIEW v1 AS SELECT GeomFromwkb(ASBINARY(a)) FROM t1; -CREATE VIEW v2 AS SELECT a FROM t1; -DESCRIBE v1; -DESCRIBE v2; - -DROP VIEW v1,v2; -DROP TABLE t1; - # # Bug#24563: MBROverlaps does not seem to function propertly # Bug#54888: MBROverlaps missing in 5.1? @@ -744,14 +735,574 @@ SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000 SET @a=POLYFROMWKB(@a); -# -# Bug #57321 crashes and valgrind errors from spatial types -# - -create table t1(a polygon NOT NULL)engine=myisam; -insert into t1 values (geomfromtext("point(0 1)")); -insert into t1 values (geomfromtext("point(1 0)")); -select * from (select polygon(t1.a) as p from t1 order by t1.a) d; -drop table t1; - --echo End of 5.1 tests + +# +# Bug #50574 5.5.x allows spatial indexes on non-spatial +# columns, causing crashes! +# +--error ER_SPATIAL_MUST_HAVE_GEOM_COL +CREATE TABLE t1( + col0 BINARY NOT NULL, + col2 TIMESTAMP, + SPATIAL INDEX i1 (col0) +) ENGINE=MyISAM; + +# Test other ways to add indices +CREATE TABLE t1 ( + col0 BINARY NOT NULL, + col2 TIMESTAMP +) ENGINE=MyISAM; + +--error ER_SPATIAL_MUST_HAVE_GEOM_COL +CREATE SPATIAL INDEX idx0 ON t1(col0); + +--error ER_SPATIAL_MUST_HAVE_GEOM_COL +ALTER TABLE t1 ADD SPATIAL INDEX i1 (col0); + +CREATE TABLE t2 ( + col0 INTEGER NOT NULL, + col1 POINT, + col2 POINT +); + +--error ER_WRONG_ARGUMENTS +CREATE SPATIAL INDEX idx0 ON t2 (col1, col2); + +--error ER_WRONG_ARGUMENTS +CREATE TABLE t3 ( + col0 INTEGER NOT NULL, + col1 POINT, + col2 LINESTRING, + SPATIAL INDEX i1 (col1, col2) +); + +# cleanup +DROP TABLE t1; +DROP TABLE t2; + +# Conformance tests +# +# C.3.3 Geometry types and functions +# + +--disable_warnings +DROP DATABASE IF EXISTS gis_ogs; +--enable_warnings + +CREATE DATABASE gis_ogs; +USE gis_ogs; + +--echo # +--echo # C.3.3.1 Geometry types and functions schema construction +--echo # + +# TODO: WL#2377 +#CREATE TABLE spatial_ref_sys ( +#srid INTEGER NOT NULL PRIMARY KEY, +#auth_name CHARACTER VARYING, +#auth_srid INTEGER, +#srtext CHARACTER VARYING(2048)); + +CREATE TABLE lakes ( + fid INTEGER NOT NULL PRIMARY KEY, + name CHARACTER VARYING(64), + shore POLYGON); + +CREATE TABLE road_segments ( + fid INTEGER NOT NULL PRIMARY KEY, + name CHARACTER VARYING(64), + aliases CHARACTER VARYING(64), + num_lanes INTEGER, + centerline LINESTRING); + +CREATE TABLE divided_routes ( + fid INTEGER NOT NULL PRIMARY KEY, + name CHARACTER VARYING(64), + num_lanes INTEGER, + centerlines MULTILINESTRING); + +CREATE TABLE forests ( + fid INTEGER NOT NULL PRIMARY KEY, + name CHARACTER VARYING(64), + boundary MULTIPOLYGON); + +CREATE TABLE bridges ( + fid INTEGER NOT NULL PRIMARY KEY, + name CHARACTER VARYING(64), + position POINT); + +CREATE TABLE streams ( + fid INTEGER NOT NULL PRIMARY KEY, + name CHARACTER VARYING(64), + centerline LINESTRING); + +CREATE TABLE buildings ( + fid INTEGER NOT NULL PRIMARY KEY, + address CHARACTER VARYING(64), + position POINT, + footprint POLYGON); + +CREATE TABLE ponds ( + fid INTEGER NOT NULL PRIMARY KEY, + name CHARACTER VARYING(64), + type CHARACTER VARYING(64), + shores MULTIPOLYGON); + +CREATE TABLE named_places ( + fid INTEGER NOT NULL PRIMARY KEY, + name CHARACTER VARYING(64), + boundary POLYGON); + +CREATE TABLE map_neatlines ( + fid INTEGER NOT NULL PRIMARY KEY, + neatline POLYGON); + +--echo # +--echo # C.3.3.2 Geometry types and functions schema data loading +--echo # + +# TODO: WL#2377 +#-- Spatial Reference System +#INSERT INTO spatial_ref_sys VALUES +#(101, 'POSC', 32214, 'PROJCS["UTM_ZONE_14N", +#GEOGCS["World Geodetic System 72", +#DATUM["WGS_72", +#ELLIPSOID["NWL_10D", 6378135, 298.26]], +#PRIMEM["Greenwich", 0], +#UNIT["Meter", 1.0]], +#PROJECTION["Transverse_Mercator"], +#PARAMETER["False_Easting", 500000.0], +#PARAMETER["False_Northing", 0.0], +#PARAMETER["Central_Meridian", -99.0], +#PARAMETER["Scale_Factor", 0.9996], +#PARAMETER["Latitude_of_origin", 0.0], +#UNIT["Meter", 1.0]]'); + +--echo # Lakes +INSERT INTO lakes VALUES ( +101, 'BLUE LAKE', +PolyFromText( +'POLYGON( +(52 18,66 23,73 9,48 6,52 18), +(59 18,67 18,67 13,59 13,59 18) +)', +101)); + + +--echo # Road Segments + +INSERT INTO road_segments VALUES(102, 'Route 5', NULL, 2, +LineFromText( +'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101)); + +INSERT INTO road_segments VALUES(103, 'Route 5', 'Main Street', 4, +LineFromText( +'LINESTRING( 44 31, 56 34, 70 38 )' ,101)); + +INSERT INTO road_segments VALUES(104, 'Route 5', NULL, 2, +LineFromText( +'LINESTRING( 70 38, 72 48 )' ,101)); + +INSERT INTO road_segments VALUES(105, 'Main Street', NULL, 4, +LineFromText( +'LINESTRING( 70 38, 84 42 )' ,101)); + +INSERT INTO road_segments VALUES(106, 'Dirt Road by Green Forest', NULL, +1, +LineFromText( +'LINESTRING( 28 26, 28 0 )',101)); + +--echo # DividedRoutes + +INSERT INTO divided_routes VALUES(119, 'Route 75', 4, +MLineFromText( +'MULTILINESTRING((10 48,10 21,10 0), +(16 0,16 23,16 48))', 101)); + +--echo # Forests + +INSERT INTO forests VALUES(109, 'Green Forest', +MPolyFromText( +'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26), +(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))', +101)); + +--echo # Bridges + +INSERT INTO bridges VALUES(110, 'Cam Bridge', PointFromText( +'POINT( 44 31 )', 101)); + +--echo # Streams + +INSERT INTO streams VALUES(111, 'Cam Stream', +LineFromText( +'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101)); + +INSERT INTO streams VALUES(112, NULL, +LineFromText( +'LINESTRING( 76 0, 78 4, 73 9 )', 101)); + +--echo # Buildings + +INSERT INTO buildings VALUES(113, '123 Main Street', +PointFromText( +'POINT( 52 30 )', 101), +PolyFromText( +'POLYGON( ( 50 31, 54 31, 54 29, 50 29, 50 31) )', 101)); + +INSERT INTO buildings VALUES(114, '215 Main Street', +PointFromText( +'POINT( 64 33 )', 101), +PolyFromText( +'POLYGON( ( 66 34, 62 34, 62 32, 66 32, 66 34) )', 101)); + + +--echo # Ponds + +INSERT INTO ponds VALUES(120, NULL, 'Stock Pond', +MPolyFromText( +'MULTIPOLYGON( ( ( 24 44, 22 42, 24 40, 24 44) ), +( ( 26 44, 26 40, 28 42, 26 44) ) )', 101)); + +--echo # Named Places + +INSERT INTO named_places VALUES(117, 'Ashton', +PolyFromText( +'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101)); + +INSERT INTO named_places VALUES(118, 'Goose Island', +PolyFromText( +'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101)); + +--echo # Map Neatlines + +INSERT INTO map_neatlines VALUES(115, +PolyFromText( +'POLYGON( ( 0 0, 0 48, 84 48, 84 0, 0 0 ) )', 101)); + +--echo # +--echo # C.3.3.3 Geometry types and functions schema test queries +--echo + +# TODO: WL#2377 +#--echo # Conformance Item T1 +#SELECT f_table_name +#FROM geometry_columns; +# +#--echo # Conformance Item T2 +#SELECT f_geometry_column +#FROM geometry_columns +#WHERE f_table_name = 'streams'; +# +#--echo # Conformance Item T3 +#SELECT coord_dimension +#FROM geometry_columns +#WHERE f_table_name = 'streams'; +# +#--echo # Conformance Item T4 +# +#SELECT srid +#FROM geometry_columns +#WHERE f_table_name = 'streams'; +# +#--echo # Conformance Item T5 +# +#SELECT srtext +#FROM SPATIAL_REF_SYS +#WHERE SRID = 101; +# + + +--echo # Conformance Item T6 +# TODO: ST_Dimension() alias +SELECT Dimension(shore) +FROM lakes +WHERE name = 'Blue Lake'; + +--echo # Conformance Item T7 +# TODO: ST_GeometryType() alias +SELECT GeometryType(centerlines) +FROM divided_routes +WHERE name = 'Route 75'; + +--echo # Conformance Item T8 +# TODO: ST_AsText() alias +SELECT AsText(boundary) +FROM named_places +WHERE name = 'Goose Island'; + +--echo # Conformance Item T9 +# TODO: ST_AsBinary(), ST_PolyFromWKB() aliases +SELECT AsText(PolyFromWKB(AsBinary(boundary),101)) +FROM named_places +WHERE name = 'Goose Island'; + +--echo # Conformance Item T10 +# TODO: ST_SRID() alias +SELECT SRID(boundary) +FROM named_places +WHERE name = 'Goose Island'; + +--echo # Conformance Item T11 +# TODO: ST_IsEmpty() alias +SELECT IsEmpty(centerline) +FROM road_segments +WHERE name = 'Route 5' +AND aliases = 'Main Street'; + +# FIXME: get wrong result:0, expected 1. +#--echo # Conformance Item T12 +# TODO: ST_IsSimple() alias +#SELECT IsSimple(shore) +#FROM lakes +#WHERE name = 'Blue Lake'; + +# TODO: WL#2377 +#--echo # Conformance Item T13 +#SELECT AsText(Boundary((boundary),101) +#FROM named_places +#WHERE name = 'Goose Island'; + +--echo # Conformance Item T14 +# TODO: ST_Envelope( ) alias +# FIXME: we get anticlockwise, GIS suggests clockwise +SELECT AsText(Envelope(boundary)) +FROM named_places +WHERE name = 'Goose Island'; + +--echo # Conformance Item T15 +# TODO: ST_X() alias +SELECT X(position) +FROM bridges +WHERE name = 'Cam Bridge'; + +--echo # Conformance Item T16 +# TODO: ST_Y() alias +SELECT Y(position) +FROM bridges +WHERE name = 'Cam Bridge'; + +--echo # Conformance Item T17 +# TODO: ST_StartPoint() alias +SELECT AsText(StartPoint(centerline)) +FROM road_segments +WHERE fid = 102; + +--echo # Conformance Item T18 +# TODO: ST_EndPoint +SELECT AsText(EndPoint(centerline)) +FROM road_segments +WHERE fid = 102; + +# TODO: WL#2377 +#--echo # Conformance Item T19 +# TODO: ST_LineFromWKB() alias +#SELECT IsClosed(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) +#FROM named_places +#WHERE name = 'Goose Island'; + +# TODO: WL#2377 +#--echo # Conformance Item T20 +#SELECT IsRing(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) +#FROM named_places +#WHERE name = 'Goose Island'; + +--echo # Conformance Item T21 +# TODO: ST_Length() alias +SELECT GLength(centerline) +FROM road_segments +WHERE fid = 106; + +--echo # Conformance Item T22 +# TODO: ST_NumPoints() alias +SELECT NumPoints(centerline) +FROM road_segments +WHERE fid = 102; + +--echo # Conformance Item T23 +# TODO: ST_PointN() alias +SELECT AsText(PointN(centerline, 1)) +FROM road_segments +WHERE fid = 102; + +--echo # Conformance Item T24 +# TODO: ST_Centroid() alias +SELECT AsText(Centroid(boundary)) +FROM named_places +WHERE name = 'Goose Island'; + +# TODO: WL#2377 +#--echo # Conformance Item T25 +#SELECT Contains(boundary, PointOnSurface(boundary)) +#FROM named_places +#WHERE name = 'Goose Island'; + +--echo # Conformance Item T26 +# TODO: ST_Area() alias +SELECT Area(boundary) +FROM named_places +WHERE name = 'Goose Island'; + +--echo # Conformance Item T27 +# TODO: ST_ExteriorRing() alias +SELECT AsText(ExteriorRing(shore)) +FROM lakes +WHERE name = 'Blue Lake'; + +--echo # Conformance Item T28 +# TODO: ST_NumInteriorRings() alias +SELECT NumInteriorRings(shore) +FROM lakes +WHERE name = 'Blue Lake'; + +--echo # Conformance Item T29 +# TODO: ST_InteriorRingN() alias +SELECT AsText(InteriorRingN(shore, 1)) +FROM lakes +WHERE name = 'Blue Lake'; + +--echo # Conformance Item T30 +# TODO: ST_NumGeometries() alias +SELECT NumGeometries(centerlines) +FROM divided_routes +WHERE name = 'Route 75'; + +--echo # Conformance Item T31 +# TODO: ST_GeometryN() alias +SELECT AsText(GeometryN(centerlines, 2)) +FROM divided_routes +WHERE name = 'Route 75'; + +--echo # Conformance Item T32 +# TODO: ST_IsClosed() alias +SELECT IsClosed(centerlines) +FROM divided_routes +WHERE name = 'Route 75'; + +--echo # Conformance Item T33 +# TODO: ST_Length() alias +SELECT GLength(centerlines) +FROM divided_routes +WHERE name = 'Route 75'; + +--echo # Conformance Item T34 +# TODO: ST_Centroid() alias +SELECT AsText(Centroid(shores)) +FROM ponds +WHERE fid = 120; + +# TODO: WL#2377 +#--echo # Conformance Item T35 +#SELECT Contains(shores, PointOnSurface(shores)) +#FROM ponds +#WHERE fid = 120; + +--echo # Conformance Item T36 +# TODO: ST_Area() alias +SELECT Area(shores) +FROM ponds +WHERE fid = 120; + +--echo # Conformance Item T37 +# TODO: ST_PolyFromText() alias +SELECT ST_Equals(boundary, +PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1)) +FROM named_places +WHERE name = 'Goose Island'; + +--echo # Conformance Item T38 +SELECT ST_Disjoint(centerlines, boundary) +FROM divided_routes, named_places +WHERE divided_routes.name = 'Route 75' +AND named_places.name = 'Ashton'; + +--echo # Conformance Item T39 +SELECT ST_Touches(centerline, shore) +FROM streams, lakes +WHERE streams.name = 'Cam Stream' +AND lakes.name = 'Blue Lake'; + +# FIXME: wrong result: get 0, expected 1 +#--echo # Conformance Item T40 +#SELECT ST_Within(boundary, footprint) +#FROM named_places, buildings +#WHERE named_places.name = 'Ashton' +#AND buildings.address = '215 Main Street'; + +# FIXME: wrong result: get 0, expected 1 +#--echo # Conformance Item T41 +#SELECT ST_Overlaps(forests.boundary, named_places.boundary) +#FROM forests, named_places +#WHERE forests.name = 'Green Forest' +#AND named_places.name = 'Ashton'; + +--echo # Conformance Item T42 +# FIXME: TODO: ST_Crosses() alias +SELECT Crosses(road_segments.centerline, divided_routes.centerlines) +FROM road_segments, divided_routes +WHERE road_segments.fid = 102 +AND divided_routes.name = 'Route 75'; + +--echo # Conformance Item T43 +SELECT ST_Intersects(road_segments.centerline, divided_routes.centerlines) +FROM road_segments, divided_routes +WHERE road_segments.fid = 102 +AND divided_routes.name = 'Route 75'; + +--echo # Conformance Item T44 +SELECT ST_Contains(forests.boundary, named_places.boundary) +FROM forests, named_places +WHERE forests.name = 'Green Forest' +AND named_places.name = 'Ashton'; + +# TODO: WL#2377 +#--echo # Conformance Item T45 +#SELECT Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT') +#FROM forests, named_places +#WHERE forests.name = 'Green Forest' +#AND named_places.name = 'Ashton'; + +--echo # Conformance Item T46 +SELECT ST_Distance(position, boundary) +FROM bridges, named_places +WHERE bridges.name = 'Cam Bridge' +AND named_places.name = 'Ashton'; + +# FIXME: wrong result: NULL, expected 12 +#--echo # Conformance Item T47 +#SELECT AsText(ST_Intersection(centerline, shore)) +#FROM streams, lakes +#WHERE streams.name = 'Cam Stream' +#AND lakes.name = 'Blue Lake'; + +--echo # Conformance Item T48 +SELECT AsText(ST_Difference(named_places.boundary, forests.boundary)) +FROM named_places, forests +WHERE named_places.name = 'Ashton' +AND forests.name = 'Green Forest'; + +#--echo # Conformance Item T49 +SELECT AsText(ST_Union(shore, boundary)) +FROM lakes, named_places +WHERE lakes.name = 'Blue Lake' +AND named_places.name = 'Goose Island'; + +--echo # Conformance Item T50 +SELECT AsText(ST_SymDifference(shore, boundary)) +FROM lakes, named_places +WHERE lakes.name = 'Blue Lake' +AND named_places.name = 'Ashton'; + +--echo # Conformance Item T51 +SELECT count(*) +FROM buildings, bridges +WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; + +# TODO: WL#2377 +#--echo # Conformance Item T52 +#SELECT AsText(ConvexHull(shore)) +#FROM lakes +#WHERE lakes.name = 'Blue Lake'; + +DROP DATABASE gis_ogs; diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 8d2aeca17db..96c3643ccbc 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -78,6 +78,7 @@ SET (SQL_SOURCE rpl_rli.cc rpl_mi.cc sql_servers.cc sql_connect.cc scheduler.cc sql_profile.cc event_parse_data.cc opt_table_elimination.cc + gcalc_slicescan.cc gcalc_tools.cc multi_range_read.cc opt_subselect.cc opt_index_cond_pushdown.cc diff --git a/sql/Makefile.am b/sql/Makefile.am index cde8962b8d0..54a2fafb2c7 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -56,6 +56,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ sql_map.h sql_string.h unireg.h \ sql_error.h field.h handler.h mysqld_suffix.h \ sql_profile.h \ + gcalc_slicescan.h gcalc_tools.h \ ha_ndbcluster.h ha_ndbcluster_cond.h \ ha_ndbcluster_binlog.h ha_ndbcluster_tables.h \ ha_partition.h rpl_constants.h \ @@ -101,6 +102,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ sql_join_cache.cc \ sql_base.cc table.cc sql_select.cc sql_insert.cc \ sql_profile.cc \ + gcalc_slicescan.cc gcalc_tools.cc \ sql_prepare.cc sql_error.cc sql_locale.cc \ sql_update.cc sql_delete.cc uniques.cc sql_do.cc \ procedure.cc sql_test.cc \ diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc new file mode 100644 index 00000000000..4a77f309f46 --- /dev/null +++ b/sql/gcalc_slicescan.cc @@ -0,0 +1,762 @@ +/* Copyright (c) 2000, 2010 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include "mysql_priv.h" + +#ifdef HAVE_SPATIAL + +#include "gcalc_slicescan.h" + + +#define PH_DATA_OFFSET 8 +#define coord_to_float(d) ((double) d) + +typedef int (*sc_compare_func)(const void*, const void*); + +#define LS_LIST_ITEM Gcalc_dyn_list::Item +#define LS_COMPARE_FUNC_DECL sc_compare_func compare, +#define LS_COMPARE_FUNC_CALL(list_el1, list_el2) (*compare)(list_el1, list_el2) +#define LS_NEXT(A) (A)->next +#define LS_SET_NEXT(A,val) (A)->next= val +#define LS_P_NEXT(A) &(A)->next +#define LS_NAME sort_list +#define LS_SCOPE static +#define LS_STRUCT_NAME sort_list_stack_struct +#include "plistsort.c" + + +Gcalc_dyn_list::Gcalc_dyn_list(size_t blk_size, size_t sizeof_item): + m_blk_size(blk_size - ALLOC_ROOT_MIN_BLOCK_SIZE), + m_sizeof_item(ALIGN_SIZE(sizeof_item)), + m_points_per_blk((m_blk_size - PH_DATA_OFFSET) / m_sizeof_item), + m_blk_hook(&m_first_blk), + m_free(NULL), + m_keep(NULL) +{} + + +void Gcalc_dyn_list::format_blk(void* block) +{ + Item *pi_end, *cur_pi, *first_pi; + DBUG_ASSERT(m_free == NULL); + first_pi= cur_pi= (Item *)(((char *)block) + PH_DATA_OFFSET); + pi_end= ptr_add(first_pi, m_points_per_blk - 1); + do { + cur_pi= cur_pi->next= ptr_add(cur_pi, 1); + } while (cur_pinext= m_free; + m_free= first_pi; +} + + +Gcalc_dyn_list::Item *Gcalc_dyn_list::alloc_new_blk() +{ + void *new_block= my_malloc(m_blk_size, MYF(MY_WME)); + if (!new_block) + return NULL; + *m_blk_hook= new_block; + m_blk_hook= (void**)new_block; + format_blk(new_block); + return new_item(); +} + + +static void free_blk_list(void *list) +{ + void *next_blk; + while (list) + { + next_blk= *((void **)list); + my_free(list, MYF(0)); + list= next_blk; + } +} + + +void Gcalc_dyn_list::cleanup() +{ + *m_blk_hook= NULL; + free_blk_list(m_first_blk); + m_first_blk= NULL; + m_blk_hook= &m_first_blk; + m_free= NULL; +} + + +Gcalc_dyn_list::~Gcalc_dyn_list() +{ + cleanup(); +} + + +void Gcalc_dyn_list::reset() +{ + *m_blk_hook= NULL; + if (m_first_blk) + { + free_blk_list(*((void **)m_first_blk)); + m_blk_hook= (void**)m_first_blk; + m_free= NULL; + format_blk(m_first_blk); + } +} + + +static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node) +{ + if (!node) + return; + DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node)); + if (node->left == prev_node) + node->left= node->right; + node->right= NULL; +} + + +static double find_first_different(const Gcalc_heap::Info *p) +{ + if (p->left && (p->left->y != p->y)) + return p->left->y; + if (p->right && (p->right->y != p->y)) + return p->right->y; + if (p->left && p->left->left && (p->left->left->y != p->y)) + return p->left->left->y; + if (p->right && p->right->right && (p->right->right->y != p->y)) + return p->right->right->y; + + return p->y; +} + + +static int compare_point_info(const void *e0, const void *e1) +{ + const Gcalc_heap::Info *i0= (const Gcalc_heap::Info *)e0; + const Gcalc_heap::Info *i1= (const Gcalc_heap::Info *)e1; + if (i0->y != i1->y) + return i0->y > i1->y; + return find_first_different(i0) > find_first_different(i1); +} + + +void Gcalc_heap::prepare_operation() +{ + DBUG_ASSERT(m_hook); + *m_hook= NULL; + m_first= sort_list(compare_point_info, m_first, m_n_points); + m_hook= NULL; /* just to check it's not called twice */ + + /* TODO - move this to the 'normal_scan' loop */ + for (Info *cur= get_first(); cur; cur= cur->get_next()) + { + trim_node(cur->left, cur); + trim_node(cur->right, cur); + } +} + + +void Gcalc_heap::reset() +{ + if (!m_hook) + { + m_hook= &m_first; + for (; *m_hook; m_hook= &(*m_hook)->next) + {} + } + + *m_hook= m_free; + m_free= m_first; + m_hook= &m_first; + m_n_points= 0; +} + +int Gcalc_shape_transporter::int_single_point(gcalc_shape_info Info, + double x, double y) +{ + Gcalc_heap::Info *point= m_heap->new_point_info(x, y, Info); + if (!point) + return 1; + point->left= point->right= 0; + return 0; +} + + +int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info, + double x, double y) +{ + Gcalc_heap::Info *point; + if (!(point= m_heap->new_point_info(x, y, Info))) + return 1; + if (m_first) + { + m_prev->left= point; + point->right= m_prev; + } + else + m_first= point; + m_prev= point; + return 0; +} + + +void Gcalc_shape_transporter::int_complete() +{ + DBUG_ASSERT(m_shape_started == 1 || m_shape_started == 3); + + if (!m_first) + return; + + /* simple point */ + if (m_first == m_prev) + { + m_first->right= m_first->left= NULL; + return; + } + + /* line */ + if (m_shape_started == 1) + { + m_first->right= NULL; + m_prev->left= m_prev->right; + m_prev->right= NULL; + return; + } + + /* polygon */ + m_first->right= m_prev; + m_prev->left= m_first; +} + + +inline int GET_DX_DY(double *dxdy, + const Gcalc_heap::Info *p0, const Gcalc_heap::Info *p1) +{ + double dy= p1->y - p0->y; + *dxdy= p1->x - p0->x; + return (dy == 0.0) || + (*dxdy/= dy)>DBL_MAX || + (*dxdy)<-DBL_MAX; +} + +Gcalc_scan_iterator::Gcalc_scan_iterator(size_t blk_size) : + Gcalc_dyn_list(blk_size, + (sizeof(point) > sizeof(intersection)) ? + sizeof(point) : sizeof(intersection)), + m_slice0(NULL), m_slice1(NULL) +{} + +Gcalc_scan_iterator::point + *Gcalc_scan_iterator::new_slice(Gcalc_scan_iterator::point *example) +{ + point *result= NULL; + Gcalc_dyn_list::Item **result_hook= (Gcalc_dyn_list::Item **)&result; + while (example) + { + *result_hook= new_slice_point(); + result_hook= &(*result_hook)->next; + example= example->get_next(); + } + *result_hook= NULL; + return result; +} + + +void Gcalc_scan_iterator::init(Gcalc_heap *points) +{ + DBUG_ASSERT(points->ready()); + DBUG_ASSERT(!m_slice0 && !m_slice1); + + if (!(m_cur_pi= points->get_first())) + return; + m_cur_thread= 0; + m_sav_slice= NULL; + m_intersections= NULL; + m_cur_intersection= NULL; + m_y1= m_cur_pi->y; + m_next_is_top_point= true; + m_bottom_points_count= 0; +} + +void Gcalc_scan_iterator::reset() +{ + if (m_slice0) + free_list(m_slice0); + if (m_slice1) + free_list(m_slice1); + m_slice0= m_slice1= NULL; + Gcalc_dyn_list::reset(); +} + +static bool slice_first_equal_x(const Gcalc_scan_iterator::point *p0, + const Gcalc_scan_iterator::point *p1) +{ + if (p0->horiz_dir == p1->horiz_dir) + return p0->dx_dy <= p1->dx_dy; + if (p0->horiz_dir) + return p0->dx_dy < 0; + return p1->dx_dy > 0; /* p1->horiz_dir case */ +} + + +static inline bool slice_first(const Gcalc_scan_iterator::point *p0, + const Gcalc_scan_iterator::point *p1) +{ + if (p0->x != p1->x) + return p0->x < p1->x; + return slice_first_equal_x(p0, p1); +} + + +int Gcalc_scan_iterator::insert_top_point() +{ + point *sp= m_slice1; + Gcalc_dyn_list::Item **prev_hook= (Gcalc_dyn_list::Item **)&m_slice1; + point *sp1; + point *sp0= new_slice_point(); + + if (!sp0) + return 1; + sp0->pi= m_cur_pi; + sp0->next_pi= m_cur_pi->left; + sp0->thread= m_cur_thread++; + sp0->x= coord_to_float(m_cur_pi->x); + if (m_cur_pi->left) + { + sp0->horiz_dir= GET_DX_DY(&sp0->dx_dy, m_cur_pi, m_cur_pi->left); + m_event1= scev_thread; + + /*Now just to increase the size of m_slice0 to be same*/ + if (!(sp1= new_slice_point())) + return 1; + sp1->next= m_slice0; + m_slice0= sp1; + } + else + { + m_event1= scev_single_point; + sp0->horiz_dir= 0; + sp0->dx_dy= 0.0; + } + + /* First we need to find the place to insert. + Binary search could probably make things faster here, + but structures used aren't suitable, and the + scan is usually not really long */ + for (; sp && slice_first(sp, sp0); + prev_hook= &sp->next, sp=sp->get_next()) + {} + + if (m_cur_pi->right) + { + m_event1= scev_two_threads; + /*We have two threads so should decide which one will be first*/ + sp1= new_slice_point(); + if (!sp1) + return 1; + sp1->pi= m_cur_pi; + sp1->next_pi= m_cur_pi->right; + sp1->thread= m_cur_thread++; + sp1->x= sp0->x; + sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->right); + if (slice_first_equal_x(sp1, sp0)) + { + point *tmp= sp0; + sp0= sp1; + sp1= tmp; + } + sp1->next= sp; + sp0->next= sp1; + + /*Now just to increase the size of m_slice0 to be same*/ + if (!(sp1= new_slice_point())) + return 1; + sp1->next= m_slice0; + m_slice0= sp1; + } + else + sp0->next= sp; + + *prev_hook= sp0; + m_event_position1= sp0; + + return 0; +} + +enum +{ + intersection_normal= 1, + intersection_forced= 2 +}; + + +static int intersection_found(const Gcalc_scan_iterator::point *sp0, + const Gcalc_scan_iterator::point *sp1, + unsigned int bottom_points_count) +{ + if (sp1->x < sp0->x) + return intersection_normal; + if (sp1->is_bottom() && !sp0->is_bottom() && + (bottom_points_count > 1)) + return intersection_forced; + return 0; +} + + +int Gcalc_scan_iterator::normal_scan() +{ + if (m_next_is_top_point) + if (insert_top_point()) + return 1; + + point *tmp= m_slice0; + m_slice0= m_slice1; + m_slice1= tmp; + m_event0= m_event1; + m_event_position0= m_event_position1; + m_y0= m_y1; + + if (!(m_cur_pi= m_cur_pi->get_next())) + { + free_list(m_slice1); + m_slice1= NULL; + return 0; + } + + Gcalc_heap::Info *cur_pi= m_cur_pi; + m_y1= coord_to_float(cur_pi->y); + m_h= m_y1 - m_y0; + + point *sp0= m_slice0; + point *sp1= m_slice1; + point *prev_sp1= NULL; + + m_bottom_points_count= 0; + m_next_is_top_point= true; + bool intersections_found= false; + + for (; sp0; sp0= sp0->get_next()) + { + if (sp0->next_pi == cur_pi) /* End of the segment */ + { + sp1->x= coord_to_float(cur_pi->x); + sp1->pi= cur_pi; + sp1->thread= sp0->thread; + sp1->next_pi= cur_pi->left; + if (cur_pi->left) + sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->left); + + m_next_is_top_point= false; + + if (sp1->is_bottom()) + { + ++m_bottom_points_count; + if (m_bottom_points_count == 1) + { + m_event1= scev_end; + m_event_position1= sp1; + } + else + m_event1= scev_two_ends; + } + else + { + m_event1= scev_point; + m_event_position1= sp1; + } + } + else if (!sp0->is_bottom()) + { + /* Cut current string with the height of the new point*/ + sp1->copy_core(sp0); + sp1->x= sp1->horiz_dir ? sp0->x : + (coord_to_float(sp1->pi->x) + + (m_y1-coord_to_float(sp1->pi->y)) * sp1->dx_dy); + } + else /* Skip the bottom point in slice0 */ + continue; + + intersections_found= intersections_found || + (prev_sp1 && intersection_found(prev_sp1, sp1, m_bottom_points_count)); + + prev_sp1= sp1; + sp1= sp1->get_next(); + } + + if (sp1) + { + if (prev_sp1) + prev_sp1->next= NULL; + else + m_slice1= NULL; + free_list(sp1); + } + + if (intersections_found) + return handle_intersections(); + + return 0; +} + + +int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, + int isc_kind, Gcalc_dyn_list::Item ***p_hook) +{ + intersection *isc= new_intersection(); + + if (!isc) + return 1; + m_n_intersections++; + **p_hook= isc; + *p_hook= &isc->next; + isc->thread_a= a->thread; + isc->thread_b= b->thread; + if (isc_kind == intersection_forced) + { + isc->y= m_y1; + isc->x= a->x; + return 0; + } + + /* intersection_normal */ + const point *a0= a->precursor; + const point *b0= b->precursor; + if (!a0->horiz_dir && !b0->horiz_dir) + { + double dk= a0->dx_dy - b0->dx_dy; + double dy= (b0->x - a0->x)/dk; + isc->y= m_y0 + dy; + isc->x= a0->x + dy*a0->dx_dy; + return 0; + } + isc->y= m_y1; + isc->x= a0->horiz_dir ? b->x : a->x; + return 0; +} + + +int Gcalc_scan_iterator::find_intersections() +{ + point *sp1= m_slice1; + Gcalc_dyn_list::Item **hook; + + m_n_intersections= 0; + { + /* Set links between slicepoints */ + point *sp0= m_slice0; + for (; sp1; sp0= sp0->get_next(),sp1= sp1->get_next()) + { + while (sp0->is_bottom()) + sp0= sp0->get_next(); + DBUG_ASSERT(sp0->thread == sp1->thread); + sp1->precursor= sp0; + } + } + + hook= (Gcalc_dyn_list::Item **)&m_intersections; + bool intersections_found; + + point *last_possible_isc= NULL; + do + { + sp1= m_slice1; + point **pprev_s1= &m_slice1; + intersections_found= false; + unsigned int bottom_points_count= sp1->is_bottom() ? 1:0; + sp1= m_slice1->get_next(); + int isc_kind; + point *cur_possible_isc= NULL; + for (; sp1 != last_possible_isc; + pprev_s1= (point **)(&(*pprev_s1)->next), sp1= sp1->get_next()) + { + if (sp1->is_bottom()) + ++bottom_points_count; + if (!(isc_kind=intersection_found(*pprev_s1, sp1, bottom_points_count))) + continue; + point *prev_s1= *pprev_s1; + intersections_found= true; + if (add_intersection(prev_s1, sp1, isc_kind, &hook)) + return 1; + *pprev_s1= sp1; + prev_s1->next= sp1->next; + sp1->next= prev_s1; + sp1= prev_s1; + cur_possible_isc= sp1; + } + last_possible_isc= cur_possible_isc; + } while (intersections_found); + + *hook= NULL; + return 0; +} + + +static int compare_intersections(const void *e0, const void *e1) +{ + Gcalc_scan_iterator::intersection *i0= (Gcalc_scan_iterator::intersection *)e0; + Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1; + return i0->y > i1->y; +} + + +inline void Gcalc_scan_iterator::sort_intersections() +{ + m_intersections= (intersection *)sort_list(compare_intersections, + m_intersections,m_n_intersections); +} + + +int Gcalc_scan_iterator::handle_intersections() +{ + DBUG_ASSERT(m_slice1->next); + + if (find_intersections()) + return 1; + sort_intersections(); + + m_sav_slice= m_slice1; + m_sav_y= m_y1; + m_slice1= new_slice(m_sav_slice); + + m_cur_intersection= m_intersections; + m_pre_intersection_hook= NULL; + return intersection_scan(); +} + + +void Gcalc_scan_iterator::pop_suitable_intersection() +{ + intersection *prev_i= m_cur_intersection; + intersection *cur_i= prev_i->get_next(); + for (; cur_i; prev_i= cur_i, cur_i= cur_i->get_next()) + { + point *prev_p= m_slice0; + point *sp= prev_p->get_next(); + for (; sp; prev_p= sp, sp= sp->get_next()) + { + if ((prev_p->thread == cur_i->thread_a) && + (sp->thread == cur_i->thread_b)) + { + /* Move cur_t on the top of the list */ + if (prev_i == m_cur_intersection) + { + m_cur_intersection->next= cur_i->next; + cur_i->next= m_cur_intersection; + m_cur_intersection= cur_i; + } + else + { + Gcalc_dyn_list::Item *tmp= m_cur_intersection->next; + m_cur_intersection->next= cur_i->next; + prev_i->next= m_cur_intersection; + m_cur_intersection= cur_i; + cur_i->next= tmp; + } + return; + } + } + } + DBUG_ASSERT(0); +} + + +int Gcalc_scan_iterator::intersection_scan() +{ + if (m_pre_intersection_hook) /*Skip the first point*/ + { + point *next= (*m_pre_intersection_hook)->get_next(); + (*m_pre_intersection_hook)->next= next->next; + next->next= *m_pre_intersection_hook; + *m_pre_intersection_hook= next; + m_event0= scev_intersection; + m_event_position0= next; + point *tmp= m_slice1; + m_slice1= m_slice0; + m_slice0= tmp; + m_y0= m_y1; + m_cur_intersection= m_cur_intersection->get_next(); + if (!m_cur_intersection) + { + m_h= m_sav_y - m_y1; + m_y1= m_sav_y; + free_list(m_slice1); + m_slice1= m_sav_slice; + free_list(m_intersections); + return 0; + } + } + + m_y1= m_cur_intersection->y; + m_h= m_y1 - m_y0; + + point *sp0; + point **psp1; + +redo_loop: + sp0= m_slice0; + psp1= &m_slice1; + for (; sp0; sp0= sp0->get_next()) + { + point *sp1= *psp1; + if (sp0->thread == m_cur_intersection->thread_a) + { + point *next_s0= sp0; + /* Skip Bottom points */ + do + next_s0= next_s0->get_next(); + while(next_s0->is_bottom()); /* We always find nonbottom point here*/ + /* If the next point's thread isn't the thread of intersection, + we try to find suitable intersection */ + if (next_s0->thread != m_cur_intersection->thread_b) + { + /* It's really rare case - sometimes happen when + there's two intersections with the same Y + Move suitable one to the beginning of the list + */ + pop_suitable_intersection(); + goto redo_loop; + } + m_pre_intersection_hook= psp1; + sp1->copy_core(sp0); + sp1->x= m_cur_intersection->x; + sp0= next_s0; + sp1= sp1->get_next(); + sp1->copy_core(sp0); + sp1->x= m_cur_intersection->x; + psp1= (point **)&sp1->next; + continue; + } + if (!sp0->is_bottom()) + { + sp1->copy_core(sp0); + sp1->x= sp1->horiz_dir ? sp0->x : + (coord_to_float(sp1->pi->x) + + (m_y1-coord_to_float(sp1->pi->y)) * sp1->dx_dy); + } + else + /* Skip bottom point */ + continue; + psp1= (point **)&sp1->next; + } + + if (*psp1) + { + free_list(*psp1); + *psp1= NULL; + } + + return 0; +} + +#endif /* HAVE_SPATIAL */ diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h new file mode 100644 index 00000000000..3ea910dc4fd --- /dev/null +++ b/sql/gcalc_slicescan.h @@ -0,0 +1,433 @@ +/* Copyright (c) 2000, 2010 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef GCALC_SLICESCAN_INCLUDED +#define GCALC_SLICESCAN_INCLUDED + + +/* + Gcalc_dyn_list class designed to manage long lists of same-size objects + with the possible efficiency. + It allocates fixed-size blocks of memory (blk_size specified at the time + of creation). When new object is added to the list, it occupies part of + this block until it's full. Then the new block is allocated. + Freed objects are chained to the m_free list, and if it's not empty, the + newly added object is taken from this list instead the block. +*/ + +class Gcalc_dyn_list +{ +public: + class Item + { + public: + Item *next; + }; + + Gcalc_dyn_list(size_t blk_size, size_t sizeof_item); + ~Gcalc_dyn_list(); + Item *new_item() + { + Item *result; + if (m_free) + { + result= m_free; + m_free= m_free->next; + } + else + result= alloc_new_blk(); + + return result; + } + inline void free_item(Item *item) + { + item->next= m_free; + m_free= item; + } + inline void free_list(Item *list, Item **hook) + { + *hook= m_free; + m_free= list; + } + + void free_list(Item *list) + { + Item **hook= &list; + while (*hook) + hook= &(*hook)->next; + free_list(list, hook); + } + + void reset(); + void cleanup(); + +protected: + size_t m_blk_size; + size_t m_sizeof_item; + unsigned int m_points_per_blk; + void *m_first_blk; + void **m_blk_hook; + Item *m_free; + Item *m_keep; + + Item *alloc_new_blk(); + void format_blk(void* block); + inline Item *ptr_add(Item *ptr, int n_items) + { + return (Item *)(((char*)ptr) + n_items * m_sizeof_item); + } +}; + +typedef uint gcalc_shape_info; + +/* + Gcalc_heap represents the 'dynamic list' of Info objects, that + contain information about vertexes of all the shapes that take + part in some spatial calculation. Can become quite long. + After filled, the list is usually sorted and then walked through + in the slicescan algorithm. + The Gcalc_heap and the algorithm can only operate with two + kinds of shapes - polygon and polyline. So all the spatial + objects should be represented as sets of these two. +*/ + +class Gcalc_heap : public Gcalc_dyn_list +{ +public: + class Info : public Gcalc_dyn_list::Item + { + public: + gcalc_shape_info shape; + Info *left; + Info *right; + double x,y; + + inline bool is_bottom() const { return !left; } + inline Info *get_next() { return (Info *)next; } + inline const Info *get_next() const { return (const Info *)next; } + }; + + Gcalc_heap(size_t blk_size=8192) : + Gcalc_dyn_list(blk_size, sizeof(Info)), m_hook(&m_first), m_n_points(0) {} + Info *new_point_info(double x, double y, gcalc_shape_info shape) + { + Info *result= (Info *)new_item(); + if (!result) + return NULL; + *m_hook= result; + m_hook= &result->next; + m_n_points++; + result->x= x; + result->y= y; + result->shape= shape; + return result; + } + void prepare_operation(); + inline bool ready() const { return m_hook == NULL; } + Info *get_first() { return (Info *)m_first; } + const Info *get_first() const { return (const Info *)m_first; } + Gcalc_dyn_list::Item **get_last_hook() { return m_hook; } + void reset(); +private: + Gcalc_dyn_list::Item *m_first; + Gcalc_dyn_list::Item **m_hook; + int m_n_points; +}; + + +/* + the spatial object has to be represented as a set of + simple polygones and polylines to be sent to the slicescan. + + Gcalc_shape_transporter class and his descendants are used to + simplify storing the information about the shape into necessary structures. + This base class only fills the Gcalc_heap with the information about + shapes and vertices. + + Normally the Gcalc_shape_transporter family object is sent as a parameter + to the 'get_shapes' method of an 'spatial' object so it can pass + the spatial information about itself. The virtual methods are + treating this data in a way the caller needs. +*/ + +class Gcalc_shape_transporter +{ +private: + Gcalc_heap::Info *m_first; + Gcalc_heap::Info *m_prev; + int m_shape_started; + void int_complete(); +protected: + Gcalc_heap *m_heap; + int int_single_point(gcalc_shape_info Info, double x, double y); + int int_add_point(gcalc_shape_info Info, double x, double y); + void int_start_line() + { + DBUG_ASSERT(!m_shape_started); + m_shape_started= 1; + m_first= m_prev= NULL; + } + void int_complete_line() + { + DBUG_ASSERT(m_shape_started== 1); + int_complete(); + m_shape_started= 0; + } + void int_start_ring() + { + DBUG_ASSERT(m_shape_started== 2); + m_shape_started= 3; + m_first= m_prev= NULL; + } + void int_complete_ring() + { + DBUG_ASSERT(m_shape_started== 3); + int_complete(); + m_shape_started= 2; + } + void int_start_poly() + { + DBUG_ASSERT(!m_shape_started); + m_shape_started= 2; + } + void int_complete_poly() + { + DBUG_ASSERT(m_shape_started== 2); + m_shape_started= 0; + } + bool line_started() { return m_shape_started == 1; }; +public: + Gcalc_shape_transporter(Gcalc_heap *heap) : + m_shape_started(0), m_heap(heap) {} + + virtual int single_point(double x, double y)=0; + virtual int start_line()=0; + virtual int complete_line()=0; + virtual int start_poly()=0; + virtual int complete_poly()=0; + virtual int start_ring()=0; + virtual int complete_ring()=0; + virtual int add_point(double x, double y)=0; + virtual int start_collection(int n_objects) { return 0; } + int start_simple_poly() + { + return start_poly() || start_ring(); + } + int complete_simple_poly() + { + return complete_ring() || complete_poly(); + } + virtual ~Gcalc_shape_transporter() {} +}; + + +enum Gcalc_scan_events +{ + scev_point= 1, /* Just a new point in thread */ + scev_thread= 2, /* Start of the new thread */ + scev_two_threads= 4, /* A couple of new threads started */ + scev_intersection= 8, /* Intersection happened */ + scev_end= 16, /* Single thread finished */ + scev_two_ends= 32, /* A couple of threads finished */ + scev_single_point= 64 /* Got single point */ +}; + +typedef int sc_thread_id; + +/* + Gcalc_scan_iterator incapsulates the slisescan algorithm. + It takes filled Gcalc_heap as an datasource. Then can be + iterated trought the vertexes and intersection points with + the step() method. After the 'step()' one usually observes + the current 'slice' to do the necessary calculations, like + looking for intersections, calculating the area, whatever. +*/ + +class Gcalc_scan_iterator : public Gcalc_dyn_list +{ +public: + class point : public Gcalc_dyn_list::Item + { + public: + double x; + double dx_dy; + int horiz_dir; + Gcalc_heap::Info *pi; + Gcalc_heap::Info *next_pi; + sc_thread_id thread; + const point *precursor; /* used as a temporary field */ + + inline const point *c_get_next() const + { return (const point *)next; } + inline bool is_bottom() const { return pi->is_bottom(); } + gcalc_shape_info get_shape() const { return pi->shape; } + inline point *get_next() { return (point *)next; } + inline const point *get_next() const { return (const point *)next; } + + /* copies all but 'next' 'x' and 'precursor' */ + void copy_core(const point *from) + { + dx_dy= from->dx_dy; + horiz_dir= from->horiz_dir; + pi= from->pi; + next_pi= from->next_pi; + thread= from->thread; + } +#ifndef DBUG_OFF + void dbug_print(); +#endif /*DBUG_OFF*/ + }; + + class intersection : public Gcalc_dyn_list::Item + { + public: + sc_thread_id thread_a; + sc_thread_id thread_b; + double x; + double y; + inline intersection *get_next() { return (intersection *)next; } + }; + +public: + Gcalc_scan_iterator(size_t blk_size= 8192); + + void init(Gcalc_heap *points); /* Iterator can be reused */ + void reset(); + int step() + { + DBUG_ASSERT(more_points()); + return m_cur_intersection ? intersection_scan() : normal_scan(); + } + + inline Gcalc_heap::Info *more_points() { return m_cur_pi; } + inline bool more_trapezoids() + { return m_cur_pi && m_cur_pi->next; } + + inline Gcalc_scan_events get_event() const { return m_event0; } + inline const point *get_event_position() const + { return m_event_position0; } + inline const point *get_b_slice() const { return m_slice0; } + inline const point *get_t_slice() const { return m_slice1; } + inline double get_h() const { return m_h; } + inline double get_y() const { return m_y0; } + +private: + Gcalc_heap::Info *m_cur_pi; + point *m_slice0; + point *m_slice1; + point *m_sav_slice; + intersection *m_intersections; + int m_n_intersections; + intersection *m_cur_intersection; + point **m_pre_intersection_hook; + double m_h; + double m_y0; + double m_y1; + double m_sav_y; + bool m_next_is_top_point; + unsigned int m_bottom_points_count; + sc_thread_id m_cur_thread; + Gcalc_scan_events m_event0, m_event1; + point *m_event_position0; + point *m_event_position1; + + int normal_scan(); + int intersection_scan(); + void sort_intersections(); + int handle_intersections(); + int insert_top_point(); + int add_intersection(const point *a, const point *b, + int isc_kind, Gcalc_dyn_list::Item ***p_hook); + int find_intersections(); + void pop_suitable_intersection(); + + intersection *new_intersection() + { + return (intersection *)new_item(); + } + point *new_slice_point() + { + return (point *)new_item(); + } + point *new_slice(point *example); +}; + + +/* + Gcalc_trapezoid_iterator simplifies the calculations on + the current slice of the Gcalc_scan_iterator. + One can walk through the trapezoids formed between + previous and current slices. +*/ + +class Gcalc_trapezoid_iterator +{ +protected: + const Gcalc_scan_iterator::point *sp0; + const Gcalc_scan_iterator::point *sp1; +public: + Gcalc_trapezoid_iterator(const Gcalc_scan_iterator *scan_i) : + sp0(scan_i->get_b_slice()), + sp1(scan_i->get_t_slice()) + {} + + inline bool more() const { return sp1 && sp1->next; } + + const Gcalc_scan_iterator::point *lt() const { return sp1; } + const Gcalc_scan_iterator::point *lb() const { return sp0; } + const Gcalc_scan_iterator::point *rb() const + { + const Gcalc_scan_iterator::point *result= sp0; + while ((result= result->c_get_next())->is_bottom()) + {} + return result; + } + const Gcalc_scan_iterator::point *rt() const + { return sp1->c_get_next(); } + + void operator++() + { + sp0= rb(); + sp1= rt(); + } +}; + + +/* + Gcalc_point_iterator simplifies the calculations on + the current slice of the Gcalc_scan_iterator. + One can walk through the points on the current slice. +*/ + +class Gcalc_point_iterator +{ +protected: + const Gcalc_scan_iterator::point *sp; +public: + Gcalc_point_iterator(const Gcalc_scan_iterator *scan_i): + sp(scan_i->get_b_slice()) + {} + + inline bool more() const { return sp != NULL; } + inline void operator++() { sp= sp->c_get_next(); } + inline const Gcalc_scan_iterator::point *point() const { return sp; } + inline const Gcalc_heap::Info *get_pi() const { return sp->pi; } + inline gcalc_shape_info get_shape() const { return sp->get_shape(); } + inline double get_x() const { return sp->x; } +}; + +#endif /*GCALC_SLICESCAN_INCLUDED*/ + diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc new file mode 100644 index 00000000000..0e2970116ce --- /dev/null +++ b/sql/gcalc_tools.cc @@ -0,0 +1,1156 @@ +/* Copyright (c) 2000, 2010 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include "mysql_priv.h" + +#ifdef HAVE_SPATIAL + +#include "gcalc_tools.h" +#include "spatial.h" + +#define float_to_coord(d) ((double) d) + + +/* + Adds new shape to the relation. + After that it can be used as an argument of an operation. +*/ + +gcalc_shape_info Gcalc_function::add_new_shape(uint32 shape_id, + shape_type shape_kind) +{ + shapes_buffer.q_append((uint32) shape_kind); + return n_shapes++; +} + + +/* + Adds new operation to the constructed relation. + To construct the complex relation one has to specify operations + in prefix style. +*/ + +void Gcalc_function::add_operation(op_type operation, uint32 n_operands) +{ + uint32 op_code= (uint32 ) operation + n_operands; + function_buffer.q_append(op_code); +} + + +/* + Sometimes the number of arguments is unknown at the moment the operation + is added. That allows to specify it later. +*/ + +void Gcalc_function::add_operands_to_op(uint32 operation_pos, uint32 n_operands) +{ + uint32 op_code= uint4korr(function_buffer.ptr() + operation_pos) + n_operands; + function_buffer.write_at_position(operation_pos, op_code); +} + + +/* + Just like the add_operation() but the result will be the inverted + value of an operation. +*/ + +void Gcalc_function::add_not_operation(op_type operation, uint32 n_operands) +{ + uint32 op_code= ((uint32) op_not | (uint32 ) operation) + n_operands; + function_buffer.q_append(op_code); +} + + +int Gcalc_function::single_shape_op(shape_type shape_kind, gcalc_shape_info *si) +{ + if (reserve_shape_buffer(1) || reserve_op_buffer(1)) + return 1; + *si= add_new_shape(0, shape_kind); + add_operation(op_shape, *si); + return 0; +} + + +/* + Specify how many arguments we're going to have. +*/ + +int Gcalc_function::reserve_shape_buffer(uint n_shapes) +{ + return shapes_buffer.reserve(n_shapes * 4, 512); +} + + +/* + Specify how many operations we're going to have. +*/ + +int Gcalc_function::reserve_op_buffer(uint n_ops) +{ + return function_buffer.reserve(n_ops * 4, 512); +} + + +int Gcalc_function::alloc_states() +{ + if (function_buffer.reserve((n_shapes+1) * sizeof(int))) + return 1; + i_states= (int *) (function_buffer.ptr() + ALIGN_SIZE(function_buffer.length())); + return 0; +} + + +int Gcalc_function::count_internal() +{ + int c_op= uint4korr(cur_func); + op_type next_func= (op_type) (c_op & op_any); + int mask= (c_op & op_not) ? 1:0; + int n_ops= c_op & ~op_any; + int result; + + cur_func+= 4; + if (next_func == op_shape) + return i_states[c_op & ~(op_any | op_not)] ^ mask; + + result= count_internal(); + + while (--n_ops) + { + int next_res= count_internal(); + switch (next_func) + { + case op_union: + result= result | next_res; + break; + case op_intersection: + result= result & next_res; + break; + case op_symdifference: + result= result ^ next_res; + break; + case op_difference: + result= result & !next_res; + break; + case op_backdifference: + result= !result & next_res; + break; + default: + DBUG_ASSERT(FALSE); + }; + } + + return result ^ mask; +} + + +/* + Clear the state of the object. +*/ + +void Gcalc_function::reset() +{ + n_shapes= 0; + shapes_buffer.length(0); + function_buffer.length(0); +} + + +int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it) +{ + while (scan_it.more_points()) + { + if (scan_it.step()) + return -1; + Gcalc_scan_events ev= scan_it.get_event(); + const Gcalc_scan_iterator::point *evpos= scan_it.get_event_position(); + if (ev & (scev_point | scev_end | scev_two_ends)) + continue; + + clear_state(); + for (Gcalc_point_iterator pit(&scan_it); pit.point() != evpos; ++pit) + { + gcalc_shape_info si= pit.point()->get_shape(); + if ((get_shape_kind(si) == Gcalc_function::shape_polygon)) + invert_state(si); + } + invert_state(evpos->get_shape()); + + if (ev == scev_intersection) + { + const Gcalc_scan_iterator::point *evnext= evpos->c_get_next(); + if ((get_shape_kind(evpos->get_shape()) != + Gcalc_function::shape_polygon) || + (get_shape_kind(evnext->get_shape()) != + Gcalc_function::shape_polygon)) + invert_state(evnext->get_shape()); + } + + if (count()) + return 1; + } + return 0; +} + + +int Gcalc_operation_transporter::single_point(double x, double y) +{ + gcalc_shape_info si; + return m_fn->single_shape_op(Gcalc_function::shape_point, &si) || + int_single_point(si, x, y); +} + + +int Gcalc_operation_transporter::start_line() +{ + int_start_line(); + return m_fn->single_shape_op(Gcalc_function::shape_line, &m_si); +} + + +int Gcalc_operation_transporter::complete_line() +{ + int_complete_line(); + return 0; +} + + +int Gcalc_operation_transporter::start_poly() +{ + int_start_poly(); + return m_fn->single_shape_op(Gcalc_function::shape_polygon, &m_si); +} + + +int Gcalc_operation_transporter::complete_poly() +{ + int_complete_poly(); + return 0; +} + + +int Gcalc_operation_transporter::start_ring() +{ + int_start_ring(); + return 0; +} + + +int Gcalc_operation_transporter::complete_ring() +{ + int_complete_ring(); + return 0; +} + + +int Gcalc_operation_transporter::add_point(double x, double y) +{ + return int_add_point(m_si, x, y); +} + + +int Gcalc_operation_transporter::start_collection(int n_objects) +{ + if (m_fn->reserve_shape_buffer(n_objects) || m_fn->reserve_op_buffer(1)) + return 1; + m_fn->add_operation(Gcalc_function::op_union, n_objects); + return 0; +} + + +int Gcalc_result_receiver::start_shape(Gcalc_function::shape_type shape) +{ + if (buffer.reserve(4*2, 512)) + return 1; + cur_shape= shape; + shape_pos= buffer.length(); + buffer.length(shape_pos + ((shape == Gcalc_function::shape_point) ? 4:8)); + n_points= 0; + shape_area= 0.0; + + return 0; +} + + +int Gcalc_result_receiver::add_point(double x, double y) +{ + if (n_points && x == prev_x && y == prev_y) + return 0; + + if (!n_points++) + { + prev_x= first_x= x; + prev_y= first_y= y; + return 0; + } + + shape_area+= prev_x*y - prev_y*x; + + if (buffer.reserve(8*2, 512)) + return 1; + buffer.q_append(prev_x); + buffer.q_append(prev_y); + prev_x= x; + prev_y= y; + return 0; +} + + +int Gcalc_result_receiver::complete_shape() +{ + if (n_points == 0) + { + buffer.length(shape_pos); + return 0; + } + if (n_points == 1) + { + if (cur_shape != Gcalc_function::shape_point) + { + cur_shape= Gcalc_function::shape_point; + buffer.length(buffer.length()-4); + } + } + else + { + DBUG_ASSERT(cur_shape != Gcalc_function::shape_point); + if (cur_shape == Gcalc_function::shape_hole) + { + shape_area+= prev_x*first_y - prev_y*first_x; + if (fabs(shape_area) < 1e-8) + { + buffer.length(shape_pos); + return 0; + } + } + + if ((cur_shape == Gcalc_function::shape_polygon || + cur_shape == Gcalc_function::shape_hole) && + prev_x == first_x && prev_y == first_y) + { + n_points--; + buffer.write_at_position(shape_pos+4, n_points); + goto do_complete; + } + buffer.write_at_position(shape_pos+4, n_points); + } + + if (buffer.reserve(8*2, 512)) + return 1; + buffer.q_append(prev_x); + buffer.q_append(prev_y); + +do_complete: + buffer.write_at_position(shape_pos, (uint32) cur_shape); + + if (!n_shapes++) + { + DBUG_ASSERT(cur_shape != Gcalc_function::shape_hole); + common_shapetype= cur_shape; + } + else if (cur_shape == Gcalc_function::shape_hole) + { + ++n_holes; + } + else if (!collection_result && (cur_shape != common_shapetype)) + { + collection_result= true; + } + return 0; +} + + +int Gcalc_result_receiver::single_point(double x, double y) +{ + return start_shape(Gcalc_function::shape_point) || + add_point(x, y) || + complete_shape(); +} + + +int Gcalc_result_receiver::done() +{ + return 0; +} + + +void Gcalc_result_receiver::reset() +{ + buffer.length(0); + collection_result= FALSE; + n_shapes= n_holes= 0; +} + + +int Gcalc_result_receiver::get_result_typeid() +{ + if (!n_shapes) + return 0; + + if (collection_result) + return Geometry::wkb_geometrycollection; + switch (common_shapetype) + { + case Gcalc_function::shape_polygon: + return (n_shapes - n_holes == 1) ? + Geometry::wkb_polygon : Geometry::wkb_multipolygon; + case Gcalc_function::shape_point: + return (n_shapes == 1) ? Geometry::wkb_point : Geometry::wkb_multipoint; + case Gcalc_function::shape_line: + return (n_shapes == 1) ? Geometry::wkb_linestring : + Geometry::wkb_multilinestring; + default: + DBUG_ASSERT(0); + } + return 0; +} + + +int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_position, + uint32 *new_dest_position) +{ + char *ptr; + int source_len; + if (dest_position == source_position) + { + *new_dest_position= position(); + return 0; + } + + source_len= buffer.length() - source_position; + if (buffer.reserve(source_len, MY_ALIGN(source_len, 512))) + return 1; + + ptr= (char *) buffer.ptr(); + memmove(ptr + dest_position + source_len, ptr + dest_position, + buffer.length() - dest_position); + memcpy(ptr + dest_position, ptr + buffer.length(), source_len); + *new_dest_position= dest_position + source_len; + return 0; +} + + +Gcalc_operation_reducer::Gcalc_operation_reducer(size_t blk_size) : + Gcalc_dyn_list(blk_size, sizeof(res_point)), + m_res_hook((Gcalc_dyn_list::Item **)&m_result), + m_first_active_thread(NULL) +{} + + +void Gcalc_operation_reducer::init(Gcalc_function *fn, modes mode) +{ + m_fn= fn; + m_mode= mode; + m_first_active_thread= NULL; +} + + +Gcalc_operation_reducer:: +Gcalc_operation_reducer(Gcalc_function *fn, modes mode, size_t blk_size) : + Gcalc_dyn_list(blk_size, sizeof(res_point)), + m_res_hook((Gcalc_dyn_list::Item **)&m_result) +{ + init(fn, mode); +} + + +inline int Gcalc_operation_reducer::continue_range(active_thread *t, + const Gcalc_heap::Info *p) +{ + DBUG_ASSERT(t->result_range); + res_point *rp= add_res_point(); + if (!rp) + return 1; + rp->glue= NULL; + rp->down= t->rp; + t->rp->up= rp; + rp->intersection_point= false; + rp->pi= p; + t->rp= rp; + return 0; +} + + +inline int Gcalc_operation_reducer::continue_i_range(active_thread *t, + const Gcalc_heap::Info *p, + double x, double y) +{ + DBUG_ASSERT(t->result_range); + res_point *rp= add_res_point(); + if (!rp) + return 1; + rp->glue= NULL; + rp->down= t->rp; + t->rp->up= rp; + rp->intersection_point= true; + rp->x= x; + rp->pi= p; + rp->y= y; + t->rp= rp; + return 0; +} + +inline int Gcalc_operation_reducer::start_range(active_thread *t, + const Gcalc_heap::Info *p) +{ + res_point *rp= add_res_point(); + if (!rp) + return 1; + rp->glue= rp->down= NULL; + rp->intersection_point= false; + rp->pi= p; + t->result_range= 1; + t->rp= rp; + return 0; +} + +inline int Gcalc_operation_reducer::start_i_range(active_thread *t, + const Gcalc_heap::Info *p, + double x, double y) +{ + res_point *rp= add_res_point(); + if (!rp) + return 1; + rp->glue= rp->down= NULL; + rp->intersection_point= true; + rp->x= x; + rp->y= y; + rp->pi= p; + t->result_range= 1; + t->rp= rp; + return 0; +} + +inline int Gcalc_operation_reducer::end_range(active_thread *t, + const Gcalc_heap::Info *p) +{ + res_point *rp= add_res_point(); + if (!rp) + return 1; + rp->glue= rp->up= NULL; + rp->down= t->rp; + rp->intersection_point= false; + rp->pi= p; + t->rp->up= rp; + t->result_range= 0; + return 0; +} + +inline int Gcalc_operation_reducer::end_i_range(active_thread *t, + const Gcalc_heap::Info *p, + double x, double y) +{ + res_point *rp= add_res_point(); + if (!rp) + return 1; + rp->glue= rp->up= NULL; + rp->down= t->rp; + rp->intersection_point= true; + rp->x= x; + rp->pi= p; + rp->y= y; + t->rp->up= rp; + t->result_range= 0; + return 0; +} + +int Gcalc_operation_reducer::start_couple(active_thread *t0, active_thread *t1, + const Gcalc_heap::Info *p, + const active_thread *prev_range) +{ + res_point *rp0, *rp1; + if (!(rp0= add_res_point()) || !(rp1= add_res_point())) + return 1; + rp0->glue= rp1; + rp1->glue= rp0; + rp0->intersection_point= rp1->intersection_point= false; + rp0->down= rp1->down= NULL; + rp0->pi= rp1->pi= p; + t0->rp= rp0; + t1->rp= rp1; + if (prev_range) + { + rp0->outer_poly= prev_range->thread_start; + t1->thread_start= prev_range->thread_start; + } + else + { + rp0->outer_poly= 0; + t0->thread_start= rp0; + } + return 0; +} + +int Gcalc_operation_reducer::start_i_couple(active_thread *t0, active_thread *t1, + const Gcalc_heap::Info *p0, + const Gcalc_heap::Info *p1, + double x, double y, + const active_thread *prev_range) +{ + res_point *rp0, *rp1; + if (!(rp0= add_res_point()) || !(rp1= add_res_point())) + return 1; + rp0->glue= rp1; + rp1->glue= rp0; + rp0->pi= p0; + rp1->pi= p1; + rp0->intersection_point= rp1->intersection_point= true; + rp0->down= rp1->down= NULL; + rp0->x= rp1->x= x; + rp0->y= rp1->y= y; + t0->result_range= t1->result_range= 1; + t0->rp= rp0; + t1->rp= rp1; + if (prev_range) + { + rp0->outer_poly= prev_range->thread_start; + t1->thread_start= prev_range->thread_start; + } + else + { + rp0->outer_poly= 0; + t0->thread_start= rp0; + } + return 0; +} + +int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1, + const Gcalc_heap::Info *p) +{ + res_point *rp0, *rp1; + DBUG_ASSERT(t1->result_range); + if (!(rp0= add_res_point()) || !(rp1= add_res_point())) + return 1; + rp0->down= t0->rp; + rp1->down= t1->rp; + rp1->glue= rp0; + rp0->glue= rp1; + rp0->up= rp1->up= NULL; + t0->rp->up= rp0; + t1->rp->up= rp1; + rp0->intersection_point= rp1->intersection_point= false; + rp0->pi= rp1->pi= p; + t0->result_range= t1->result_range= 0; + return 0; +} + +int Gcalc_operation_reducer::end_i_couple(active_thread *t0, active_thread *t1, + const Gcalc_heap::Info *p0, + const Gcalc_heap::Info *p1, + double x, double y) +{ + res_point *rp0, *rp1; + if (!(rp0= add_res_point()) || !(rp1= add_res_point())) + return 1; + rp0->down= t0->rp; + rp1->down= t1->rp; + rp0->pi= p0; + rp1->pi= p1; + rp1->glue= rp0; + rp0->glue= rp1; + rp0->up= rp1->up= NULL; + rp0->intersection_point= rp1->intersection_point= true; + rp0->x= rp1->x= x; + rp0->y= rp1->y= y; + t0->result_range= t1->result_range= 0; + t0->rp->up= rp0; + t1->rp->up= rp1; + return 0; +} + +int Gcalc_operation_reducer::add_single_point(const Gcalc_heap::Info *p) +{ + res_point *rp= add_res_point(); + if (!rp) + return 1; + rp->glue= rp->up= rp->down= NULL; + rp->intersection_point= false; + rp->pi= p; + rp->x= p->x; + rp->y= p->y; + return 0; +} + +int Gcalc_operation_reducer::add_i_single_point(const Gcalc_heap::Info *p, + double x, double y) +{ + res_point *rp= add_res_point(); + if (!rp) + return 1; + rp->glue= rp->up= rp->down= NULL; + rp->intersection_point= true; + rp->x= x; + rp->pi= p; + rp->y= y; + return 0; +} + +int Gcalc_operation_reducer:: +handle_lines_intersection(active_thread *t0, active_thread *t1, + const Gcalc_heap::Info *p0, const Gcalc_heap::Info *p1, + double x, double y) +{ + m_fn->invert_state(p0->shape); + m_fn->invert_state(p1->shape); + int intersection_state= m_fn->count(); + if ((t0->result_range | t1->result_range) == intersection_state) + return 0; + + if (t0->result_range && + (end_i_range(t0, p1, x, y) || start_i_range(t0, p1, x, y))) + return 1; + + if (t1->result_range && + (end_i_range(t1, p0, x, y) || start_i_range(t1, p0, x, y))) + return 1; + + if (intersection_state && + add_i_single_point(p0, x, y)) + return 1; + + return 0; +} + +inline int Gcalc_operation_reducer:: +handle_line_polygon_intersection(active_thread *l, const Gcalc_heap::Info *pl, + int line_state, int poly_state, + double x, double y) +{ + int range_after= ~poly_state & line_state; + if (l->result_range == range_after) + return 0; + return range_after ? start_i_range(l, pl, x, y) : end_i_range(l, pl, x, y); +} + +static inline void switch_athreads(Gcalc_operation_reducer::active_thread *t0, + Gcalc_operation_reducer::active_thread *t1, + Gcalc_dyn_list::Item **hook) +{ + *hook= t1; + t0->next= t1->next; + t1->next= t0; +} + +inline int Gcalc_operation_reducer:: +handle_polygons_intersection(active_thread *t0, active_thread *t1, + Gcalc_dyn_list::Item **t_hook, + const Gcalc_heap::Info *p0, + const Gcalc_heap::Info *p1, + int prev_state, double x, double y, + const active_thread *prev_range) +{ + m_fn->invert_state(p0->shape); + int state_11= m_fn->count(); + m_fn->invert_state(p1->shape); + int state_2= m_fn->count(); + int state_01= prev_state ^ t0->result_range; + if ((prev_state == state_01) && (prev_state == state_2)) + { + if (state_11 == prev_state) + { + switch_athreads(t0, t1, t_hook); + return 0; + } + return start_i_couple(t0, t1, p0, p1, x, y, prev_range); + } + if (prev_state == state_2) + { + if (state_01 == state_11) + { + if (m_mode & polygon_selfintersections_allowed) + { + switch_athreads(t0, t1, t_hook); + return 0; + } + if (prev_state != (m_mode & prefer_big_with_holes)) + return continue_i_range(t0, p0, x, y) || continue_i_range(t1, p1, x, y); + return end_i_couple(t0, t1, p0, p1, x, y) || + start_i_couple(t0, t1, p0, p1, x, y, prev_range); + } + else + return end_i_couple(t0, t1, p0, p1, x, y); + } + if (state_01 ^ state_11) + { + switch_athreads(t0, t1, t_hook); + return 0; + } + + active_thread *thread_to_continue; + const Gcalc_heap::Info *way_to_go; + if (prev_state == state_01) + { + thread_to_continue= t1; + way_to_go= p1; + } + else + { + thread_to_continue= t0; + way_to_go= p0; + } + return continue_i_range(thread_to_continue, way_to_go, x, y); +} + +int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) +{ + Gcalc_point_iterator pi(si); + active_thread *cur_t= m_first_active_thread; + Gcalc_dyn_list::Item **at_hook= (Gcalc_dyn_list::Item **)&m_first_active_thread; + const active_thread *prev_range; + int prev_state; + + if (si->get_event() & (scev_point | scev_end | scev_two_ends)) + { + for (; pi.point() != si->get_event_position(); ++pi, cur_t= cur_t->get_next()) + at_hook= &cur_t->next; + + switch (si->get_event()) + { + case scev_point: + { + if (cur_t->result_range && + continue_range(cur_t, pi.get_pi())) + return 1; + break; + } + case scev_end: + { + if (cur_t->result_range && + end_range(cur_t, pi.get_pi())) + return 1; + *at_hook= cur_t->next; + free_item(cur_t); + break; + } + case scev_two_ends: + { + active_thread *cur_t1= cur_t->get_next(); + if (cur_t->result_range && + end_couple(cur_t, cur_t1, pi.get_pi())) + return 1; + + *at_hook= cur_t1->next; + free_list(cur_t, &cur_t1->next); + break; + } + default: + DBUG_ASSERT(0); + } + return 0; + } + + prev_state= 0; + prev_range= 0; + + m_fn->clear_state(); + for (; pi.point() != si->get_event_position(); ++pi, cur_t= cur_t->get_next()) + { + if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon) + { + m_fn->invert_state(pi.get_shape()); + prev_state^= cur_t->result_range; + } + at_hook= &cur_t->next; + if (cur_t->result_range) + prev_range= prev_state ? cur_t : 0; + } + + switch (si->get_event()) + { + case scev_thread: + { + active_thread *new_t= new_active_thread(); + if (!new_t) + return 1; + m_fn->invert_state(pi.get_shape()); + new_t->result_range= prev_state ^ m_fn->count(); + new_t->next= *at_hook; + *at_hook= new_t; + if (new_t->result_range && + start_range(new_t, pi.get_pi())) + return 1; + break; + } + case scev_two_threads: + { + active_thread *new_t0, *new_t1; + int fn_result; + if (!(new_t0= new_active_thread()) || !(new_t1= new_active_thread())) + return 1; + + m_fn->invert_state(pi.get_shape()); + fn_result= m_fn->count(); + new_t0->result_range= new_t1->result_range= prev_state ^ fn_result; + new_t1->next= *at_hook; + new_t0->next= new_t1; + *at_hook= new_t0; + if (new_t0->result_range && + start_couple(new_t0, new_t1, pi.get_pi(), prev_range)) + return 1; + break; + } + case scev_intersection: + { + active_thread *cur_t1= cur_t->get_next(); + const Gcalc_heap::Info *p0, *p1; + p0= pi.get_pi(); + ++pi; + p1= pi.get_pi(); + bool line0= m_fn->get_shape_kind(p0->shape) == Gcalc_function::shape_line; + bool line1= m_fn->get_shape_kind(p1->shape) == Gcalc_function::shape_line; + + if (!line0 && !line1) /* two polygons*/ + { + if (handle_polygons_intersection(cur_t, cur_t1, at_hook, p0, p1, + prev_state, pi.get_x(), si->get_y(), + prev_range)) + return 1; + } + else if (line0 && line1) + { + if (!prev_state && + handle_lines_intersection(cur_t, cur_t1, + p0, p1, pi.get_x(), si->get_y())) + return 1; + switch_athreads(cur_t, cur_t1, at_hook); + } + else + { + int poly_state; + int line_state; + const Gcalc_heap::Info *line; + active_thread *line_t; + m_fn->invert_state(p0->shape); + if (line0) + { + line_state= m_fn->count(); + poly_state= prev_state; + line= p0; + line_t= cur_t1; + } + else + { + poly_state= m_fn->count(); + m_fn->invert_state(p1->shape); + line_state= m_fn->count(); + line= p1; + line_t= cur_t; + } + if (handle_line_polygon_intersection(line_t, line, + line_state, poly_state, + pi.get_x(), si->get_y())) + return 1; + switch_athreads(cur_t, cur_t1, at_hook); + } + break; + } + case scev_single_point: + { + m_fn->invert_state(pi.get_shape()); + if ((prev_state ^ m_fn->count()) && + add_single_point(pi.get_pi())) + return 1; + break; + } + default: + DBUG_ASSERT(0); + } + + return 0; +} + +int Gcalc_operation_reducer::count_all(Gcalc_heap *hp) +{ + Gcalc_scan_iterator si; + si.init(hp); + while (si.more_points()) + { + if (si.step()) + return 1; + if (count_slice(&si)) + return 1; + } + return 0; +} + +inline void Gcalc_operation_reducer::free_result(res_point *res) +{ + if ((*res->prev_hook= res->next)) + { + res->get_next()->prev_hook= res->prev_hook; + } + free_item(res); +} + + +inline int Gcalc_operation_reducer::get_single_result(res_point *res, + Gcalc_result_receiver *storage) +{ + if (res->intersection_point) + { + if (storage->single_point(float_to_coord(res->x), + float_to_coord(res->y))) + return 1; + } + else + if (storage->single_point(res->x, res->y)) + return 1; + free_result(res); + return 0; +} + + +int Gcalc_operation_reducer::get_result_thread(res_point *cur, + Gcalc_result_receiver *storage, + int move_upward) +{ + res_point *next; + bool glue_step= false; + res_point *first_poly_node= cur; + double x, y; + while (cur) + { + if (!glue_step) + { + if (cur->intersection_point) + { + x= float_to_coord(cur->x); + y= float_to_coord(cur->y); + } + else + { + x= cur->pi->x; + y= cur->pi->y; + } + if (storage->add_point(x, y)) + return 1; + } + + next= move_upward ? cur->up : cur->down; + if (!next && !glue_step) + { + next= cur->glue; + move_upward^= 1; + glue_step= true; + if (next) + next->glue= NULL; + } + else + glue_step= false; + + cur->first_poly_node= first_poly_node; + free_result(cur); + cur= next; + } + return 0; +} + + +int Gcalc_operation_reducer::get_polygon_result(res_point *cur, + Gcalc_result_receiver *storage) +{ + res_point *glue= cur->glue; + glue->up->down= NULL; + free_result(glue); + return get_result_thread(cur, storage, 1) || + storage->complete_shape(); +} + + +int Gcalc_operation_reducer::get_line_result(res_point *cur, + Gcalc_result_receiver *storage) +{ + res_point *next; + int move_upward= 1; + if (cur->glue) + { + /* Here we have to find the beginning of the line */ + next= cur->up; + move_upward= 1; + while (next) + { + cur= next; + next= move_upward ? next->up : next->down; + if (!next) + { + next= cur->glue; + move_upward^= 1; + } + } + } + + return get_result_thread(cur, storage, move_upward) || + storage->complete_shape(); +} + + +int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) +{ + *m_res_hook= NULL; + while (m_result) + { + if (!m_result->up) + { + if (get_single_result(m_result, storage)) + return 1; + continue; + } + Gcalc_function::shape_type shape= m_fn->get_shape_kind(m_result->pi->shape); + if (shape == Gcalc_function::shape_polygon) + { + if (m_result->outer_poly) + { + uint32 *insert_position, hole_position; + insert_position= &m_result->outer_poly->first_poly_node->poly_position; + DBUG_ASSERT(*insert_position); + hole_position= storage->position(); + storage->start_shape(Gcalc_function::shape_hole); + if (get_polygon_result(m_result, storage) || + storage->move_hole(*insert_position, hole_position, + insert_position)) + return 1; + } + else + { + uint32 *poly_position= &m_result->poly_position; + storage->start_shape(Gcalc_function::shape_polygon); + if (get_polygon_result(m_result, storage)) + return 1; + *poly_position= storage->position(); + } + } + else + { + storage->start_shape(shape); + if (get_line_result(m_result, storage)) + return 1; + } + } + + m_res_hook= (Gcalc_dyn_list::Item **)&m_result; + storage->done(); + return 0; +} + + +void Gcalc_operation_reducer::reset() +{ + free_list(m_result, m_res_hook); + m_res_hook= (Gcalc_dyn_list::Item **)&m_result; + free_list(m_first_active_thread); +} + +#endif /*HAVE_SPATIAL*/ + diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h new file mode 100644 index 00000000000..7df236618fb --- /dev/null +++ b/sql/gcalc_tools.h @@ -0,0 +1,306 @@ +/* Copyright (c) 2000, 2010 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef GCALC_TOOLS_INCLUDED +#define GCALC_TOOLS_INCLUDED + +#include "gcalc_slicescan.h" + + +/* + The Gcalc_function class objects are used to check for a binary relation. + The relation can be constructed with the prefix notation using predicates as + op_not (as !A) + op_union ( A || B || C... ) + op_intersection ( A && B && C ... ) + op_symdifference ( A+B+C+... == 1 ) + op_difference ( A && !(B||C||..)) + with the calls of the add_operation(operation, n_operands) method. + The relation is calculated over a set of shapes, that in turn have + to be added with the add_new_shape() method. All the 'shapes' can + be set to 0 with clear_shapes() method and single value + can be changed with the invert_state() method. + Then the value of the relation can be calculated with the count() method. + Frequently used method is find_function(Gcalc_scan_iterator it) that + iterates through the 'it' until the relation becomes TRUE. +*/ + +class Gcalc_function +{ +private: + String shapes_buffer; + String function_buffer; + const char *cur_func; + int *i_states; + uint32 cur_object_id; + uint n_shapes; + int count_internal(); +public: + enum op_type + { + op_shape= 0, + op_not= 0x80000000, + op_union= 0x10000000, + op_intersection= 0x20000000, + op_symdifference= 0x30000000, + op_difference= 0x40000000, + op_backdifference= 0x50000000, + op_any= 0x70000000 + }; + enum shape_type + { + shape_point= 0, + shape_line= 1, + shape_polygon= 2, + shape_hole= 3 + }; + Gcalc_function() : n_shapes(0) {} + gcalc_shape_info add_new_shape(uint32 shape_id, shape_type shape_kind); + /* + Adds the leaf operation that returns the shape value. + Also adds the shape to the list of operands. + */ + int single_shape_op(shape_type shape_kind, gcalc_shape_info *si); + void add_operation(op_type operation, uint32 n_operands); + void add_not_operation(op_type operation, uint32 n_operands); + uint32 get_next_operation_pos() { return function_buffer.length(); } + void add_operands_to_op(uint32 operation_pos, uint32 n_operands); + void set_cur_obj(uint32 cur_obj) { cur_object_id= cur_obj; } + int reserve_shape_buffer(uint n_shapes); + int reserve_op_buffer(uint n_ops); + uint get_nshapes() const { return n_shapes; } + shape_type get_shape_kind(gcalc_shape_info si) const + { + return (shape_type) uint4korr(shapes_buffer.ptr() + (si*4)); + } + + void set_states(int *shape_states) { i_states= shape_states; } + int alloc_states(); + void invert_state(gcalc_shape_info shape) { i_states[shape]^= 1; } + int get_state(gcalc_shape_info shape) { return i_states[shape]; } + int count() + { + cur_func= function_buffer.ptr(); + return count_internal(); + } + void clear_state() { bzero(i_states, n_shapes * sizeof(int)); } + void reset(); + + int find_function(Gcalc_scan_iterator &scan_it); +}; + + +/* + Gcalc_operation_transporter class extends the Gcalc_shape_transporter. + In addition to the parent's functionality, it fills the Gcalc_function + object so it has the function that determines the proper shape. + For example Multipolyline will be represented as an union of polylines. +*/ + +class Gcalc_operation_transporter : public Gcalc_shape_transporter +{ +protected: + Gcalc_function *m_fn; + gcalc_shape_info m_si; +public: + Gcalc_operation_transporter(Gcalc_function *fn, Gcalc_heap *heap) : + Gcalc_shape_transporter(heap), m_fn(fn) {} + + int single_point(double x, double y); + int start_line(); + int complete_line(); + int start_poly(); + int complete_poly(); + int start_ring(); + int complete_ring(); + int add_point(double x, double y); + int start_collection(int n_objects); +}; + + +/* + When we calculate the result of an spatial operation like + Union or Intersection, we receive vertexes of the result + one-by-one, and probably need to treat them in variative ways. + So, the Gcalc_result_receiver class designed to get these + vertexes and construct shapes/objects out of them. + and to store the result in an appropriate format +*/ + +class Gcalc_result_receiver +{ + String buffer; + uint32 n_points; + Gcalc_function::shape_type common_shapetype; + bool collection_result; + uint32 n_shapes; + uint32 n_holes; + + Gcalc_function::shape_type cur_shape; + uint32 shape_pos; + double first_x, first_y, prev_x, prev_y; + double shape_area; +public: + Gcalc_result_receiver() : collection_result(FALSE), n_shapes(0), n_holes(0) + {} + int start_shape(Gcalc_function::shape_type shape); + int add_point(double x, double y); + int complete_shape(); + int single_point(double x, double y); + int done(); + void reset(); + + const char *result() { return buffer.ptr(); } + uint length() { return buffer.length(); } + int get_nshapes() { return n_shapes; } + int get_nholes() { return n_holes; } + int get_result_typeid(); + uint32 position() { return buffer.length(); } + int move_hole(uint32 dest_position, uint32 source_position, + uint32 *new_dest_position); +}; + + +/* + Gcalc_operation_reducer class incapsulates the spatial + operation functionality. It analyses the slices generated by + the slicescan and calculates the shape of the result defined + by some Gcalc_function. +*/ + +class Gcalc_operation_reducer : public Gcalc_dyn_list +{ +public: + enum modes + { + /* Numeric values important here - careful with changing */ + default_mode= 0, + prefer_big_with_holes= 1, + polygon_selfintersections_allowed= 2, /* allowed in the result */ + line_selfintersections_allowed= 4 /* allowed in the result */ + }; + + Gcalc_operation_reducer(size_t blk_size=8192); + void init(Gcalc_function *fn, modes mode= default_mode); + Gcalc_operation_reducer(Gcalc_function *fn, modes mode= default_mode, + size_t blk_size=8192); + int count_slice(Gcalc_scan_iterator *si); + int count_all(Gcalc_heap *hp); + int get_result(Gcalc_result_receiver *storage); + void reset(); + + class res_point : public Gcalc_dyn_list::Item + { + public: + bool intersection_point; + double x,y; + res_point *up; + res_point *down; + res_point *glue; + union + { + const Gcalc_heap::Info *pi; + res_point *first_poly_node; + }; + union + { + res_point *outer_poly; + uint32 poly_position; + }; + Gcalc_dyn_list::Item **prev_hook; + res_point *get_next() { return (res_point *)next; } + }; + + class active_thread : public Gcalc_dyn_list::Item + { + public: + res_point *rp; + int result_range; + res_point *thread_start; + active_thread *get_next() { return (active_thread *)next; } + }; + +protected: + Gcalc_function *m_fn; + Gcalc_dyn_list::Item **m_res_hook; + res_point *m_result; + int m_mode; + + res_point *result_heap; + active_thread *m_first_active_thread; + + res_point *add_res_point() + { + res_point *result= (res_point *)new_item(); + *m_res_hook= result; + result->prev_hook= m_res_hook; + m_res_hook= &result->next; + return result; + } + + active_thread *new_active_thread() { return (active_thread *)new_item(); } + +private: + int continue_range(active_thread *t, const Gcalc_heap::Info *p); + int continue_i_range(active_thread *t, const Gcalc_heap::Info *p, + double x, double y); + int start_range(active_thread *t, const Gcalc_heap::Info *p); + int start_i_range(active_thread *t, const Gcalc_heap::Info *p, + double x, double y); + int end_range(active_thread *t, const Gcalc_heap::Info *p); + int end_i_range(active_thread *t, const Gcalc_heap::Info *p, + double x, double y); + int start_couple(active_thread *t0, active_thread *t1,const Gcalc_heap::Info *p, + const active_thread *prev_range); + int start_i_couple(active_thread *t0, active_thread *t1, + const Gcalc_heap::Info *p0, + const Gcalc_heap::Info *p1, + double x, double y, + const active_thread *prev_range); + int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p); + int end_i_couple(active_thread *t0, active_thread *t1, + const Gcalc_heap::Info *p0, + const Gcalc_heap::Info *p1, + double x, double y); + int add_single_point(const Gcalc_heap::Info *p); + int add_i_single_point(const Gcalc_heap::Info *p, double x, double y); + + int handle_lines_intersection(active_thread *t0, active_thread *t1, + const Gcalc_heap::Info *p0, + const Gcalc_heap::Info *p1, + double x, double y); + int handle_polygons_intersection(active_thread *t0, active_thread *t1, + Gcalc_dyn_list::Item **t_hook, + const Gcalc_heap::Info *p0, + const Gcalc_heap::Info *p1, + int prev_state, double x, double y, + const active_thread *prev_range); + int handle_line_polygon_intersection(active_thread *l, + const Gcalc_heap::Info *pl, + int line_state, int poly_state, + double x, double y); + + int get_single_result(res_point *res, Gcalc_result_receiver *storage); + int get_result_thread(res_point *cur, Gcalc_result_receiver *storage, + int move_upward); + int get_polygon_result(res_point *cur, Gcalc_result_receiver *storage); + int get_line_result(res_point *cur, Gcalc_result_receiver *storage); + + void free_result(res_point *res); +}; + +#endif /*GCALC_TOOLS_INCLUDED*/ + diff --git a/sql/item_create.cc b/sql/item_create.cc index b3a0e7cf3b2..8ff38bc4bc0 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -509,6 +509,19 @@ protected: #ifdef HAVE_SPATIAL +class Create_func_mbr_contains : public Create_func_arg2 +{ + public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_mbr_contains s_singleton; + + protected: + Create_func_mbr_contains() {} + virtual ~Create_func_mbr_contains() {} +}; + + class Create_func_contains : public Create_func_arg2 { public: @@ -749,6 +762,19 @@ protected: #ifdef HAVE_SPATIAL +class Create_func_mbr_disjoint : public Create_func_arg2 +{ + public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_mbr_disjoint s_singleton; + + protected: + Create_func_mbr_disjoint() {} + virtual ~Create_func_mbr_disjoint() {} +}; + + class Create_func_disjoint : public Create_func_arg2 { public: @@ -760,6 +786,19 @@ protected: Create_func_disjoint() {} virtual ~Create_func_disjoint() {} }; + + +class Create_func_distance : public Create_func_arg2 +{ + public: + virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_distance s_singleton; + + protected: + Create_func_distance() {} + virtual ~Create_func_distance() {} +}; #endif @@ -833,6 +872,19 @@ protected: #ifdef HAVE_SPATIAL +class Create_func_mbr_equals : public Create_func_arg2 +{ + public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_mbr_equals s_singleton; + + protected: + Create_func_mbr_equals() {} + virtual ~Create_func_mbr_equals() {} +}; + + class Create_func_equals : public Create_func_arg2 { public: @@ -1161,6 +1213,19 @@ protected: #ifdef HAVE_SPATIAL +class Create_func_mbr_intersects : public Create_func_arg2 +{ + public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_mbr_intersects s_singleton; + + protected: + Create_func_mbr_intersects() {} + virtual ~Create_func_mbr_intersects() {} +}; + + class Create_func_intersects : public Create_func_arg2 { public: @@ -1172,7 +1237,72 @@ protected: Create_func_intersects() {} virtual ~Create_func_intersects() {} }; -#endif + + +class Create_func_intersection : public Create_func_arg2 +{ +public: + virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_intersection s_singleton; + +protected: + Create_func_intersection() {} + virtual ~Create_func_intersection() {} +}; + + +class Create_func_difference : public Create_func_arg2 +{ +public: + virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_difference s_singleton; + +protected: + Create_func_difference() {} + virtual ~Create_func_difference() {} +}; + + +class Create_func_union : public Create_func_arg2 +{ +public: + virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_union s_singleton; + +protected: + Create_func_union() {} + virtual ~Create_func_union() {} +}; + + +class Create_func_symdifference : public Create_func_arg2 +{ +public: + virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_symdifference s_singleton; + +protected: + Create_func_symdifference() {} + virtual ~Create_func_symdifference() {} +}; + + +class Create_func_buffer : public Create_func_arg2 +{ +public: + virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_buffer s_singleton; + +protected: + Create_func_buffer() {} + virtual ~Create_func_buffer() {} +}; +#endif /*HAVE_SPATIAL*/ class Create_func_is_free_lock : public Create_func_arg1 @@ -1604,6 +1734,19 @@ protected: #ifdef HAVE_SPATIAL +class Create_func_mbr_overlaps : public Create_func_arg2 +{ + public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_mbr_overlaps s_singleton; + + protected: + Create_func_mbr_overlaps() {} + virtual ~Create_func_mbr_overlaps() {} +}; + + class Create_func_overlaps : public Create_func_arg2 { public: @@ -2199,6 +2342,19 @@ protected: #ifdef HAVE_SPATIAL +class Create_func_mbr_within : public Create_func_arg2 +{ + public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_mbr_within s_singleton; + + protected: + Create_func_mbr_within() {} + virtual ~Create_func_mbr_within() {} +}; + + class Create_func_within : public Create_func_arg2 { public: @@ -2890,6 +3046,16 @@ Create_func_connection_id::create_builder(THD *thd) #ifdef HAVE_SPATIAL +Create_func_mbr_contains Create_func_mbr_contains::s_singleton; + +Item* +Create_func_mbr_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2, + Item_func::SP_CONTAINS_FUNC); +} + + Create_func_contains Create_func_contains::s_singleton; Item* @@ -3122,6 +3288,16 @@ Create_func_dimension::create_1_arg(THD *thd, Item *arg1) #ifdef HAVE_SPATIAL +Create_func_mbr_disjoint Create_func_mbr_disjoint::s_singleton; + +Item* +Create_func_mbr_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2, + Item_func::SP_DISJOINT_FUNC); +} + + Create_func_disjoint Create_func_disjoint::s_singleton; Item* @@ -3130,6 +3306,15 @@ Create_func_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2) return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2, Item_func::SP_DISJOINT_FUNC); } + + +Create_func_distance Create_func_distance::s_singleton; + +Item* +Create_func_distance::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_distance(arg1, arg2); +} #endif @@ -3225,6 +3410,16 @@ Create_func_envelope::create_1_arg(THD *thd, Item *arg1) #ifdef HAVE_SPATIAL +Create_func_mbr_equals Create_func_mbr_equals::s_singleton; + +Item* +Create_func_mbr_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2, + Item_func::SP_EQUALS_FUNC); +} + + Create_func_equals Create_func_equals::s_singleton; Item* @@ -3620,6 +3815,16 @@ Create_func_interiorringn::create_2_arg(THD *thd, Item *arg1, Item *arg2) #ifdef HAVE_SPATIAL +Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton; + +Item* +Create_func_mbr_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2, + Item_func::SP_INTERSECTS_FUNC); +} + + Create_func_intersects Create_func_intersects::s_singleton; Item* @@ -3628,7 +3833,56 @@ Create_func_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2) return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2, Item_func::SP_INTERSECTS_FUNC); } -#endif + + +Create_func_intersection Create_func_intersection::s_singleton; + +Item* +Create_func_intersection::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_operation(arg1, arg2, + Gcalc_function::op_intersection); +} + + +Create_func_difference Create_func_difference::s_singleton; + +Item* +Create_func_difference::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_operation(arg1, arg2, + Gcalc_function::op_difference); +} + + +Create_func_union Create_func_union::s_singleton; + +Item* +Create_func_union::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_operation(arg1, arg2, + Gcalc_function::op_union); +} + + +Create_func_symdifference Create_func_symdifference::s_singleton; + +Item* +Create_func_symdifference::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_operation(arg1, arg2, + Gcalc_function::op_symdifference); +} + + +Create_func_buffer Create_func_buffer::s_singleton; + +Item* +Create_func_buffer::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_buffer(arg1, arg2); +} +#endif /*HAVE_SPATAI*/ Create_func_is_free_lock Create_func_is_free_lock::s_singleton; @@ -4088,6 +4342,16 @@ Create_func_ord::create_1_arg(THD *thd, Item *arg1) #ifdef HAVE_SPATIAL +Create_func_mbr_overlaps Create_func_mbr_overlaps::s_singleton; + +Item* +Create_func_mbr_overlaps::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2, + Item_func::SP_OVERLAPS_FUNC); +} + + Create_func_overlaps Create_func_overlaps::s_singleton; Item* @@ -4640,6 +4904,16 @@ Create_func_weekofyear::create_1_arg(THD *thd, Item *arg1) #ifdef HAVE_SPATIAL +Create_func_mbr_within Create_func_mbr_within::s_singleton; + +Item* +Create_func_mbr_within::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2, + Item_func::SP_WITHIN_FUNC); +} + + Create_func_within Create_func_within::s_singleton; Item* @@ -4773,6 +5047,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("BIN") }, BUILDER(Create_func_bin)}, { { C_STRING_WITH_LEN("BIT_COUNT") }, BUILDER(Create_func_bit_count)}, { { C_STRING_WITH_LEN("BIT_LENGTH") }, BUILDER(Create_func_bit_length)}, + { { C_STRING_WITH_LEN("BUFFER") }, GEOM_BUILDER(Create_func_buffer)}, { { C_STRING_WITH_LEN("CEIL") }, BUILDER(Create_func_ceiling)}, { { C_STRING_WITH_LEN("CEILING") }, BUILDER(Create_func_ceiling)}, { { C_STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)}, @@ -4800,13 +5075,13 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("DES_DECRYPT") }, BUILDER(Create_func_des_decrypt)}, { { C_STRING_WITH_LEN("DES_ENCRYPT") }, BUILDER(Create_func_des_encrypt)}, { { C_STRING_WITH_LEN("DIMENSION") }, GEOM_BUILDER(Create_func_dimension)}, - { { C_STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)}, + { { C_STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)}, { { C_STRING_WITH_LEN("ELT") }, BUILDER(Create_func_elt)}, { { C_STRING_WITH_LEN("ENCODE") }, BUILDER(Create_func_encode)}, { { C_STRING_WITH_LEN("ENCRYPT") }, BUILDER(Create_func_encrypt)}, { { C_STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)}, { { C_STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)}, - { { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)}, + { { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)}, { { C_STRING_WITH_LEN("EXP") }, BUILDER(Create_func_exp)}, { { C_STRING_WITH_LEN("EXPORT_SET") }, BUILDER(Create_func_export_set)}, { { C_STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)}, @@ -4837,7 +5112,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("INET_NTOA") }, BUILDER(Create_func_inet_ntoa)}, { { C_STRING_WITH_LEN("INSTR") }, BUILDER(Create_func_instr)}, { { C_STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)}, - { { C_STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)}, + { { C_STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)}, { { C_STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)}, { { C_STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)}, { { C_STRING_WITH_LEN("ISNULL") }, BUILDER(Create_func_isnull)}, @@ -4866,13 +5141,13 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("MAKETIME") }, BUILDER(Create_func_maketime)}, { { C_STRING_WITH_LEN("MAKE_SET") }, BUILDER(Create_func_make_set)}, { { C_STRING_WITH_LEN("MASTER_POS_WAIT") }, BUILDER(Create_func_master_pos_wait)}, - { { C_STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_contains)}, - { { C_STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_disjoint)}, - { { C_STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_equals)}, - { { C_STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_intersects)}, - { { C_STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)}, + { { C_STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_mbr_contains)}, + { { C_STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)}, + { { C_STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_mbr_equals)}, + { { C_STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)}, + { { C_STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)}, { { C_STRING_WITH_LEN("MBRTOUCHES") }, GEOM_BUILDER(Create_func_touches)}, - { { C_STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_within)}, + { { C_STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_mbr_within)}, { { C_STRING_WITH_LEN("MD5") }, BUILDER(Create_func_md5)}, { { C_STRING_WITH_LEN("MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { C_STRING_WITH_LEN("MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, @@ -4895,7 +5170,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("OCT") }, BUILDER(Create_func_oct)}, { { C_STRING_WITH_LEN("OCTET_LENGTH") }, BUILDER(Create_func_length)}, { { C_STRING_WITH_LEN("ORD") }, BUILDER(Create_func_ord)}, - { { C_STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)}, + { { C_STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)}, { { C_STRING_WITH_LEN("PERIOD_ADD") }, BUILDER(Create_func_period_add)}, { { C_STRING_WITH_LEN("PERIOD_DIFF") }, BUILDER(Create_func_period_diff)}, { { C_STRING_WITH_LEN("PI") }, BUILDER(Create_func_pi)}, @@ -4930,6 +5205,64 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)}, { { C_STRING_WITH_LEN("STRCMP") }, BUILDER(Create_func_strcmp)}, { { C_STRING_WITH_LEN("STR_TO_DATE") }, BUILDER(Create_func_str_to_date)}, + { { C_STRING_WITH_LEN("ST_AREA") }, GEOM_BUILDER(Create_func_area)}, + { { C_STRING_WITH_LEN("ST_ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)}, + { { C_STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)}, + { { C_STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)}, + { { C_STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)}, + { { C_STRING_WITH_LEN("ST_BUFFER") }, GEOM_BUILDER(Create_func_buffer)}, + { { C_STRING_WITH_LEN("ST_CENTROID") }, GEOM_BUILDER(Create_func_centroid)}, + { { C_STRING_WITH_LEN("ST_CONTAINS") }, GEOM_BUILDER(Create_func_contains)}, + { { C_STRING_WITH_LEN("ST_CROSSES") }, GEOM_BUILDER(Create_func_crosses)}, + { { C_STRING_WITH_LEN("ST_DIFFERENCE") }, GEOM_BUILDER(Create_func_difference)}, + { { C_STRING_WITH_LEN("ST_DIMENSION") }, GEOM_BUILDER(Create_func_dimension)}, + { { C_STRING_WITH_LEN("ST_DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)}, + { { C_STRING_WITH_LEN("ST_DISTANCE") }, GEOM_BUILDER(Create_func_distance)}, + { { C_STRING_WITH_LEN("ST_ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)}, + { { C_STRING_WITH_LEN("ST_ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)}, + { { C_STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)}, + { { C_STRING_WITH_LEN("ST_EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)}, + { { C_STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)}, + { { C_STRING_WITH_LEN("ST_GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)}, + { { C_STRING_WITH_LEN("ST_GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)}, + { { C_STRING_WITH_LEN("ST_INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)}, + { { C_STRING_WITH_LEN("ST_INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)}, + { { C_STRING_WITH_LEN("ST_INTERSECTION") }, GEOM_BUILDER(Create_func_intersection)}, + { { C_STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)}, + { { C_STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)}, + { { C_STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)}, + { { C_STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)}, + { { C_STRING_WITH_LEN("ST_LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)}, + { { C_STRING_WITH_LEN("ST_NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)}, + { { C_STRING_WITH_LEN("ST_NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)}, + { { C_STRING_WITH_LEN("ST_OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)}, + { { C_STRING_WITH_LEN("ST_POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_POINTN") }, GEOM_BUILDER(Create_func_pointn)}, + { { C_STRING_WITH_LEN("ST_POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, + { { C_STRING_WITH_LEN("ST_POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_SRID") }, GEOM_BUILDER(Create_func_srid)}, + { { C_STRING_WITH_LEN("ST_STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)}, + { { C_STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)}, + { { C_STRING_WITH_LEN("ST_TOUCHES") }, GEOM_BUILDER(Create_func_touches)}, + { { C_STRING_WITH_LEN("ST_UNION") }, GEOM_BUILDER(Create_func_union)}, + { { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_mbr_within)}, + { { C_STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)}, + { { C_STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)}, { { C_STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)}, { { C_STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)}, { { C_STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)}, diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 8c38cb2a859..9432de95182 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2003-2006 MySQL AB +/* Copyright (c) 2003, 2010, 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 @@ -10,8 +10,8 @@ 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ /** @@ -26,9 +26,15 @@ #endif #include "mysql_priv.h" +/* + It is necessary to include set_var.h instead of item.h because there + are dependencies on include order for set_var.h and item.h. This + will be resolved later. +*/ #ifdef HAVE_SPATIAL #include + Field *Item_geometry_func::tmp_table_field(TABLE *t_arg) { Field *result; @@ -42,7 +48,7 @@ void Item_geometry_func::fix_length_and_dec() { collation.set(&my_charset_bin); decimals=0; - max_length= max_field_size; + max_length= (uint32) 4294967295U; maybe_null= 1; } @@ -134,6 +140,7 @@ String *Item_func_as_wkt::val_str(String *str) void Item_func_as_wkt::fix_length_and_dec() { + collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); max_length=MAX_BLOB_WIDTH; maybe_null= 1; } @@ -360,8 +367,8 @@ String *Item_func_point::val_str(String *str) uint32 srid= 0; if ((null_value= (args[0]->null_value || - args[1]->null_value || - str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE*2)))) + args[1]->null_value || + str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2)))) return 0; str->set_charset(&my_charset_bin); @@ -508,7 +515,33 @@ err: Functions for spatial relations */ -longlong Item_func_spatial_rel::val_int() +const char *Item_func_spatial_mbr_rel::func_name() const +{ + switch (spatial_rel) { + case SP_CONTAINS_FUNC: + return "mbrcontains"; + case SP_WITHIN_FUNC: + return "mbrwithin"; + case SP_EQUALS_FUNC: + return "mbrequals"; + case SP_DISJOINT_FUNC: + return "mbrdisjoint"; + case SP_INTERSECTS_FUNC: + return "mbrintersects"; + case SP_TOUCHES_FUNC: + return "mbrtouches"; + case SP_CROSSES_FUNC: + return "mbrcrosses"; + case SP_OVERLAPS_FUNC: + return "mbroverlaps"; + default: + DBUG_ASSERT(0); // Should never happened + return "mbrsp_unknown"; + } +} + + +longlong Item_func_spatial_mbr_rel::val_int() { DBUG_ASSERT(fixed == 1); String *res1= args[0]->val_str(&cmp.value1); @@ -553,6 +586,867 @@ longlong Item_func_spatial_rel::val_int() } +Item_func_spatial_rel::Item_func_spatial_rel(Item *a,Item *b, + enum Functype sp_rel) : + Item_bool_func2(a,b), collector() +{ + spatial_rel = sp_rel; +} + + +Item_func_spatial_rel::~Item_func_spatial_rel() +{ +} + + +const char *Item_func_spatial_rel::func_name() const +{ + switch (spatial_rel) { + case SP_CONTAINS_FUNC: + return "st_contains"; + case SP_WITHIN_FUNC: + return "st_within"; + case SP_EQUALS_FUNC: + return "st_equals"; + case SP_DISJOINT_FUNC: + return "st_disjoint"; + case SP_INTERSECTS_FUNC: + return "st_intersects"; + case SP_TOUCHES_FUNC: + return "st_touches"; + case SP_CROSSES_FUNC: + return "st_crosses"; + case SP_OVERLAPS_FUNC: + return "st_overlaps"; + default: + DBUG_ASSERT(0); // Should never happened + return "sp_unknown"; + } +} + + +static double count_edge_t(const Gcalc_heap::Info *ea, + const Gcalc_heap::Info *eb, + const Gcalc_heap::Info *v, + double &ex, double &ey, double &vx, double &vy, + double &e_sqrlen) +{ + ex= eb->x - ea->x; + ey= eb->y - ea->y; + vx= v->x - ea->x; + vy= v->y - ea->y; + e_sqrlen= ex * ex + ey * ey; + return (ex * vx + ey * vy) / e_sqrlen; +} + + +static double distance_to_line(double ex, double ey, double vx, double vy, + double e_sqrlen) +{ + return fabs(vx * ey - vy * ex) / sqrt(e_sqrlen); +} + + +static double distance_points(const Gcalc_heap::Info *a, + const Gcalc_heap::Info *b) +{ + double x= a->x - b->x; + double y= a->y - b->y; + return sqrt(x * x + y * y); +} + + +/* + Calculates the distance between objects. +*/ + +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, *dist_point; + Gcalc_scan_events ev; + double t, distance, cur_distance; + double ex, ey, vx, vy, e_sqrlen; + + 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_event(); + cur_point= evpos->pi; + + /* + handling intersection we only need to check if it's the intersecion + of objects 1 and 2. In this case distance is 0 + */ + if (ev == scev_intersection) + { + if ((evpos->get_next()->pi->shape >= obj2_si) != + (cur_point->shape >= obj2_si)) + { + distance= 0; + goto exit; + } + continue; + } + + /* + if we get 'scev_point | scev_end | scev_two_ends' we don't need + to check for intersection of objects. + Though we need to calculate distances. + */ + if (ev & (scev_point | scev_end | scev_two_ends)) + goto calculate_distance; + + 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; + } + + +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); +} + + +#define GIS_ZERO 0.00000000001 + +int Item_func_spatial_rel::func_touches() +{ + bool above_cur_point; + double x1, x2, y1, y2, ex, ey; + double distance, area; + int result= 0; + int cur_func= 0; + + Gcalc_operation_transporter trn(&func, &collector); + + String *res1= args[0]->val_str(&tmp_value1); + String *res2= args[1]->val_str(&tmp_value2); + Geometry_buffer buffer1, buffer2; + Geometry *g1, *g2; + int obj2_si; + + DBUG_ENTER("Item_func_spatial_rel::func_touches"); + DBUG_ASSERT(fixed == 1); + + 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()))))) + goto mem_error; + + if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) && + (g2->get_class_info()->m_type_id == Geometry::wkb_point)) + { + if (((Gis_point *) g1)->get_xy(&x1, &y1) || + ((Gis_point *) g2)->get_xy(&x2, &y2)) + goto mem_error; + ex= x2 - x1; + ey= y2 - y1; + DBUG_RETURN((ex * ex + ey * ey) < GIS_ZERO); + } + + if (func.reserve_op_buffer(1)) + goto mem_error; + func.add_operation(Gcalc_function::op_intersection, 2); + + if (g1->store_shapes(&trn)) + goto mem_error; + obj2_si= func.get_nshapes(); + + if (g2->store_shapes(&trn) || func.alloc_states()) + goto mem_error; + + collector.prepare_operation(); + scan_it.init(&collector); + + if (calc_distance(&distance, &collector, obj2_si, &func, &scan_it)) + goto mem_error; + if (distance > GIS_ZERO) + goto exit; + + scan_it.reset(); + scan_it.init(&collector); + + above_cur_point= false; + distance= DBL_MAX; + + while (scan_it.more_trapezoids()) + { + if (scan_it.step()) + goto mem_error; + + func.clear_state(); + for (Gcalc_trapezoid_iterator ti(&scan_it); ti.more(); ++ti) + { + gcalc_shape_info si= ti.lb()->get_shape(); + if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon)) + { + func.invert_state(si); + cur_func= func.count(); + } + if (cur_func) + { + area= scan_it.get_h() * + ((ti.rb()->x - ti.lb()->x) + (ti.rt()->x - ti.lt()->x)); + if (area > GIS_ZERO) + { + result= 0; + goto exit; + } + } + } + } + result= 1; + +exit: + collector.reset(); + func.reset(); + scan_it.reset(); + DBUG_RETURN(result); +mem_error: + null_value= 1; + DBUG_RETURN(0); +} + + +int Item_func_spatial_rel::func_equals() +{ + Gcalc_heap::Info *pi_s1, *pi_s2; + Gcalc_heap::Info *cur_pi= collector.get_first(); + double d; + + if (!cur_pi) + return 1; + + do { + pi_s1= cur_pi; + pi_s2= 0; + while ((cur_pi= cur_pi->get_next())) + { + d= fabs(pi_s1->x - cur_pi->x) + fabs(pi_s1->y - cur_pi->y); + if (d > GIS_ZERO) + break; + if (!pi_s2 && pi_s1->shape != cur_pi->shape) + pi_s2= cur_pi; + } + + if (!pi_s2) + return 0; + } while (cur_pi); + + return 1; +} + + +longlong Item_func_spatial_rel::val_int() +{ + DBUG_ENTER("Item_func_spatial_rel::val_int"); + DBUG_ASSERT(fixed == 1); + String *res1; + String *res2; + Geometry_buffer buffer1, buffer2; + Geometry *g1, *g2; + int result= 0; + int mask= 0; + + if (spatial_rel == SP_TOUCHES_FUNC) + DBUG_RETURN(func_touches()); + + res1= args[0]->val_str(&tmp_value1); + res2= args[1]->val_str(&tmp_value2); + Gcalc_operation_transporter trn(&func, &collector); + + if (func.reserve_op_buffer(1)) + DBUG_RETURN(0); + + switch (spatial_rel) { + case SP_CONTAINS_FUNC: + mask= 1; + func.add_operation(Gcalc_function::op_backdifference, 2); + break; + case SP_WITHIN_FUNC: + mask= 1; + func.add_operation(Gcalc_function::op_difference, 2); + break; + case SP_EQUALS_FUNC: + break; + case SP_DISJOINT_FUNC: + mask= 1; + func.add_operation(Gcalc_function::op_intersection, 2); + break; + case SP_INTERSECTS_FUNC: + func.add_operation(Gcalc_function::op_intersection, 2); + break; + case SP_OVERLAPS_FUNC: + func.add_operation(Gcalc_function::op_backdifference, 2); + break; + case SP_CROSSES_FUNC: + func.add_operation(Gcalc_function::op_intersection, 2); + break; + default: + DBUG_ASSERT(FALSE); + break; + } + + + 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)))) + goto exit; + + collector.prepare_operation(); + scan_it.init(&collector); + 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; + } + + if (func.alloc_states()) + goto exit; + + result= func.find_function(scan_it) ^ mask; + +exit: + collector.reset(); + func.reset(); + scan_it.reset(); + DBUG_RETURN(result); +} + + +Item_func_spatial_operation::~Item_func_spatial_operation() +{ +} + + +String *Item_func_spatial_operation::val_str(String *str_value) +{ + DBUG_ENTER("Item_func_spatial_operation::val_str"); + DBUG_ASSERT(fixed == 1); + String *res1= args[0]->val_str(&tmp_value1); + String *res2= args[1]->val_str(&tmp_value2); + Geometry_buffer buffer1, buffer2; + Geometry *g1, *g2; + uint32 srid= 0; + Gcalc_operation_transporter trn(&func, &collector); + + if (func.reserve_op_buffer(1)) + DBUG_RETURN(0); + func.add_operation(spatial_op, 2); + + 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)))) + goto exit; + + + collector.prepare_operation(); + scan_it.init(&collector); + if (func.alloc_states()) + goto exit; + + operation.init(&func); + + if (operation.count_all(&collector) || + operation.get_result(&res_receiver)) + goto exit; + + + str_value->set_charset(&my_charset_bin); + if (str_value->reserve(SRID_SIZE, 512)) + goto exit; + str_value->length(0); + str_value->q_append(srid); + + if (!Geometry::create_from_opresult(&buffer1, str_value, res_receiver)) + goto exit; + +exit: + collector.reset(); + func.reset(); + scan_it.reset(); + res_receiver.reset(); + DBUG_RETURN(str_value); +} + + +const char *Item_func_spatial_operation::func_name() const +{ + switch (spatial_op) { + case Gcalc_function::op_intersection: + return "st_intersection"; + case Gcalc_function::op_difference: + return "st_difference"; + case Gcalc_function::op_union: + return "st_union"; + case Gcalc_function::op_symdifference: + return "st_symdifference"; + default: + DBUG_ASSERT(0); // Should never happen + return "sp_unknown"; + } +} + + +static const int SINUSES_CALCULATED= 32; +static double n_sinus[SINUSES_CALCULATED+1]= +{ + 0, + 0.04906767432741802, + 0.0980171403295606, + 0.1467304744553618, + 0.1950903220161283, + 0.2429801799032639, + 0.2902846772544623, + 0.3368898533922201, + 0.3826834323650898, + 0.4275550934302821, + 0.4713967368259976, + 0.5141027441932217, + 0.5555702330196022, + 0.5956993044924334, + 0.6343932841636455, + 0.6715589548470183, + 0.7071067811865475, + 0.7409511253549591, + 0.773010453362737, + 0.8032075314806448, + 0.8314696123025452, + 0.8577286100002721, + 0.8819212643483549, + 0.9039892931234433, + 0.9238795325112867, + 0.9415440651830208, + 0.9569403357322089, + 0.970031253194544, + 0.9807852804032304, + 0.989176509964781, + 0.9951847266721968, + 0.9987954562051724, + 1 +}; + + +static void get_n_sincos(int n, double *sinus, double *cosinus) +{ + DBUG_ASSERT(n > 0 && n < SINUSES_CALCULATED*2+1); + if (n < (SINUSES_CALCULATED + 1)) + { + *sinus= n_sinus[n]; + *cosinus= n_sinus[SINUSES_CALCULATED - n]; + } + else + { + n-= SINUSES_CALCULATED; + *sinus= n_sinus[SINUSES_CALCULATED - n]; + *cosinus= -n_sinus[n]; + } +} + + +static int fill_half_circle(Gcalc_shape_transporter *trn, double x, double y, + double ax, double ay) +{ + double n_sin, n_cos; + double x_n, y_n; + for (int n = 1; n < (SINUSES_CALCULATED * 2 - 1); n++) + { + get_n_sincos(n, &n_sin, &n_cos); + x_n= ax * n_cos - ay * n_sin; + y_n= ax * n_sin + ay * n_cos; + if (trn->add_point(x_n + x, y_n + y)) + return 1; + } + return 0; +} + + +static int fill_gap(Gcalc_shape_transporter *trn, + double x, double y, + double ax, double ay, double bx, double by, double d, + bool *empty_gap) +{ + double ab= ax * bx + ay * by; + double cosab= ab / (d * d) + GIS_ZERO; + double n_sin, n_cos; + double x_n, y_n; + int n=1; + + *empty_gap= true; + for (;;) + { + get_n_sincos(n++, &n_sin, &n_cos); + if (n_cos <= cosab) + break; + *empty_gap= false; + x_n= ax * n_cos - ay * n_sin; + y_n= ax * n_sin + ay * n_cos; + if (trn->add_point(x_n + x, y_n + y)) + return 1; + } + return 0; +} + + +/* + Calculates the vector (p2,p1) and + negatively orthogonal to it with the length of d. + The result is (ex,ey) - the vector, (px,py) - the orthogonal. +*/ + +static void calculate_perpendicular( + double x1, double y1, double x2, double y2, double d, + double *ex, double *ey, + double *px, double *py) +{ + double q; + *ex= x1 - x2; + *ey= y1 - y2; + q= d / sqrt((*ex) * (*ex) + (*ey) * (*ey)); + *px= (*ey) * q; + *py= -(*ex) * q; +} + + +int Item_func_buffer::Transporter::single_point(double x, double y) +{ + return add_point_buffer(x, y); +} + + +int Item_func_buffer::Transporter::add_edge_buffer( + double x3, double y3, bool round_p1, bool round_p2) +{ + Gcalc_operation_transporter trn(m_fn, m_heap); + double e1_x, e1_y, e2_x, e2_y, p1_x, p1_y, p2_x, p2_y; + double e1e2; + double sin1, cos1; + double x_n, y_n; + bool empty_gap1, empty_gap2; + + ++m_nshapes; + if (trn.start_simple_poly()) + return 1; + + calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y); + calculate_perpendicular(x3, y3, x2, y2, m_d, &e2_x, &e2_y, &p2_x, &p2_y); + + e1e2= e1_x * e2_y - e2_x * e1_y; + sin1= n_sinus[1]; + cos1= n_sinus[31]; + if (e1e2 < 0) + { + empty_gap2= false; + x_n= x2 + p2_x * cos1 - p2_y * sin1; + y_n= y2 + p2_y * cos1 + p2_x * sin1; + if (fill_gap(&trn, x2, y2, -p1_x,-p1_y, p2_x,p2_y, m_d, &empty_gap1) || + trn.add_point(x2 + p2_x, y2 + p2_y) || + trn.add_point(x_n, y_n)) + return 1; + } + else + { + x_n= x2 - p2_x * cos1 - p2_y * sin1; + y_n= y2 - p2_y * cos1 + p2_x * sin1; + if (trn.add_point(x_n, y_n) || + trn.add_point(x2 - p2_x, y2 - p2_y) || + fill_gap(&trn, x2, y2, -p2_x, -p2_y, p1_x, p1_y, m_d, &empty_gap2)) + return 1; + empty_gap1= false; + } + if ((!empty_gap2 && trn.add_point(x2 + p1_x, y2 + p1_y)) || + trn.add_point(x1 + p1_x, y1 + p1_y)) + return 1; + + if (round_p1 && fill_half_circle(&trn, x1, y1, p1_x, p1_y)) + return 1; + + if (trn.add_point(x1 - p1_x, y1 - p1_y) || + (!empty_gap1 && trn.add_point(x2 - p1_x, y2 - p1_y))) + return 1; + return trn.complete_simple_poly(); +} + + +int Item_func_buffer::Transporter::add_last_edge_buffer() +{ + Gcalc_operation_transporter trn(m_fn, m_heap); + double e1_x, e1_y, p1_x, p1_y; + + ++m_nshapes; + if (trn.start_simple_poly()) + return 1; + + calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y); + + if (trn.add_point(x1 + p1_x, y1 + p1_y) || + trn.add_point(x1 - p1_x, y1 - p1_y) || + trn.add_point(x2 - p1_x, y2 - p1_y) || + fill_half_circle(&trn, x2, y2, -p1_x, -p1_y) || + trn.add_point(x2 + p1_x, y2 + p1_y)) + return 1; + return trn.complete_simple_poly(); +} + + +int Item_func_buffer::Transporter::add_point_buffer(double x, double y) +{ + Gcalc_operation_transporter trn(m_fn, m_heap); + + m_nshapes++; + if (trn.start_simple_poly()) + return 1; + if (trn.add_point(x - m_d, y) || + fill_half_circle(&trn, x, y, -m_d, 0.0) || + trn.add_point(x + m_d, y) || + fill_half_circle(&trn, x, y, m_d, 0.0)) + return 1; + return trn.complete_simple_poly(); +} + + +int Item_func_buffer::Transporter::start_line() +{ + m_npoints= 0; + int_start_line(); + return 0; +} + + +int Item_func_buffer::Transporter::start_poly() +{ + ++m_nshapes; + return Gcalc_operation_transporter::start_poly(); +} + + +int Item_func_buffer::Transporter::start_ring() +{ + m_npoints= 0; + return Gcalc_operation_transporter::start_ring(); +} + + +int Item_func_buffer::Transporter::add_point(double x, double y) +{ + if (m_npoints && x == x2 && y == y2) + return 0; + + ++m_npoints; + + if (m_npoints == 1) + { + x00= x; + y00= y; + } + else if (m_npoints == 2) + { + x01= x; + y01= y; + } + else if (add_edge_buffer(x, y, (m_npoints == 3) && line_started(), false)) + return 1; + + x1= x2; + y1= y2; + x2= x; + y2= y; + + return line_started() ? 0 : Gcalc_operation_transporter::add_point(x, y); +} + + +int Item_func_buffer::Transporter::complete() +{ + if (m_npoints) + { + if (m_npoints == 1) + { + if (add_point_buffer(x2, y2)) + return 1; + } + else if (m_npoints == 2) + { + if (add_edge_buffer(x1, y1, true, true)) + return 1; + } + else if (line_started()) + { + if (add_last_edge_buffer()) + return 1; + } + else + { + if (x2 != x00 && y2 != y00) + { + if (add_edge_buffer(x00, y00, false, false)) + return 1; + x1= x2; + y1= y2; + x2= x00; + y2= y00; + } + if (add_edge_buffer(x01, y01, false, false)) + return 1; + } + } + + return 0; +} + + +int Item_func_buffer::Transporter::complete_line() +{ + if (complete()) + return 1; + int_complete_line(); + return 0; +} + + +int Item_func_buffer::Transporter::complete_ring() +{ + return complete() || + Gcalc_operation_transporter::complete_ring(); +} + + +String *Item_func_buffer::val_str(String *str_value) +{ + DBUG_ENTER("Item_func_buffer::val_str"); + DBUG_ASSERT(fixed == 1); + String *obj= args[0]->val_str(&tmp_value); + double dist= args[1]->val_real(); + Geometry_buffer buffer; + Geometry *g; + uint32 union_pos; + uint32 srid= 0; + String *str_result= NULL; + Transporter trn(&func, &collector, dist); + + null_value= 1; + if (args[0]->null_value || args[1]->null_value || + !(g= Geometry::construct(&buffer, obj->ptr(), obj->length()))) + goto mem_error; + + if (func.reserve_op_buffer(2)) + goto mem_error; + /* will specify operands later */ + union_pos= func.get_next_operation_pos(); + func.add_operation((dist > 0.0) ? Gcalc_function::op_union : + Gcalc_function::op_difference, 0); + + if (g->store_shapes(&trn)) + goto mem_error; + + func.add_operands_to_op(union_pos, trn.m_nshapes); + collector.prepare_operation(); + if (func.alloc_states()) + goto mem_error; + operation.init(&func); + + if (operation.count_all(&collector) || + operation.get_result(&res_receiver)) + goto mem_error; + + + str_value->set_charset(&my_charset_bin); + if (str_value->reserve(SRID_SIZE, 512)) + goto mem_error; + str_value->length(0); + str_value->q_append(srid); + + if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver)) + goto mem_error; + + null_value= 0; + str_result= str_value; +mem_error: + collector.reset(); + func.reset(); + scan_it.reset(); + res_receiver.reset(); + DBUG_RETURN(str_result); +} + + longlong Item_func_isempty::val_int() { DBUG_ASSERT(fixed == 1); @@ -566,20 +1460,50 @@ longlong Item_func_isempty::val_int() } -/** - @todo - Ramil or Holyfoot, add real IsSimple calculation -*/ longlong Item_func_issimple::val_int() { - DBUG_ASSERT(fixed == 1); - String tmp; String *swkb= args[0]->val_str(&tmp); Geometry_buffer buffer; + Gcalc_operation_transporter trn(&func, &collector); + Geometry *g; + int result= 1; + + DBUG_ENTER("Item_func_issimple::val_int"); + DBUG_ASSERT(fixed == 1); - null_value= args[0]->null_value || - !(Geometry::construct(&buffer, swkb->ptr(), swkb->length())); - /* TODO: Ramil or Holyfoot, add real IsSimple calculation */ + if ((null_value= args[0]->null_value) || + !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))) + DBUG_RETURN(0); + + + if (g->get_class_info()->m_type_id == Geometry::wkb_point) + DBUG_RETURN(1); + + if (g->store_shapes(&trn)) + goto mem_error; + + collector.prepare_operation(); + scan_it.init(&collector); + + while (scan_it.more_points()) + { + if (scan_it.step()) + goto mem_error; + + if (scan_it.get_event() == scev_intersection) + { + result= 0; + break; + } + } + + collector.reset(); + func.reset(); + scan_it.reset(); + DBUG_RETURN(result); +mem_error: + null_value= 1; + DBUG_RETURN(0); return 0; } @@ -752,4 +1676,160 @@ longlong Item_func_srid::val_int() return (longlong) (uint4korr(swkb->ptr())); } + +double Item_func_distance::val_real() +{ + bool above_cur_point, cur_point_edge; + const Gcalc_scan_iterator::point *evpos; + const Gcalc_heap::Info *cur_point, *dist_point; + Gcalc_scan_events ev; + double t, distance, cur_distance; + double x1, x2, y1, y2; + double ex, ey, vx, vy, e_sqrlen; + uint obj2_si; + Gcalc_operation_transporter trn(&func, &collector); + + DBUG_ENTER("Item_func_distance::val_real"); + DBUG_ASSERT(fixed == 1); + String *res1= args[0]->val_str(&tmp_value1); + String *res2= args[1]->val_str(&tmp_value2); + Geometry_buffer buffer1, buffer2; + Geometry *g1, *g2; + + + 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()))))) + goto mem_error; + + if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) && + (g2->get_class_info()->m_type_id == Geometry::wkb_point)) + { + if (((Gis_point *) g1)->get_xy(&x1, &y1) || + ((Gis_point *) g2)->get_xy(&x2, &y2)) + goto mem_error; + ex= x2 - x1; + ey= y2 - y1; + DBUG_RETURN(sqrt(ex * ex + ey * ey)); + } + + if (func.reserve_op_buffer(1)) + goto mem_error; + func.add_operation(Gcalc_function::op_intersection, 2); + + if (g1->store_shapes(&trn)) + goto mem_error; + obj2_si= func.get_nshapes(); + if (g2->store_shapes(&trn) || func.alloc_states()) + goto mem_error; + + collector.prepare_operation(); + scan_it.init(&collector); + + 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_event(); + cur_point= evpos->pi; + + /* + handling intersection we only need to check if it's the intersecion + of objects 1 and 2. In this case distance is 0 + */ + if (ev == scev_intersection) + { + if ((evpos->get_next()->pi->shape >= obj2_si) != + (cur_point->shape >= obj2_si)) + { + distance= 0; + goto exit; + } + continue; + } + + /* + if we get 'scev_point | scev_end | scev_two_ends' we don't need + to check for intersection of objects. + Though we need to calculate distances. + */ + if (ev & (scev_point | scev_end | scev_two_ends)) + goto count_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; + } + + +count_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: + collector.reset(); + func.reset(); + scan_it.reset(); + DBUG_RETURN(distance); +mem_error: + null_value= 1; + DBUG_RETURN(0); +} + + #endif /*HAVE_SPATIAL*/ diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 0bcd933e52b..1838a3783e8 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -1,4 +1,7 @@ -/* Copyright (c) 2003, 2011, Oracle and/or its affiliates. +#ifndef ITEM_GEOFUNC_INCLUDED +#define ITEM_GEOFUNC_INCLUDED + +/* Copyright (c) 2000, 2010, 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 @@ -10,8 +13,8 @@ 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ /* This file defines all spatial functions */ @@ -22,6 +25,8 @@ #pragma interface /* gcc class implementation */ #endif +#include "gcalc_slicescan.h" + class Item_geometry_func: public Item_str_func { public: @@ -41,7 +46,7 @@ class Item_func_geometry_from_text: public Item_geometry_func public: Item_func_geometry_from_text(Item *a) :Item_geometry_func(a) {} Item_func_geometry_from_text(Item *a, Item *srid) :Item_geometry_func(a, srid) {} - const char *func_name() const { return "geometryfromtext"; } + const char *func_name() const { return "st_geometryfromtext"; } String *val_str(String *); }; @@ -50,7 +55,7 @@ class Item_func_geometry_from_wkb: public Item_geometry_func public: Item_func_geometry_from_wkb(Item *a): Item_geometry_func(a) {} Item_func_geometry_from_wkb(Item *a, Item *srid): Item_geometry_func(a, srid) {} - const char *func_name() const { return "geometryfromwkb"; } + const char *func_name() const { return "st_geometryfromwkb"; } String *val_str(String *); }; @@ -58,7 +63,7 @@ class Item_func_as_wkt: public Item_str_func { public: Item_func_as_wkt(Item *a): Item_str_func(a) {} - const char *func_name() const { return "astext"; } + const char *func_name() const { return "st_astext"; } String *val_str(String *); void fix_length_and_dec(); }; @@ -67,7 +72,7 @@ class Item_func_as_wkb: public Item_geometry_func { public: Item_func_as_wkb(Item *a): Item_geometry_func(a) {} - const char *func_name() const { return "aswkb"; } + const char *func_name() const { return "st_aswkb"; } String *val_str(String *); enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } }; @@ -77,11 +82,12 @@ class Item_func_geometry_type: public Item_str_func public: Item_func_geometry_type(Item *a): Item_str_func(a) {} String *val_str(String *); - const char *func_name() const { return "geometrytype"; } + const char *func_name() const { return "st_geometrytype"; } void fix_length_and_dec() { - max_length=20; // "GeometryCollection" is the most long - maybe_null= 1; + // "GeometryCollection" is the longest + max_length= 20; + maybe_null= 1; }; }; @@ -89,7 +95,7 @@ class Item_func_centroid: public Item_geometry_func { public: Item_func_centroid(Item *a): Item_geometry_func(a) {} - const char *func_name() const { return "centroid"; } + const char *func_name() const { return "st_centroid"; } String *val_str(String *); Field::geometry_type get_geometry_type() const; }; @@ -98,7 +104,7 @@ class Item_func_envelope: public Item_geometry_func { public: Item_func_envelope(Item *a): Item_geometry_func(a) {} - const char *func_name() const { return "envelope"; } + const char *func_name() const { return "st_envelope"; } String *val_str(String *); Field::geometry_type get_geometry_type() const; }; @@ -108,7 +114,7 @@ class Item_func_point: public Item_geometry_func public: Item_func_point(Item *a, Item *b): Item_geometry_func(a, b) {} Item_func_point(Item *a, Item *b, Item *srid): Item_geometry_func(a, b, srid) {} - const char *func_name() const { return "point"; } + const char *func_name() const { return "st_point"; } String *val_str(String *); Field::geometry_type get_geometry_type() const; }; @@ -124,11 +130,11 @@ public: switch (decomp_func) { case SP_STARTPOINT: - return "startpoint"; + return "st_startpoint"; case SP_ENDPOINT: - return "endpoint"; + return "st_endpoint"; case SP_EXTERIORRING: - return "exteriorring"; + return "st_exteriorring"; default: DBUG_ASSERT(0); // Should never happened return "spatial_decomp_unknown"; @@ -148,11 +154,11 @@ public: switch (decomp_func_n) { case SP_POINTN: - return "pointn"; + return "st_pointn"; case SP_GEOMETRYN: - return "geometryn"; + return "st_geometryn"; case SP_INTERIORRINGN: - return "interiorringn"; + return "st_interiorringn"; default: DBUG_ASSERT(0); // Should never happened return "spatial_decomp_n_unknown"; @@ -177,7 +183,6 @@ public: String *val_str(String *); void fix_length_and_dec() { - Item_geometry_func::fix_length_and_dec(); for (unsigned int i= 0; i < arg_count; ++i) { if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY) @@ -191,57 +196,53 @@ public: } } - const char *func_name() const { return "multipoint"; } + const char *func_name() const { return "st_multipoint"; } }; + /* Spatial relations */ -class Item_func_spatial_rel: public Item_bool_func2 +class Item_func_spatial_mbr_rel: public Item_bool_func2 { enum Functype spatial_rel; public: - Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) : + Item_func_spatial_mbr_rel(Item *a,Item *b, enum Functype sp_rel) : Item_bool_func2(a,b) { spatial_rel = sp_rel; } longlong val_int(); enum Functype functype() const { - switch (spatial_rel) { - case SP_CONTAINS_FUNC: - return SP_WITHIN_FUNC; - case SP_WITHIN_FUNC: - return SP_CONTAINS_FUNC; - default: - return spatial_rel; - } + return spatial_rel; } enum Functype rev_functype() const { return spatial_rel; } - const char *func_name() const - { - switch (spatial_rel) { - case SP_CONTAINS_FUNC: - return "contains"; - case SP_WITHIN_FUNC: - return "within"; - case SP_EQUALS_FUNC: - return "equals"; - case SP_DISJOINT_FUNC: - return "disjoint"; - case SP_INTERSECTS_FUNC: - return "intersects"; - case SP_TOUCHES_FUNC: - return "touches"; - case SP_CROSSES_FUNC: - return "crosses"; - case SP_OVERLAPS_FUNC: - return "overlaps"; - default: - DBUG_ASSERT(0); // Should never happened - return "sp_unknown"; - } + const char *func_name() const; + virtual inline void print(String *str, enum_query_type query_type) + { + Item_func::print(str, query_type); } + void fix_length_and_dec() { maybe_null= 1; } + bool is_null() { (void) val_int(); return null_value; } +}; + +class Item_func_spatial_rel: public Item_bool_func2 +{ + enum Functype spatial_rel; + Gcalc_heap collector; + Gcalc_scan_iterator scan_it; + Gcalc_function func; + String tmp_value1,tmp_value2; +public: + Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel); + virtual ~Item_func_spatial_rel(); + longlong val_int(); + enum Functype functype() const + { + return spatial_rel; + } + enum Functype rev_functype() const { return spatial_rel; } + const char *func_name() const; virtual inline void print(String *str, enum_query_type query_type) { Item_func::print(str, query_type); @@ -249,25 +250,104 @@ public: void fix_length_and_dec() { maybe_null= 1; } bool is_null() { (void) val_int(); return null_value; } +protected: + int func_touches(); + int func_equals(); }; + +/* + Spatial operations +*/ + +class Item_func_spatial_operation: public Item_geometry_func +{ +public: + Gcalc_function::op_type spatial_op; + Gcalc_heap collector; + Gcalc_function func; + Gcalc_scan_iterator scan_it; + + Gcalc_result_receiver res_receiver; + Gcalc_operation_reducer operation; + String tmp_value1,tmp_value2; +public: + Item_func_spatial_operation(Item *a,Item *b, Gcalc_function::op_type sp_op) : + Item_geometry_func(a, b), spatial_op(sp_op) + {} + virtual ~Item_func_spatial_operation(); + String *val_str(String *); + const char *func_name() const; + virtual inline void print(String *str, enum_query_type query_type) + { + Item_func::print(str, query_type); + } +}; + + +class Item_func_buffer: public Item_geometry_func +{ +protected: + class Transporter : public Gcalc_operation_transporter + { + int m_npoints; + double m_d; + double x1,y1,x2,y2; + double x00,y00,x01,y01; + int add_edge_buffer(double x3, double y3, bool round_p1, bool round_p2); + int add_last_edge_buffer(); + int add_point_buffer(double x, double y); + int complete(); + public: + int m_nshapes; + Transporter(Gcalc_function *fn, Gcalc_heap *heap, double d) : + Gcalc_operation_transporter(fn, heap), m_npoints(0), m_d(d), m_nshapes(0) + {} + int single_point(double x, double y); + int start_line(); + int complete_line(); + int start_poly(); + int start_ring(); + int complete_ring(); + int add_point(double x, double y); + }; + Gcalc_heap collector; + Gcalc_function func; + Gcalc_scan_iterator scan_it; + + Gcalc_result_receiver res_receiver; + Gcalc_operation_reducer operation; + String tmp_value; + +public: + Item_func_buffer(Item *obj, Item *distance): + Item_geometry_func(obj, distance) {} + const char *func_name() const { return "st_buffer"; } + String *val_str(String *); +}; + + class Item_func_isempty: public Item_bool_func { public: Item_func_isempty(Item *a): Item_bool_func(a) {} longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_NONE; } - const char *func_name() const { return "isempty"; } + const char *func_name() const { return "st_isempty"; } void fix_length_and_dec() { maybe_null= 1; } }; class Item_func_issimple: public Item_bool_func { + Gcalc_heap collector; + Gcalc_function func; + Gcalc_scan_iterator scan_it; + String tmp; public: Item_func_issimple(Item *a): Item_bool_func(a) {} longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_NONE; } - const char *func_name() const { return "issimple"; } + const char *func_name() const { return "st_issimple"; } void fix_length_and_dec() { maybe_null= 1; } }; @@ -277,7 +357,7 @@ public: Item_func_isclosed(Item *a): Item_bool_func(a) {} longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_NONE; } - const char *func_name() const { return "isclosed"; } + const char *func_name() const { return "st_isclosed"; } void fix_length_and_dec() { maybe_null= 1; } }; @@ -287,7 +367,7 @@ class Item_func_dimension: public Item_int_func public: Item_func_dimension(Item *a): Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "dimension"; } + const char *func_name() const { return "st_dimension"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } }; @@ -297,7 +377,7 @@ class Item_func_x: public Item_real_func public: Item_func_x(Item *a): Item_real_func(a) {} double val_real(); - const char *func_name() const { return "x"; } + const char *func_name() const { return "st_x"; } void fix_length_and_dec() { Item_real_func::fix_length_and_dec(); @@ -312,7 +392,7 @@ class Item_func_y: public Item_real_func public: Item_func_y(Item *a): Item_real_func(a) {} double val_real(); - const char *func_name() const { return "y"; } + const char *func_name() const { return "st_y"; } void fix_length_and_dec() { Item_real_func::fix_length_and_dec(); @@ -327,7 +407,7 @@ class Item_func_numgeometries: public Item_int_func public: Item_func_numgeometries(Item *a): Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "numgeometries"; } + const char *func_name() const { return "st_numgeometries"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } }; @@ -338,7 +418,7 @@ class Item_func_numinteriorring: public Item_int_func public: Item_func_numinteriorring(Item *a): Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "numinteriorrings"; } + const char *func_name() const { return "st_numinteriorrings"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } }; @@ -349,7 +429,7 @@ class Item_func_numpoints: public Item_int_func public: Item_func_numpoints(Item *a): Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "numpoints"; } + const char *func_name() const { return "st_numpoints"; } void fix_length_and_dec() { max_length= 10; maybe_null= 1; } }; @@ -360,7 +440,7 @@ class Item_func_area: public Item_real_func public: Item_func_area(Item *a): Item_real_func(a) {} double val_real(); - const char *func_name() const { return "area"; } + const char *func_name() const { return "st_area"; } void fix_length_and_dec() { Item_real_func::fix_length_and_dec(); @@ -375,7 +455,7 @@ class Item_func_glength: public Item_real_func public: Item_func_glength(Item *a): Item_real_func(a) {} double val_real(); - const char *func_name() const { return "glength"; } + const char *func_name() const { return "st_length"; } void fix_length_and_dec() { Item_real_func::fix_length_and_dec(); @@ -394,11 +474,26 @@ public: void fix_length_and_dec() { max_length= 10; maybe_null= 1; } }; + +class Item_func_distance: public Item_real_func +{ + String tmp_value1; + String tmp_value2; + Gcalc_heap collector; + Gcalc_function func; + Gcalc_scan_iterator scan_it; +public: + Item_func_distance(Item *a, Item *b): Item_real_func(a, b) {} + double val_real(); + const char *func_name() const { return "st_distance"; } +}; + #define GEOM_NEW(thd, obj_constructor) new (thd->mem_root) obj_constructor #else /*HAVE_SPATIAL*/ #define GEOM_NEW(thd, obj_constructor) NULL -#endif +#endif /*HAVE_SPATIAL*/ +#endif /*ITEM_GEOFUNC_INCLUDED*/ diff --git a/sql/plistsort.c b/sql/plistsort.c new file mode 100644 index 00000000000..71d287e7b45 --- /dev/null +++ b/sql/plistsort.c @@ -0,0 +1,166 @@ +/* Copyright (c) 2000, 2010 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/* +things to define before including the file: + +#define LS_LIST_ITEM ListItem +#define LS_COMPARE_FUNC_DECL compare_func var_name, +#define LS_COMPARE_FUNC_CALL(list_el1, list_el2) (*var_name)(list_el1, list_el2) +#define LS_NEXT(A) (A)->next +#define LS_SET_NEXT(A,val) (A)->next= val +#define LS_P_NEXT(A) &(A)->next +#define LS_NAME plistsort +#define LS_SCOPE static +#define LS_STRUCT_NAME ls_struct_name +*/ + +typedef struct LS_STRUCT_NAME +{ + LS_LIST_ITEM *list1; + int list_len; + int return_point; +} LS_STRUCT_NAME; + +LS_SCOPE LS_LIST_ITEM* LS_NAME(LS_COMPARE_FUNC_DECL LS_LIST_ITEM *list, int list_len) +{ + LS_LIST_ITEM *list_end; + LS_LIST_ITEM *sorted_list; + + struct LS_STRUCT_NAME stack[63], *sp= stack; + + if (list_len < 2) + return list; + + sp->list_len= list_len; + sp->return_point= 2; + +recursion_point: + + if (sp->list_len < 4) + { + LS_LIST_ITEM *e1, *e2; + sorted_list= list; + e1= LS_NEXT(sorted_list); + list_end= LS_NEXT(e1); + if (LS_COMPARE_FUNC_CALL(sorted_list, e1)) + { + sorted_list= e1; + e1= list; + } + if (sp->list_len == 2) + { + LS_SET_NEXT(sorted_list, e1); + LS_SET_NEXT(e1, NULL); + goto exit_point; + } + e2= list_end; + list_end= LS_NEXT(e2); + if (LS_COMPARE_FUNC_CALL(e1, e2)) + { + { + LS_LIST_ITEM *tmp_e= e1; + e1= e2; + e2= tmp_e; + } + if (LS_COMPARE_FUNC_CALL(sorted_list, e1)) + { + LS_LIST_ITEM *tmp_e= sorted_list; + sorted_list= e1; + e1= tmp_e; + } + } + + LS_SET_NEXT(sorted_list, e1); + LS_SET_NEXT(e1, e2); + LS_SET_NEXT(e2, NULL); + goto exit_point; + } + + { + register struct LS_STRUCT_NAME *sp0= sp++; + sp->list_len= sp0->list_len >> 1; + sp0->list_len-= sp->list_len; + sp->return_point= 0; + } + goto recursion_point; +return_point0: + sp->list1= sorted_list; + { + register struct LS_STRUCT_NAME *sp0= sp++; + list= list_end; + sp->list_len= sp0->list_len; + sp->return_point= 1; + } + goto recursion_point; +return_point1: + { + register LS_LIST_ITEM **hook= &sorted_list; + register LS_LIST_ITEM *list1= sp->list1; + register LS_LIST_ITEM *list2= sorted_list; + + if (LS_COMPARE_FUNC_CALL(list1, list2)) + { + LS_LIST_ITEM *tmp_e= list2; + list2= list1; + list1= tmp_e; + } + for (;;) + { + *hook= list1; + do + { + if (!(list1= *(hook= LS_P_NEXT(list1)))) + { + *hook= list2; + goto exit_point; + } + } while (LS_COMPARE_FUNC_CALL(list2, list1)); + + *hook= list2; + do + { + if (!(list2= *(hook= LS_P_NEXT(list2)))) + { + *hook= list1; + goto exit_point; + } + } while (LS_COMPARE_FUNC_CALL(list1, list2)); + } + } + +exit_point: + switch ((sp--)->return_point) + { + case 0: goto return_point0; + case 1: goto return_point1; + default:; + } + + return sorted_list; +} + + +#undef LS_LIST_ITEM +#undef LS_NEXT +#undef LS_SET_NEXT +#undef LS_P_NEXT +#undef LS_NAME +#undef LS_STRUCT_NAME +#undef LS_SCOPE +#undef LS_COMPARE_FUNC_DECL +#undef LS_COMPARE_FUNC_CALL + diff --git a/sql/spatial.cc b/sql/spatial.cc index 8b869a5b1ca..48f6f466a30 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 MySQL AB +/* Copyright (c) 2004, 2010, 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 @@ -10,8 +10,8 @@ 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #include "mysql_priv.h" @@ -38,7 +38,7 @@ 17 */ -#define MAX_DIGITS_IN_DOUBLE 22 +#define MAX_DIGITS_IN_DOUBLE 30 /***************************** Gis_class_info *******************************/ @@ -264,12 +264,28 @@ Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer, } +int Geometry::create_from_opresult(Geometry_buffer *g_buf, + String *res, Gcalc_result_receiver &rr) +{ + uint32 geom_type= rr.get_result_typeid(); + Geometry *obj= create_by_typeid(g_buf, geom_type); + + if (!obj || res->reserve(WKB_HEADER_SIZE, 512)) + return 1; + + res->q_append((char) wkb_ndr); + res->q_append(geom_type); + return obj->init_from_opresult(res, rr.result(), rr.get_nshapes()); +} + + bool Geometry::envelope(String *result) const { MBR mbr; const char *end; - if (get_mbr(&mbr, &end) || result->reserve(1+4*3+SIZEOF_STORED_DOUBLE*10)) + if (get_mbr(&mbr, &end) || + result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10)) return 1; result->q_append((char) wkb_ndr); @@ -306,13 +322,13 @@ bool Geometry::envelope(String *result) const bool Geometry::create_point(String *result, const char *data) const { - if (no_data(data, SIZEOF_STORED_DOUBLE * 2) || - result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2)) + if (no_data(data, POINT_DATA_SIZE) || + result->reserve(1 + 4 + POINT_DATA_SIZE)) return 1; result->q_append((char) wkb_ndr); result->q_append((uint32) wkb_point); /* Copy two double in same format */ - result->q_append(data, SIZEOF_STORED_DOUBLE*2); + result->q_append(data, POINT_DATA_SIZE); return 0; } @@ -332,7 +348,7 @@ bool Geometry::create_point(String *result, const char *data) const bool Geometry::create_point(String *result, double x, double y) const { - if (result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2)) + if (result->reserve(1 + 4 + POINT_DATA_SIZE)) return 1; result->q_append((char) wkb_ndr); @@ -364,7 +380,7 @@ const char *Geometry::append_points(String *txt, uint32 n_points, double x,y; data+= offset; get_point(&x, &y, data); - data+= SIZEOF_STORED_DOUBLE * 2; + data+= POINT_DATA_SIZE; txt->qs_append(x); txt->qs_append(' '); txt->qs_append(y); @@ -399,7 +415,7 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points)) + if (no_data(data, (POINT_DATA_SIZE + offset) * points)) return 0; /* Calculate MBR for points */ @@ -407,7 +423,7 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, { data+= offset; mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE); - data+= SIZEOF_STORED_DOUBLE * 2; + data+= POINT_DATA_SIZE; } return data; } @@ -425,7 +441,7 @@ bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb) { double x, y; if (trs->get_next_number(&x) || trs->get_next_number(&y) || - wkb->reserve(SIZEOF_STORED_DOUBLE * 2)) + wkb->reserve(POINT_DATA_SIZE)) return 1; wkb->q_append(x); wkb->q_append(y); @@ -472,6 +488,15 @@ bool Gis_point::get_mbr(MBR *mbr, const char **end) const return 0; } + +int Gis_point::store_shapes(Gcalc_shape_transporter *trn) const +{ + double x, y; + + return get_xy(&x, &y) || trn->single_point(x, y); +} + + const Geometry::Class_info *Gis_point::get_class_info() const { return &point_class; @@ -523,12 +548,12 @@ uint Gis_line_string::init_from_wkb(const char *wkb, uint len, const char *wkb_end; Gis_point p; - if (len < 4) + if (len < 4 || + (n_points= wkb_get_uint(wkb, bo))<1) return 0; - n_points= wkb_get_uint(wkb, bo); proper_length= 4 + n_points * POINT_DATA_SIZE; - if (!n_points || len < proper_length || res->reserve(proper_length)) + if (len < proper_length || res->reserve(proper_length)) return 0; res->q_append(n_points); @@ -554,7 +579,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const data += 4; if (n_points < 1 || - no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) || + no_data(data, POINT_DATA_SIZE * n_points) || txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points)) return 1; @@ -562,7 +587,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const { double x, y; get_point(&x, &y, data); - data+= SIZEOF_STORED_DOUBLE * 2; + data+= POINT_DATA_SIZE; txt->qs_append(x); txt->qs_append(' '); txt->qs_append(y); @@ -591,17 +616,16 @@ int Gis_line_string::geom_length(double *len) const return 1; n_points= uint4korr(data); data+= 4; - if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) + if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points)) return 1; get_point(&prev_x, &prev_y, data); - data+= SIZEOF_STORED_DOUBLE*2; - + data+= POINT_DATA_SIZE; while (--n_points) { double x, y; get_point(&x, &y, data); - data+= SIZEOF_STORED_DOUBLE * 2; + data+= POINT_DATA_SIZE; *len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2)); prev_x= x; prev_y= y; @@ -625,14 +649,14 @@ int Gis_line_string::is_closed(int *closed) const return 0; } data+= 4; - if (no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) + if (no_data(data, POINT_DATA_SIZE * n_points)) return 1; /* Get first point */ get_point(&x1, &y1, data); /* get last point */ - data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE; + data+= POINT_DATA_SIZE + (n_points-2)*POINT_DATA_SIZE; get_point(&x2, &y2, data); *closed= (x1==x2) && (y1==y2); @@ -676,6 +700,34 @@ int Gis_line_string::point_n(uint32 num, String *result) const return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE); } + +int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_points; + double x, y; + const char *data= m_data; + + if (no_data(m_data, 4)) + return 1; + n_points= uint4korr(data); + data+= 4; + if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points)) + return 1; + + trn->start_line(); + + while (n_points--) + { + get_point(&x, &y, data); + data+= POINT_DATA_SIZE; + if (trn->add_point(x, y)) + return 1; + } + + return trn->complete_line(); +} + + const Geometry::Class_info *Gis_line_string::get_class_info() const { return &linestring_class; @@ -737,6 +789,53 @@ bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) } +uint Gis_polygon::priv_init_from_opresult(String *bin, + const char *opres, uint32 n_shapes, + uint32 *poly_shapes) +{ + const char *opres_orig= opres; + uint32 position= bin->length(); + + *poly_shapes= 0; + if (bin->reserve(4, 512)) + return 0; + bin->q_append(*poly_shapes); + + while (n_shapes--) + { + uint32 n_points, proper_length; + const char *op_end, *p1_position; + Gis_point p; + Gcalc_function::shape_type st; + + st= (Gcalc_function::shape_type) uint4korr(opres); + if (*poly_shapes && st != Gcalc_function::shape_hole) + break; + (*poly_shapes)++; + n_points= uint4korr(opres + 4) + 1; /* skip shape type id */ + proper_length= 4 + n_points * POINT_DATA_SIZE; + + if (bin->reserve(proper_length, 512)) + return 0; + + bin->q_append(n_points); + op_end= opres + 8 + (n_points-1) * 8 * 2; + p1_position= (opres+= 8); + for (; opreswrite_at_position(position, *poly_shapes); + + return (uint) (opres - opres_orig); +} + + uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) { @@ -746,9 +845,7 @@ uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, if (len < 4) return 0; - if (!(n_linear_rings= wkb_get_uint(wkb, bo))) - return 0; - + n_linear_rings= wkb_get_uint(wkb, bo); if (res->reserve(4, 512)) return 0; wkb+= 4; @@ -794,7 +891,7 @@ bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const return 1; n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) || + if (no_data(data, POINT_DATA_SIZE * n_points) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; txt->qs_append('('); @@ -848,16 +945,16 @@ int Gis_polygon::area(double *ar, const char **end_of_data) const if (no_data(data, 4)) return 1; n_points= uint4korr(data); - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) + if (no_data(data, POINT_DATA_SIZE * n_points)) return 1; get_point(&prev_x, &prev_y, data+4); - data+= (4+SIZEOF_STORED_DOUBLE*2); + data+= (4+POINT_DATA_SIZE); while (--n_points) // One point is already read { double x, y; get_point(&x, &y, data); - data+= (SIZEOF_STORED_DOUBLE*2); + data+= POINT_DATA_SIZE; lr_area+= (prev_x + x)* (prev_y - y); prev_x= x; prev_y= y; @@ -884,7 +981,7 @@ int Gis_polygon::exterior_ring(String *result) const n_points= uint4korr(data); data+= 4; length= n_points * POINT_DATA_SIZE; - if (no_data(data, length) || result->reserve(1+4+4+ length)) + if (no_data(data, length) || result->reserve(1 + 4 + 4 + length)) return 1; result->q_append((char) wkb_ndr); @@ -930,7 +1027,7 @@ int Gis_polygon::interior_ring_n(uint32 num, String *result) const n_points= uint4korr(data); points_size= n_points * POINT_DATA_SIZE; data+= 4; - if (no_data(data, points_size) || result->reserve(1+4+4+ points_size)) + if (no_data(data, points_size) || result->reserve(1 + 4 + 4 + points_size)) return 1; result->q_append((char) wkb_ndr); @@ -969,16 +1066,16 @@ int Gis_polygon::centroid_xy(double *x, double *y) const return 1; org_n_points= n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) + if (no_data(data, POINT_DATA_SIZE * n_points)) return 1; get_point(&prev_x, &prev_y, data); - data+= (SIZEOF_STORED_DOUBLE*2); + data+= POINT_DATA_SIZE; while (--n_points) // One point is already read { double tmp_x, tmp_y; get_point(&tmp_x, &tmp_y, data); - data+= (SIZEOF_STORED_DOUBLE*2); + data+= POINT_DATA_SIZE; cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y); cur_cx+= tmp_x; cur_cy+= tmp_y; @@ -1018,6 +1115,49 @@ int Gis_polygon::centroid(String *result) const return create_point(result, x, y); } + +int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_linear_rings; + const char *data= m_data; + + if (trn->start_poly()) + return 1; + + if (no_data(data, 4)) + return 1; + n_linear_rings= uint4korr(data); + data+= 4; + + while (n_linear_rings--) + { + uint32 n_points; + + if (no_data(data, 4)) + return 1; + n_points= uint4korr(data); + data+= 4; + if (!n_points || no_data(data, POINT_DATA_SIZE * n_points)) + return 1; + + trn->start_ring(); + while (--n_points) + { + double x, y; + get_point(&x, &y, data); + data+= POINT_DATA_SIZE; + if (trn->add_point(x, y)) + return 1; + } + data+= POINT_DATA_SIZE; + trn->complete_ring(); + } + + trn->complete_poly(); + return 0; +} + + const Geometry::Class_info *Gis_polygon::get_class_info() const { return &polygon_class; @@ -1046,7 +1186,7 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) for (;;) { - if (wkb->reserve(1+4, 512)) + if (wkb->reserve(1 + 4, 512)) return 1; wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_point); @@ -1061,6 +1201,32 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) } +uint Gis_multi_point::init_from_opresult(String *bin, + const char *opres, uint32 n_shapes) +{ + uint bin_size, opres_size; + Gis_point p; + const char *opres_end; + + bin_size= n_shapes * (WKB_HEADER_SIZE + POINT_DATA_SIZE) + 4; + opres_size= n_shapes * (4 + 8*2); + + if (bin->reserve(bin_size, 512)) + return 0; + + bin->q_append(n_shapes); + opres_end= opres + opres_size; + for (; opres < opres_end; opres+= (4 + 8*2)) + { + bin->q_append((char)wkb_ndr); + bin->q_append((uint32)wkb_point); + if (!p.init_from_wkb(opres + 4, POINT_DATA_SIZE, wkb_ndr, bin)) + return 0; + } + return opres_size; +} + + uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) { @@ -1099,7 +1265,7 @@ bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const n_points= uint4korr(m_data); if (no_data(m_data+4, - n_points * (SIZEOF_STORED_DOUBLE * 2 + WKB_HEADER_SIZE)) || + n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE)) || txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; *end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE); @@ -1140,6 +1306,35 @@ int Gis_multi_point::geometry_n(uint32 num, String *result) const return 0; } + +int Gis_multi_point::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_points; + Gis_point pt; + const char *data= m_data; + + if (no_data(data, 4)) + return 1; + n_points= uint4korr(data); + data+= 4; + + if (trn->start_collection(n_points)) + return 1; + + while (n_points--) + { + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + data+= WKB_HEADER_SIZE; + pt.set_data_ptr(data, (uint32) (m_data_end - data)); + if (pt.store_shapes(trn)) + return 1; + data+= pt.get_data_size(); + } + return 0; +} + + const Geometry::Class_info *Gis_multi_point::get_class_info() const { return &multipoint_class; @@ -1182,10 +1377,9 @@ bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) { Gis_line_string ls; - if (wkb->reserve(1+4, 512)) + if (wkb->reserve(1 + 4, 512)) return 1; - 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('(') || ls.init_from_wkt(trs, wkb) || @@ -1200,15 +1394,44 @@ bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) } +uint Gis_multi_line_string::init_from_opresult(String *bin, + const char *opres, + uint32 n_shapes) +{ + const char *opres_orig= opres; + + if (bin->reserve(4, 512)) + return 0; + bin->q_append(n_shapes); + + while (n_shapes--) + { + Gis_line_string ls; + int ls_len; + + if (bin->reserve(WKB_HEADER_SIZE, 512)) + return 0; + + bin->q_append((char) wkb_ndr); + bin->q_append((uint32) wkb_linestring); + + if (!(ls_len= ls.init_from_opresult(bin, opres))) + return 0; + opres+= ls_len; + } + return (uint) (opres - opres_orig); +} + + uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) { uint32 n_line_strings; const char *wkb_orig= wkb; - if (len < 4) + if (len < 4 || + (n_line_strings= wkb_get_uint(wkb, bo))< 1) return 0; - n_line_strings= wkb_get_uint(wkb, bo); if (res->reserve(4, 512)) return 0; @@ -1256,7 +1479,7 @@ bool Gis_multi_line_string::get_data_as_wkt(String *txt, return 1; n_points= uint4korr(data + WKB_HEADER_SIZE); data+= WKB_HEADER_SIZE + 4; - if (no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) || + if (no_data(data, n_points * POINT_DATA_SIZE) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; txt->qs_append('('); @@ -1386,6 +1609,35 @@ int Gis_multi_line_string::is_closed(int *closed) const return 0; } + +int Gis_multi_line_string::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_lines; + Gis_line_string ls; + const char *data= m_data; + + if (no_data(data, 4)) + return 1; + n_lines= uint4korr(data); + data+= 4; + + if (trn->start_collection(n_lines)) + return 1; + + while (n_lines--) + { + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + data+= WKB_HEADER_SIZE; + ls.set_data_ptr(data, (uint32) (m_data_end - data)); + if (ls.store_shapes(trn)) + return 1; + data+= ls.get_data_size(); + } + return 0; +} + + const Geometry::Class_info *Gis_multi_line_string::get_class_info() const { return &multilinestring_class; @@ -1436,7 +1688,7 @@ bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) for (;;) { - if (wkb->reserve(1+4, 512)) + if (wkb->reserve(1 + 4, 512)) return 1; wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_polygon); @@ -1491,6 +1743,37 @@ uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len, } +uint Gis_multi_polygon::init_from_opresult(String *bin, + const char *opres, uint32 n_shapes) +{ + Gis_polygon p; + const char *opres_orig= opres; + uint p_len; + uint poly_shapes; + uint n_poly= 0; + uint32 np_pos= bin->length(); + + if (bin->reserve(4, 512)) + return 0; + + bin->q_append(n_shapes); + while (n_shapes) + { + if (bin->reserve(1 + 4, 512)) + return 0; + bin->q_append((char)wkb_ndr); + bin->q_append((uint32)wkb_polygon); + if (!(p_len= p.priv_init_from_opresult(bin, opres, n_shapes, &poly_shapes))) + return 0; + n_shapes-= poly_shapes; + opres+= p_len; + n_poly++; + } + bin->write_at_position(np_pos, n_poly); + return opres - opres_orig; +} + + bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const { uint32 n_polygons; @@ -1517,7 +1800,7 @@ bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const return 1; uint32 n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) || + if (no_data(data, POINT_DATA_SIZE * n_points) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points, 512)) return 1; @@ -1678,6 +1961,35 @@ int Gis_multi_polygon::centroid(String *result) const return create_point(result, res_cx, res_cy); } + +int Gis_multi_polygon::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_polygons; + Gis_polygon p; + const char *data= m_data; + + if (no_data(data, 4)) + return 1; + n_polygons= uint4korr(data); + data+= 4; + + if (trn->start_collection(n_polygons)) + return 1; + + while (n_polygons--) + { + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + data+= WKB_HEADER_SIZE; + p.set_data_ptr(data, (uint32) (m_data_end - data)); + if (p.store_shapes(trn)) + return 1; + data+= p.get_data_size(); + } + return 0; +} + + const Geometry::Class_info *Gis_multi_polygon::get_class_info() const { return &multipolygon_class; @@ -1749,6 +2061,45 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb) } +uint Gis_geometry_collection::init_from_opresult(String *bin, + const char *opres, + uint32 n_shapes) +{ + const char *opres_orig= opres; + Geometry_buffer buffer; + Geometry *geom; + int g_len; + uint32 wkb_type; + + if (bin->reserve(4, 512)) + return 0; + bin->q_append(n_shapes); + + while (n_shapes--) + { + switch ((Gcalc_function::shape_type) uint4korr(opres)) + { + case Gcalc_function::shape_point: wkb_type= wkb_point; break; + case Gcalc_function::shape_line: wkb_type= wkb_linestring; break; + case Gcalc_function::shape_polygon: wkb_type= wkb_polygon; break; + default: wkb_type= 0; DBUG_ASSERT(FALSE); + }; + + if (bin->reserve(WKB_HEADER_SIZE, 512)) + return 0; + + bin->q_append((char) wkb_ndr); + bin->q_append(wkb_type); + + if (!(geom= create_by_typeid(&buffer, wkb_type)) || + !(g_len= geom->init_from_opresult(bin, opres, 1))) + return 0; + opres+= g_len; + } + return (uint) (opres - opres_orig); +} + + uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) { @@ -1898,7 +2249,7 @@ int Gis_geometry_collection::geometry_n(uint32 num, String *result) const } while (--num); /* Copy found object to result */ - if (result->reserve(1+4+length)) + if (result->reserve(1 + 4 + length)) return 1; result->q_append((char) wkb_ndr); result->q_append((uint32) wkb_type); @@ -1959,6 +2310,42 @@ bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const return 0; } + +int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_objects; + const char *data= m_data; + Geometry_buffer buffer; + Geometry *geom; + + if (no_data(data, 4)) + return 1; + n_objects= uint4korr(data); + data+= 4; + + if (trn->start_collection(n_objects)) + return 1; + + while (n_objects--) + { + uint32 wkb_type; + + if (no_data(data, WKB_HEADER_SIZE)) + 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->store_shapes(trn)) + return 1; + + data+= geom->get_data_size(); + } + return 0; +} + + const Geometry::Class_info *Gis_geometry_collection::get_class_info() const { return &geometrycollection_class; diff --git a/sql/spatial.h b/sql/spatial.h index f778acd6c34..6f6c39b5b42 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2002-2006 MySQL AB +/* Copyright (c) 2002, 2010, 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 @@ -10,14 +10,19 @@ 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef _spatial_h #define _spatial_h +#include "sql_string.h" /* String, LEX_STRING */ +#include + #ifdef HAVE_SPATIAL +#include "gcalc_tools.h" + const uint SRID_SIZE= 4; const uint SIZEOF_STORED_DOUBLE= 8; const uint POINT_DATA_SIZE= SIZEOF_STORED_DOUBLE*2; @@ -242,10 +247,13 @@ public: virtual const Class_info *get_class_info() const=0; virtual uint32 get_data_size() const=0; virtual bool init_from_wkt(Gis_read_stream *trs, String *wkb)=0; - /* returns the length of the wkb that was read */ virtual uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res)=0; + virtual uint init_from_opresult(String *bin, + const char *opres, uint32 n_shapes=1) + { return init_from_wkb(opres + 4, UINT_MAX32, wkb_ndr, bin) + 4; } + virtual bool get_data_as_wkt(String *txt, const char **end) const=0; virtual bool get_mbr(MBR *mbr, const char **end) const=0; virtual bool dimension(uint32 *dim, const char **end) const=0; @@ -264,16 +272,20 @@ public: virtual int point_n(uint32 num, String *result) const { return -1; } virtual int interior_ring_n(uint32 num, String *result) const { return -1; } virtual int geometry_n(uint32 num, String *result) const { return -1; } + virtual int store_shapes(Gcalc_shape_transporter *trn) const=0; public: static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id); + static Geometry *construct(Geometry_buffer *buffer, const char *data, uint32 data_len); static Geometry *create_from_wkt(Geometry_buffer *buffer, Gis_read_stream *trs, String *wkt, bool init_stream=1); - static Geometry *create_from_wkb(Geometry_buffer *buffer, const char *wkb, - uint32 len, String *res); + static Geometry *create_from_wkb(Geometry_buffer *buffer, + const char *wkb, uint32 len, String *res); + static int create_from_opresult(Geometry_buffer *g_buf, + String *res, Gcalc_result_receiver &rr); int as_wkt(String *wkt, const char **end) { uint32 len= (uint) get_class_info()->m_name.length; @@ -369,6 +381,7 @@ public: *end= 0; /* No default end */ return 0; } + int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; }; @@ -397,6 +410,7 @@ public: *end= 0; /* No default end */ return 0; } + int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; }; @@ -411,6 +425,13 @@ public: uint32 get_data_size() const; bool init_from_wkt(Gis_read_stream *trs, String *wkb); uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); + uint priv_init_from_opresult(String *bin, const char *opres, + uint32 n_shapes, uint32 *poly_shapes); + uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes) + { + uint32 foo; + return priv_init_from_opresult(bin, opres, n_shapes, &foo); + } bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int area(double *ar, const char **end) const; @@ -425,6 +446,7 @@ public: *end= 0; /* No default end */ return 0; } + int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; }; @@ -439,6 +461,7 @@ public: uint32 get_data_size() const; bool init_from_wkt(Gis_read_stream *trs, String *wkb); uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); + uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int num_geometries(uint32 *num) const; @@ -449,6 +472,7 @@ public: *end= 0; /* No default end */ return 0; } + int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; }; @@ -463,6 +487,7 @@ public: uint32 get_data_size() const; bool init_from_wkt(Gis_read_stream *trs, String *wkb); uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); + uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int num_geometries(uint32 *num) const; @@ -475,6 +500,7 @@ public: *end= 0; /* No default end */ return 0; } + int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; }; @@ -501,7 +527,9 @@ public: *end= 0; /* No default end */ return 0; } + int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; + uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes); }; @@ -515,11 +543,13 @@ public: uint32 get_data_size() const; bool init_from_wkt(Gis_read_stream *trs, String *wkb); uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); + uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int num_geometries(uint32 *num) const; int geometry_n(uint32 num, String *result) const; bool dimension(uint32 *dim, const char **end) const; + int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; }; From e88c96d289b9877a8308c1aef849129f8beba7ae Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 5 May 2011 14:30:59 +0500 Subject: [PATCH 02/40] forgotten h-files added to the NOINST_HEADERS --- sql/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/Makefile.am b/sql/Makefile.am index 54a2fafb2c7..a5945a01152 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -85,7 +85,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ multi_range_read.h sql_handler.h \ sql_join_cache.h \ create_options.h \ - sql_expression_cache.h + sql_expression_cache.h \ + gcalc_slicescan.h gcalc_tools.h plistsort.c mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ From 9d51588e9560e963fa6087513098c940b70b2e3d Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 14 Jun 2011 11:20:48 +0500 Subject: [PATCH 03/40] Precision spatial function tests added. --- mysql-test/r/gis-precise.result | 204 +++++++++++++++++++++++++++++ mysql-test/r/gis-rt-precise.result | 49 +++++++ mysql-test/t/gis-precise.test | 107 +++++++++++++++ mysql-test/t/gis-rt-precise.test | 64 +++++++++ 4 files changed, 424 insertions(+) create mode 100644 mysql-test/r/gis-precise.result create mode 100644 mysql-test/r/gis-rt-precise.result create mode 100644 mysql-test/t/gis-precise.test create mode 100644 mysql-test/t/gis-rt-precise.test diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result new file mode 100644 index 00000000000..3bdc535e6f0 --- /dev/null +++ b/mysql-test/r/gis-precise.result @@ -0,0 +1,204 @@ +DROP TABLE IF EXISTS t1; +select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 0,20 20,0 20,0 0))'), GeomFromText('POLYGON((10 10,30 10,30 30,10 30,10 10))')); +1 ST_Intersects(GeomFromText('POLYGON((0 0,20 0,20 20,0 20,0 0))'), GeomFromText('POLYGON((10 10,30 10,30 30,10 30,10 10))')) +1 1 +select 0, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 40, 40 50, 20 70, 10 40))')); +0 ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 40, 40 50, 20 70, 10 40))')) +0 0 +select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POINT(10 10)')); +1 ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POINT(10 10)')) +1 1 +select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); +1 ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')) +1 1 +select 0, ST_Within(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); +0 ST_Within(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')) +0 0 +select 1, ST_Within(GeomFromText('POLYGON((1 1,20 10,10 30, 1 1))'), GeomFromText('POLYGON((0 0,30 5,10 40, 0 0))')); +1 ST_Within(GeomFromText('POLYGON((1 1,20 10,10 30, 1 1))'), GeomFromText('POLYGON((0 0,30 5,10 40, 0 0))')) +1 1 +create table t1 (g point); +insert into t1 values +(GeomFromText('POINT(2 2)')), (GeomFromText('POINT(2 4)')), (GeomFromText('POINT(2 6)')), (GeomFromText('POINT(2 8)')), +(GeomFromText('POINT(4 2)')), (GeomFromText('POINT(4 4)')), (GeomFromText('POINT(4 6)')), (GeomFromText('POINT(4 8)')), +(GeomFromText('POINT(6 2)')), (GeomFromText('POINT(6 4)')), (GeomFromText('POINT(6 6)')), (GeomFromText('POINT(6 8)')), +(GeomFromText('POINT(8 2)')), (GeomFromText('POINT(8 4)')), (GeomFromText('POINT(8 6)')), (GeomFromText('POINT(8 8)')); +select astext(g) from t1 where ST_Within(g, GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))')); +astext(g) +POINT(4 2) +POINT(4 4) +POINT(4 6) +POINT(6 2) +POINT(6 4) +POINT(6 6) +select 'Contains'; +Contains +Contains +select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); +astext(g) +POINT(4 4) +POINT(6 2) +POINT(6 4) +POINT(6 6) +select 'Intersects'; +Intersects +Intersects +select astext(g) from t1 where ST_Intersects(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); +astext(g) +POINT(4 4) +POINT(6 2) +POINT(6 4) +POINT(6 6) +select 'Contains'; +Contains +Contains +select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); +astext(g) +POINT(4 4) +POINT(6 2) +POINT(6 4) +POINT(6 6) +select 'Contains2'; +Contains2 +Contains2 +select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1), (5.01 3.01, 6 5, 9 5, 8 3, 5.01 3.01))'), g); +astext(g) +POINT(4 4) +POINT(6 2) +POINT(6 6) +POINT(8 4) +DROP TABLE t1; +select 0, ST_Within(GeomFromText('LINESTRING(15 15, 50 50, 60 60)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); +0 ST_Within(GeomFromText('LINESTRING(15 15, 50 50, 60 60)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')) +0 0 +select 1, ST_Within(GeomFromText('LINESTRING(15 15, 16 16)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); +1 ST_Within(GeomFromText('LINESTRING(15 15, 16 16)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')) +1 1 +select 1, ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText('LINESTRING(50 15, 15 50)')); +1 ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText('LINESTRING(50 15, 15 50)')) +1 1 +select 0, ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText('LINESTRING(16 16, 51 51)')); +0 ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText('LINESTRING(16 16, 51 51)')) +0 0 +select 1, ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))')); +1 ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))')) +1 1 +select astext(ST_Union(geometryfromtext('point(1 1)'), geometryfromtext('polygon((0 0, 2 0, 1 2, 0 0))'))); +astext(ST_Union(geometryfromtext('point(1 1)'), geometryfromtext('polygon((0 0, 2 0, 1 2, 0 0))'))) +POLYGON((0 0,1 2,2 0,0 0)) +select astext(ST_Intersection(geometryfromtext('point(1 1)'), geometryfromtext('polygon((0 0, 2 0, 1 2, 0 0))'))); +astext(ST_Intersection(geometryfromtext('point(1 1)'), geometryfromtext('polygon((0 0, 2 0, 1 2, 0 0))'))) +POINT(1 1) +select ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))')); +ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))')) +1 +select ST_contains(GeomFromText('MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)), ((6 6, 6 11, 11 11, 11 6, 6 6)))'), GeomFromText('POINT(5 10)')); +ST_contains(GeomFromText('MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)), ((6 6, 6 11, 11 11, 11 6, 6 6)))'), GeomFromText('POINT(5 10)')) +0 +select ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 15, 15 15, 15 10, 10 10))')); +ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 15, 15 15, 15 10, 10 10))')) +1 +select ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 4, 4 4, 4 10, 10 10))')); +ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 4, 4 4, 4 10, 10 10))')) +0 +select ST_Overlaps(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 4, 4 4, 4 10, 10 10))')); +ST_Overlaps(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 4, 4 4, 4 10, 10 10))')) +1 +select ST_Overlaps(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((1 1, 1 4, 4 4, 4 1, 1 1))')); +ST_Overlaps(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((1 1, 1 4, 4 4, 4 1, 1 1))')) +0 +select ST_DISTANCE(geomfromtext('polygon((0 0, 1 2, 2 1, 0 0))'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')); +ST_DISTANCE(geomfromtext('polygon((0 0, 1 2, 2 1, 0 0))'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')) +0.707106781186547 +select ST_DISTANCE(geomfromtext('polygon((0 0, 1 2, 2 1, 0 0))'), geomfromtext('linestring(0 1, 1 0)')); +ST_DISTANCE(geomfromtext('polygon((0 0, 1 2, 2 1, 0 0))'), geomfromtext('linestring(0 1, 1 0)')) +0 +select ST_DISTANCE(geomfromtext('polygon((0 0, 3 6, 6 3, 0 0))'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')); +ST_DISTANCE(geomfromtext('polygon((0 0, 3 6, 6 3, 0 0))'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')) +0 +select ST_DISTANCE(geomfromtext('polygon((0 0, 3 6, 6 3, 0 0),(2 2, 3 4, 4 3, 2 2))'), geomfromtext('point(3 3)')); +ST_DISTANCE(geomfromtext('polygon((0 0, 3 6, 6 3, 0 0),(2 2, 3 4, 4 3, 2 2))'), geomfromtext('point(3 3)')) +0.447213595499958 +select ST_DISTANCE(geomfromtext('linestring(0 0, 3 6, 6 3, 0 0)'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')); +ST_DISTANCE(geomfromtext('linestring(0 0, 3 6, 6 3, 0 0)'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')) +0.894427190999916 +select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))'))); +astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))'))) +POLYGON((26.4705882352941 23.8235294117647,21.9512195121951 27.4390243902439,23.855421686747 29.8192771084337,29.2899408284024 26.3609467455621,26.4705882352941 23.8235294117647)) +select astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50, 0 0)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45, 50 5)'))); +astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50, 0 0)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45, 50 5)'))) +MULTIPOINT(26.4705882352941 23.8235294117647,29.2899408284024 26.3609467455621,21.9512195121951 27.4390243902439,23.855421686747 29.8192771084337) +select astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45)'))); +astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45)'))) +POINT(29.2899408284024 26.3609467455621) +select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POINT(20 20)'))); +astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POINT(20 20)'))) +POINT(20 20) +select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200)'))); +astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200)'))) +LINESTRING(0 0,46.6666666666667 46.6666666666667) +select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))); +astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))) +MULTILINESTRING((0 0,46.6666666666667 46.6666666666667),(8 10,45.3333333333333 47.3333333333333)) +select astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))); +astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))) +GEOMETRYCOLLECTION(LINESTRING(-10 -10,0 0),LINESTRING(-11 -9,8 10),POLYGON((0 0,40 50,50 45,0 0)),LINESTRING(46.6666666666667 46.6666666666667,200 200,199 201,45.3333333333333 47.3333333333333)) +select astext(ST_intersection(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromtext('polygon((0 0, 1 1, 0 2, 0 0))'))); +astext(ST_intersection(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromtext('polygon((0 0, 1 1, 0 2, 0 0))'))) +POLYGON((0 0,0 1,0.5 0.5,0 0)) +select astext(ST_symdifference(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromtext('polygon((0 0, 1 1, 0 2, 0 0))'))); +astext(ST_symdifference(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromtext('polygon((0 0, 1 1, 0 2, 0 0))'))) +MULTIPOLYGON(((0 0,0 1,0 0,0.5 0.5,1 0,0 0)),((0.5 0.5,0 1,0 2,1 1,0.5 0.5))) +select astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))); +astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))) +GEOMETRYCOLLECTION(LINESTRING(-10 -10,0 0),LINESTRING(-11 -9,8 10),POLYGON((0 0,40 50,50 45,0 0)),LINESTRING(46.6666666666667 46.6666666666667,200 200,199 201,45.3333333333333 47.3333333333333)) +select astext(ST_buffer(geometryfromtext('point(1 1)'), 1)); +astext(ST_buffer(geometryfromtext('point(1 1)'), 1)) +POLYGON((1 0,0.950932325672582 0.00120454379482759,0.901982859670439 0.00481527332780318,0.853269525544638 0.010823490035219,0.804909677983872 0.0192147195967696,0.757019820096736 0.029968746805456,0.709715322745538 0.0430596642677911,0.66311014660778 0.0584559348169792,0.61731656763491 0.0761204674887133,0.572444906569718 0.0960107068765567,0.528603263174002 0.118078735651645,0.485897255806778 0.142271389999728,0.444429766980398 0.168530387697455,0.404300695507567 0.196792468519355,0.365606715836355 0.226989546637263,0.328441045152982 0.259048874645041,0.292893218813453 0.292893218813453,0.259048874645041 0.328441045152982,0.226989546637263 0.365606715836355,0.196792468519355 0.404300695507567,0.168530387697455 0.444429766980398,0.142271389999728 0.485897255806778,0.118078735651645 0.528603263174002,0.0960107068765567 0.572444906569718,0.0761204674887133 0.61731656763491,0.0584559348169792 0.66311014660778,0.0430596642677911 0.709715322745538,0.029968746805456 0.757019820096736,0.0192147195967696 0.804909677983872,0.010823490035219 0.853269525544638,0.00481527332780318 0.901982859670439,0.00120454379482759 0.950932325672582,0 1,0.00481527332780318 1.09801714032956,0.010823490035219 1.14673047445536,0.0192147195967696 1.19509032201613,0.029968746805456 1.24298017990326,0.0430596642677911 1.29028467725446,0.0584559348169792 1.33688985339222,0.0761204674887133 1.38268343236509,0.0960107068765567 1.42755509343028,0.118078735651645 1.471396736826,0.142271389999728 1.51410274419322,0.168530387697455 1.5555702330196,0.196792468519355 1.59569930449243,0.226989546637263 1.63439328416365,0.259048874645041 1.67155895484702,0.292893218813453 1.70710678118655,0.328441045152982 1.74095112535496,0.365606715836355 1.77301045336274,0.404300695507567 1.80320753148064,0.444429766980398 1.83146961230255,0.485897255806778 1.85772861000027,0.528603263174002 1.88192126434835,0.572444906569718 1.90398929312344,0.61731656763491 1.92387953251129,0.66311014660778 1.94154406518302,0.709715322745538 1.95694033573221,0.757019820096736 1.97003125319454,0.804909677983872 1.98078528040323,0.853269525544638 1.98917650996478,0.901982859670439 1.9951847266722,0.950932325672582 1.99879545620517,1 2,1.04906767432742 1.99879545620517,1.09801714032956 1.9951847266722,1.14673047445536 1.98917650996478,1.19509032201613 1.98078528040323,1.24298017990326 1.97003125319454,1.29028467725446 1.95694033573221,1.33688985339222 1.94154406518302,1.38268343236509 1.92387953251129,1.42755509343028 1.90398929312344,1.471396736826 1.88192126434835,1.51410274419322 1.85772861000027,1.5555702330196 1.83146961230255,1.59569930449243 1.80320753148064,1.63439328416365 1.77301045336274,1.67155895484702 1.74095112535496,1.70710678118655 1.70710678118655,1.74095112535496 1.67155895484702,1.77301045336274 1.63439328416365,1.80320753148064 1.59569930449243,1.83146961230255 1.5555702330196,1.85772861000027 1.51410274419322,1.88192126434835 1.471396736826,1.90398929312344 1.42755509343028,1.92387953251129 1.38268343236509,1.94154406518302 1.33688985339222,1.95694033573221 1.29028467725446,1.97003125319454 1.24298017990326,1.98078528040323 1.19509032201613,1.98917650996478 1.14673047445536,1.9951847266722 1.09801714032956,1.99879545620517 1.04906767432742,2 1,1.9951847266722 0.901982859670439,1.98917650996478 0.853269525544638,1.98078528040323 0.804909677983872,1.97003125319454 0.757019820096736,1.95694033573221 0.709715322745538,1.94154406518302 0.66311014660778,1.92387953251129 0.61731656763491,1.90398929312344 0.572444906569718,1.88192126434835 0.528603263174002,1.85772861000027 0.485897255806778,1.83146961230255 0.444429766980398,1.80320753148064 0.404300695507567,1.77301045336274 0.365606715836355,1.74095112535496 0.328441045152982,1.70710678118655 0.292893218813453,1.67155895484702 0.259048874645041,1.63439328416365 0.226989546637263,1.59569930449243 0.196792468519355,1.5555702330196 0.168530387697455,1.51410274419322 0.142271389999728,1.471396736826 0.118078735651645,1.42755509343028 0.0960107068765567,1.38268343236509 0.0761204674887133,1.33688985339222 0.0584559348169792,1.29028467725446 0.0430596642677911,1.24298017990326 0.029968746805456,1.19509032201613 0.0192147195967696,1.14673047445536 0.010823490035219,1.09801714032956 0.00481527332780318,1.04906767432742 0.00120454379482759,1 0)) +create table t1(geom geometrycollection); +insert into t1 values (geomfromtext('POLYGON((0 0, 10 10, 0 8, 0 0))')); +insert into t1 values (geomfromtext('POLYGON((1 1, 10 10, 0 8, 1 1))')); +select astext(geom), area(geom),area(ST_buffer(geom,2)) from t1; +astext(geom) area(geom) area(ST_buffer(geom,2)) +POLYGON((0 0,10 10,0 8,0 0)) 40 101.671508403749 +POLYGON((1 1,10 10,0 8,1 1)) 36 108.555395892665 +select astext(ST_buffer(geom,2)) from t1; +astext(ST_buffer(geom,2)) +POLYGON((1.41421356237309 -1.41421356237309,-1.41421356237309 1.41421356237309,0 2.82842712474619,0 6.00005026122218,-0.0960457772985613 6.00230752900675,-0.193952209526528 6.00942657999767,-0.29139139389354 6.02134109671101,-0.388128590869789 6.03802237603243,-0.483930752074584 6.05943023129893,-0.578567081710303 6.08551308911207,-0.671809592569691 6.11620811358278,-0.763433655277008 6.15144135770856,-0.853218539439872 6.19112794151823,-0.940947945408108 6.23517225655526,-1.02641052535855 6.2834681962069,-1.10940039245046 6.33589941132431,-1.18971761682496 6.39233959051784,-1.26716870725357 6.45265276445223,-1.34156707727553 6.51669363340867,-1.41273349470095 6.58430791732451,-1.48049651339678 6.65533272746751,-1.54469288631567 6.72959695884898,-1.6051679587723 6.80692170243074,-1.66177604102015 6.88712067613267,-1.71438075923078 6.97000067360251,-1.76285538403041 7.05536202966692,-1.80708313580201 7.14299910134239,-1.84695746601768 7.23270076324713,-1.88238231392335 7.32425091622068,-1.91327233795755 7.41742900792569,-1.93955312134675 7.5120105641778,-1.96116135138184 7.60776772972363,-1.978044971944 7.70446981716405,-1.99016330891247 7.8018838627003,-1.99748716815206 7.89977518736424,-1.99999890584435 7.99790796238047,-1.99769247099325 8.09604577729856,-1.99057342000233 8.19395220952653,-1.97865890328899 8.29139139389354,-1.96197762396757 8.38812859086979,-1.94056976870107 8.48393075207458,-1.91448691088793 8.5785670817103,-1.88379188641722 8.67180959256969,-1.84855864229144 8.76343365527701,-1.80887205848177 8.85321853943987,-1.76482774344474 8.94094794540811,-1.7165318037931 9.02641052535855,-1.66410058867569 9.10940039245046,-1.60766040948216 9.18971761682496,-1.54734723554777 9.26716870725357,-1.48330636659133 9.34156707727553,-1.41569208267549 9.41273349470094,-1.34466727253249 9.48049651339678,-1.27040304115102 9.54469288631567,-1.19307829756926 9.6051679587723,-1.11287932386733 9.66177604102015,-1.02999932639749 9.71438075923078,-0.944637970333077 9.76285538403041,-0.857000898657614 9.80708313580201,-0.767299236752872 9.84695746601768,-0.675749083779317 9.88238231392335,-0.582570992074307 9.91327233795755,-0.487989435822199 9.93955312134675,-0.392232270276368 9.96116135138184,-0.295530182835952 9.978044971944,-0.392232270276368 9.96116135138184,9.60776772972363 11.9611613513818,9.60981935596774 11.9615705608065,9.70653905108928 11.9783530199296,9.80396571934088 11.9903694533444,9.90186465134516 11.9975909124103,10 12,10.0981353486548 11.9975909124103,10.1960342806591 11.9903694533444,10.2934609489107 11.9783530199296,10.3901806440323 11.9615705608065,10.4859603598065 11.9400625063891,10.5805693545089 11.9138806714644,10.6737797067844 11.883088130366,10.7653668647302 11.8477590650226,10.8551101868606 11.8079785862469,10.942793473652 11.7638425286967,11.0282054883864 11.7154572200005,11.1111404660392 11.6629392246051,11.1913986089849 11.6064150629613,11.2687865683273 11.5460209067255,11.343117909694 11.4819022507099,11.4142135623731 11.4142135623731,11.4819022507099 11.343117909694,11.5460209067255 11.2687865683273,11.6064150629613 11.1913986089849,11.6629392246051 11.1111404660392,11.7154572200005 11.0282054883864,11.7638425286967 10.942793473652,11.8079785862469 10.8551101868606,11.8477590650226 10.7653668647302,11.883088130366 10.6737797067844,11.9138806714644 10.5805693545089,11.9400625063891 10.4859603598065,11.9615705608065 10.3901806440323,11.9783530199296 10.2934609489107,11.9903694533444 10.1960342806591,11.9975909124103 10.0981353486548,12 10,11.9975909124103 9.90186465134516,11.9903694533444 9.80396571934088,11.9783530199296 9.70653905108928,11.9615705608065 9.60981935596774,11.9400625063891 9.51403964019347,11.9138806714644 9.41943064549108,11.883088130366 9.32622029321556,11.8477590650226 9.23463313526982,11.8079785862469 9.14488981313944,11.7638425286967 9.057206526348,11.7154572200005 8.97179451161356,11.6629392246051 8.8888595339608,11.6064150629613 8.80860139101513,11.5460209067255 8.73121343167271,11.4819022507099 8.65688209030596,11.4142135623731 8.5857864376269,1.41421356237309 -1.41421356237309)) +POLYGON((0.989269849411119 -0.999971215759952,0.891148838068309 -0.997035659307595,0.793290058708828 -0.989289069032301,0.69592926170357 -0.976750107148565,0.599300997740319 -0.959448981113848,0.503638052770599 -0.937427370856167,0.409170887207927 -0.910738328363497,0.316127080728489 -0.879446149876889,0.22473078401177 -0.843626220995187,0.135202178741929 -0.803364835064523,0.0477569471708416 -0.758758985290084,-0.0373942474793394 -0.709916131070988,-0.120046268522338 -0.656953939121177,-0.2 -0.6,-0.277062826370076 -0.539191520735374,-0.351049096533933 -0.474674994280042,-0.421780571086316 -0.406605846597216,-0.489086851709682 -0.335148062225815,-0.552805791678675 -0.260473789227354,-0.61278388648579 -0.182762924466179,-0.668876643647177 -0.102202680222169,-0.720948930797688 -0.0189871331799512,-0.768875301236584 0.0666832431188291,-0.812540296139623 0.154602061233829,-0.851838722709481 0.244557517031431,-0.886675907594418 0.33633289993945,-0.916967924964667 0.429707115021888,-0.942641798697117 0.524455215615996,-0.963635678181181 0.620348945248487,-0.979898987322333 0.717157287525381,-1.97989898732233 7.71715728752538,-1.99016330891247 7.8018838627003,-1.99748716815206 7.89977518736424,-1.99999890584435 7.99790796238047,-1.99769247099325 8.09604577729856,-1.99057342000233 8.19395220952653,-1.97865890328899 8.29139139389354,-1.96197762396757 8.38812859086979,-1.94056976870107 8.48393075207458,-1.91448691088793 8.5785670817103,-1.88379188641722 8.67180959256969,-1.84855864229144 8.76343365527701,-1.80887205848177 8.85321853943987,-1.76482774344474 8.94094794540811,-1.7165318037931 9.02641052535855,-1.66410058867569 9.10940039245046,-1.60766040948216 9.18971761682496,-1.54734723554777 9.26716870725357,-1.48330636659133 9.34156707727553,-1.41569208267549 9.41273349470094,-1.34466727253249 9.48049651339678,-1.27040304115102 9.54469288631567,-1.19307829756926 9.6051679587723,-1.11287932386733 9.66177604102015,-1.02999932639749 9.71438075923078,-0.944637970333077 9.76285538403041,-0.857000898657614 9.80708313580201,-0.767299236752872 9.84695746601768,-0.675749083779317 9.88238231392335,-0.582570992074307 9.91327233795755,-0.487989435822199 9.93955312134675,-0.392232270276368 9.96116135138184,9.60776772972363 11.9611613513818,9.60981935596774 11.9615705608065,9.70653905108928 11.9783530199296,9.80396571934088 11.9903694533444,9.90186465134516 11.9975909124103,10 12,10.0981353486548 11.9975909124103,10.1960342806591 11.9903694533444,10.2934609489107 11.9783530199296,10.3901806440323 11.9615705608065,10.4859603598065 11.9400625063891,10.5805693545089 11.9138806714644,10.6737797067844 11.883088130366,10.7653668647302 11.8477590650226,10.8551101868606 11.8079785862469,10.942793473652 11.7638425286967,11.0282054883864 11.7154572200005,11.1111404660392 11.6629392246051,11.1913986089849 11.6064150629613,11.2687865683273 11.5460209067255,11.343117909694 11.4819022507099,11.4142135623731 11.4142135623731,11.4819022507099 11.343117909694,11.5460209067255 11.2687865683273,11.6064150629613 11.1913986089849,11.6629392246051 11.1111404660392,11.7154572200005 11.0282054883864,11.7638425286967 10.942793473652,11.8079785862469 10.8551101868606,11.8477590650226 10.7653668647302,11.883088130366 10.6737797067844,11.9138806714644 10.5805693545089,11.9400625063891 10.4859603598065,11.9615705608065 10.3901806440323,11.9783530199296 10.2934609489107,11.9903694533444 10.1960342806591,11.9975909124103 10.0981353486548,12 10,11.9975909124103 9.90186465134516,11.9903694533444 9.80396571934088,11.9783530199296 9.70653905108928,11.9615705608065 9.60981935596774,11.9400625063891 9.51403964019347,11.9138806714644 9.41943064549108,11.883088130366 9.32622029321556,11.8477590650226 9.23463313526982,11.8079785862469 9.14488981313944,11.7638425286967 9.057206526348,11.7154572200005 8.97179451161356,11.6629392246051 8.8888595339608,11.6064150629613 8.80860139101513,11.5460209067255 8.73121343167271,11.4819022507099 8.65688209030596,11.4142135623731 8.5857864376269,2.41421356237309 -0.414213562373095,2.40660584659722 -0.421780571086316,2.33514806222581 -0.489086851709682,2.26047378922735 -0.552805791678675,2.18276292446618 -0.61278388648579,2.10220268022217 -0.668876643647177,2.01898713317995 -0.720948930797688,1.93331675688117 -0.768875301236584,1.84539793876617 -0.812540296139623,1.75544248296857 -0.851838722709481,1.66366710006055 -0.886675907594418,1.57029288497811 -0.916967924964667,1.475544784384 -0.942641798697117,1.37965105475151 -0.963635678181181,1.28284271247462 -0.979898987322333,1.18535297732928 -0.991392546384357,1.08741671062655 -0.998088666376754,0.989269849411119 -0.999971215759952)) +set @geom=geomfromtext('LINESTRING(2 1, 4 2, 2 3, 2 5)'); +set @buff=ST_buffer(@geom,1); +select astext(@buff); +astext(@buff) +POLYGON((2.02185940085665 0.000238945250322198,1.97277712041129 0.000370611262904941,1.92376042226731 0.00291047203014849,1.87492739194389 0.0078524088049996,1.82639567248833 0.015184516028905,1.7782821810637 0.0248891300133454,1.73070282728507 0.0369428714932084,1.68377223398316 0.0513167019494863,1.63760346106787 0.0679759935656108,1.59230773315705 0.086880612648897,1.54799417162668 0.107985016316124,1.50476953172789 0.131238362210331,1.46273794540424 0.156584630984506,1.42200067042871 0.1839627612571,1.38265584646488 0.213306796714246,1.34479825863987 0.244546045004294,1.3085191091987 0.277605248041878,1.27390579779004 0.312404763311236,1.24104171091284 0.348860755732007,1.21000602103095 0.386885399625282,1.1808734958397 0.426387090293356,1.15371431814397 0.467270664703471,1.12859391678171 0.509437630743893,1.10557280900008 0.552786404500042,1.08470645466414 0.597212554979035,1.06604512264916 0.642609055693097,1.0496337697385 0.688866542495745,1.0355119323188 0.735873577049592,1.02371363113331 0.783516915291068,1.01426728932301 0.831681780245288,1.00719566395272 0.880252138533831,1.00251579118736 0.929110979909321,1.00023894525032 0.978140599143353,1.0003706112629 1.02722287958871,1.00291047203015 1.07623957773269,1.007852408805 1.12507260805611,1.01518451602891 1.17360432751167,1.02488913001335 1.2217178189363,1.03694287149321 1.26929717271493,1.05131670194949 1.31622776601684,1.06797599356561 1.36239653893213,1.0868806126489 1.40769226684295,1.10798501631612 1.45200582837332,1.13123836221033 1.49523046827211,1.15658463098451 1.53726205459576,1.1839627612571 1.57799932957129,1.21330679671425 1.61734415353512,1.24454604500429 1.65520174136013,1.27760524804188 1.6914808908013,1.31240476331124 1.72609420220996,1.34886075573201 1.75895828908716,1.38688539962528 1.78999397896905,1.42638709029336 1.8191265041603,1.46727066470347 1.84628568185603,1.50943763074389 1.87140608321829,1.55278640450004 1.89442719099992,1.76393202250021 2,1.55278640450004 2.10557280900008,1.528603263174 2.11807873565165,1.48589725580678 2.14227138999973,1.4444297669804 2.16853038769745,1.40430069550757 2.19679246851936,1.36560671583635 2.22698954663726,1.32844104515298 2.25904887464504,1.29289321881345 2.29289321881345,1.25904887464504 2.32844104515298,1.22698954663726 2.36560671583635,1.19679246851936 2.40430069550757,1.16853038769745 2.4444297669804,1.14227138999973 2.48589725580678,1.11807873565165 2.528603263174,1.09601070687656 2.57244490656972,1.07612046748871 2.61731656763491,1.05845593481698 2.66311014660778,1.04305966426779 2.70971532274554,1.02996874680546 2.75701982009674,1.01921471959677 2.80490967798387,1.01082349003522 2.85326952554464,1.0048152733278 2.90198285967044,1.00120454379483 2.95093232567258,1 3,1 5,1.0048152733278 5.09801714032956,1.01082349003522 5.14673047445536,1.01921471959677 5.19509032201613,1.02996874680546 5.24298017990326,1.04305966426779 5.29028467725446,1.05845593481698 5.33688985339222,1.07612046748871 5.38268343236509,1.09601070687656 5.42755509343028,1.11807873565165 5.471396736826,1.14227138999973 5.51410274419322,1.16853038769745 5.5555702330196,1.19679246851936 5.59569930449243,1.22698954663726 5.63439328416365,1.25904887464504 5.67155895484702,1.29289321881345 5.70710678118655,1.32844104515298 5.74095112535496,1.36560671583635 5.77301045336274,1.40430069550757 5.80320753148064,1.4444297669804 5.83146961230254,1.48589725580678 5.85772861000027,1.528603263174 5.88192126434835,1.57244490656972 5.90398929312344,1.61731656763491 5.92387953251129,1.66311014660778 5.94154406518302,1.70971532274554 5.95694033573221,1.75701982009674 5.97003125319454,1.80490967798387 5.98078528040323,1.85326952554464 5.98917650996478,1.90198285967044 5.9951847266722,1.95093232567258 5.99879545620517,2 6,2.04906767432742 5.99879545620517,2.09801714032956 5.9951847266722,2.14673047445536 5.98917650996478,2.19509032201613 5.98078528040323,2.24298017990326 5.97003125319454,2.29028467725446 5.95694033573221,2.33688985339222 5.94154406518302,2.38268343236509 5.92387953251129,2.42755509343028 5.90398929312344,2.471396736826 5.88192126434835,2.51410274419322 5.85772861000027,2.5555702330196 5.83146961230254,2.59569930449243 5.80320753148064,2.63439328416365 5.77301045336274,2.67155895484702 5.74095112535496,2.70710678118655 5.70710678118655,2.74095112535496 5.67155895484702,2.77301045336274 5.63439328416365,2.80320753148064 5.59569930449243,2.83146961230255 5.5555702330196,2.85772861000027 5.51410274419322,2.88192126434835 5.471396736826,2.90398929312344 5.42755509343028,2.92387953251129 5.38268343236509,2.94154406518302 5.33688985339222,2.95694033573221 5.29028467725446,2.97003125319454 5.24298017990326,2.98078528040323 5.19509032201613,2.98917650996478 5.14673047445536,2.9951847266722 5.09801714032956,2.99879545620517 5.04906767432742,3 5,3 3.61803398874989,4.44721359549996 2.89442719099992,4.45200582837332 2.89201498368388,4.49523046827211 2.86876163778967,4.53726205459576 2.84341536901549,4.57799932957129 2.8160372387429,4.61734415353512 2.78669320328575,4.65520174136013 2.75545395499571,4.6914808908013 2.72239475195812,4.72609420220996 2.68759523668876,4.75895828908716 2.65113924426799,4.78999397896905 2.61311460037472,4.8191265041603 2.57361290970664,4.84628568185602 2.53272933529653,4.87140608321829 2.49056236925611,4.89442719099992 2.44721359549996,4.91529354533586 2.40278744502096,4.93395487735084 2.3573909443069,4.9503662302615 2.31113345750426,4.9644880676812 2.26412642295041,4.97628636886669 2.21648308470893,4.98573271067699 2.16831821975471,4.99280433604728 2.11974786146617,4.99748420881264 2.07088902009068,4.99976105474968 2.02185940085665,4.99962938873709 1.97277712041129,4.99708952796985 1.92376042226731,4.992147591195 1.87492739194389,4.9848154839711 1.82639567248833,4.97511086998665 1.7782821810637,4.96305712850679 1.73070282728507,4.94868329805051 1.68377223398316,4.93202400643439 1.63760346106787,4.9131193873511 1.59230773315705,4.89201498368388 1.54799417162668,4.86876163778967 1.50476953172789,4.84341536901549 1.46273794540424,4.8160372387429 1.42200067042871,4.78669320328575 1.38265584646488,4.75545395499571 1.34479825863987,4.72239475195812 1.3085191091987,4.68759523668876 1.27390579779004,4.65113924426799 1.24104171091284,4.61311460037472 1.21000602103095,4.57361290970664 1.1808734958397,4.53272933529653 1.15371431814397,4.49056236925611 1.12859391678171,4.44721359549996 1.10557280900008,2.44721359549996 0.105572809000084,2.3573909443069 0.0660451226491613,2.31113345750426 0.0496337697385035,2.26412642295041 0.0355119323187965,2.21648308470893 0.0237136311333106,2.16831821975471 0.014267289323011,2.11974786146617 0.00719566395272053,2.07088902009068 0.00251579118735756,2.02185940085665 0.000238945250322198)) +DROP TABLE t1; +select st_touches(geomfromtext('point(0 0)'), geomfromtext('point(1 1)')); +st_touches(geomfromtext('point(0 0)'), geomfromtext('point(1 1)')) +0 +select st_touches(geomfromtext('point(1 1)'), geomfromtext('point(1 1)')); +st_touches(geomfromtext('point(1 1)'), geomfromtext('point(1 1)')) +1 +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)')); +st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)')) +1 +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)')); +st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)')) +0 +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 2)')); +st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 2)')) +0 +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')); +st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')) +0 +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')); +st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')) +1 +SELECT ST_Equals(PolyFromText('POLYGON((67 13, 67 18, 67 18, 59 18, 59 13, 67 13) )'),PolyFromText('POLYGON((67 13, 67 18, 59 19, 59 13, 59 13, 67 13) )')) as result; +result +0 +SELECT ST_Equals(PolyFromText('POLYGON((67 13, 67 18, 67 18, 59 18, 59 13, 67 13) )'),PolyFromText('POLYGON((67 13, 67 18, 59 18, 59 13, 59 13, 67 13) )')) as result; +result +1 +SELECT ST_Equals(PointFromText('POINT (12 13)'),PointFromText('POINT (12 13)')) as result; +result +1 diff --git a/mysql-test/r/gis-rt-precise.result b/mysql-test/r/gis-rt-precise.result new file mode 100644 index 00000000000..4519dcb6d19 --- /dev/null +++ b/mysql-test/r/gis-rt-precise.result @@ -0,0 +1,49 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +g GEOMETRY NOT NULL, +SPATIAL KEY(g) +) ENGINE=MyISAM; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `fid` int(11) NOT NULL AUTO_INCREMENT, + `g` geometry NOT NULL, + PRIMARY KEY (`fid`), + SPATIAL KEY `g` (`g`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT count(*) FROM t1; +count(*) +150 +EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE ST_Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 140))')); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range g g 34 NULL 8 Using where +SELECT fid, AsText(g) FROM t1 WHERE ST_Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); +fid AsText(g) +11 LINESTRING(140 140,160 160) +DROP TABLE t1; +CREATE TABLE t1 ( +fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +g GEOMETRY NOT NULL +) ENGINE=MyISAM; +ALTER TABLE t1 ADD SPATIAL KEY(g); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `fid` int(11) NOT NULL AUTO_INCREMENT, + `g` geometry NOT NULL, + PRIMARY KEY (`fid`), + SPATIAL KEY `g` (`g`) +) ENGINE=MyISAM AUTO_INCREMENT=101 DEFAULT CHARSET=latin1 +SELECT count(*) FROM t1; +count(*) +100 +EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE ST_Within(g, +GeomFromText('Polygon((40 40,60 40,60 60,40 40))')); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range g g 34 NULL 1 Using where +SELECT fid, AsText(g) FROM t1 WHERE ST_Within(g, +GeomFromText('Polygon((40 40,60 40,60 60,40 40))')); +fid AsText(g) +DROP TABLE t1; +End of 5.5 tests. diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test new file mode 100644 index 00000000000..f37249aedee --- /dev/null +++ b/mysql-test/t/gis-precise.test @@ -0,0 +1,107 @@ +-- source include/have_geometry.inc + + +# +# Spatial objects +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 0,20 20,0 20,0 0))'), GeomFromText('POLYGON((10 10,30 10,30 30,10 30,10 10))')); +select 0, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 40, 40 50, 20 70, 10 40))')); +select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POINT(10 10)')); +select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); +select 0, ST_Within(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); +select 1, ST_Within(GeomFromText('POLYGON((1 1,20 10,10 30, 1 1))'), GeomFromText('POLYGON((0 0,30 5,10 40, 0 0))')); + + +create table t1 (g point); +insert into t1 values +(GeomFromText('POINT(2 2)')), (GeomFromText('POINT(2 4)')), (GeomFromText('POINT(2 6)')), (GeomFromText('POINT(2 8)')), +(GeomFromText('POINT(4 2)')), (GeomFromText('POINT(4 4)')), (GeomFromText('POINT(4 6)')), (GeomFromText('POINT(4 8)')), +(GeomFromText('POINT(6 2)')), (GeomFromText('POINT(6 4)')), (GeomFromText('POINT(6 6)')), (GeomFromText('POINT(6 8)')), +(GeomFromText('POINT(8 2)')), (GeomFromText('POINT(8 4)')), (GeomFromText('POINT(8 6)')), (GeomFromText('POINT(8 8)')); + +select astext(g) from t1 where ST_Within(g, GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))')); +select 'Contains'; +select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); +select 'Intersects'; +select astext(g) from t1 where ST_Intersects(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); +select 'Contains'; +select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); +select 'Contains2'; +select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1), (5.01 3.01, 6 5, 9 5, 8 3, 5.01 3.01))'), g); + +DROP TABLE t1; + +select 0, ST_Within(GeomFromText('LINESTRING(15 15, 50 50, 60 60)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); +select 1, ST_Within(GeomFromText('LINESTRING(15 15, 16 16)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); + + +select 1, ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText('LINESTRING(50 15, 15 50)')); +select 0, ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText('LINESTRING(16 16, 51 51)')); + +select 1, ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))')); + +select astext(ST_Union(geometryfromtext('point(1 1)'), geometryfromtext('polygon((0 0, 2 0, 1 2, 0 0))'))); +select astext(ST_Intersection(geometryfromtext('point(1 1)'), geometryfromtext('polygon((0 0, 2 0, 1 2, 0 0))'))); + +select ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))')); +select ST_contains(GeomFromText('MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)), ((6 6, 6 11, 11 11, 11 6, 6 6)))'), GeomFromText('POINT(5 10)')); +select ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 15, 15 15, 15 10, 10 10))')); +select ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 4, 4 4, 4 10, 10 10))')); +select ST_Overlaps(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 4, 4 4, 4 10, 10 10))')); +select ST_Overlaps(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((1 1, 1 4, 4 4, 4 1, 1 1))')); + +# Distance tests +select ST_DISTANCE(geomfromtext('polygon((0 0, 1 2, 2 1, 0 0))'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')); +select ST_DISTANCE(geomfromtext('polygon((0 0, 1 2, 2 1, 0 0))'), geomfromtext('linestring(0 1, 1 0)')); +select ST_DISTANCE(geomfromtext('polygon((0 0, 3 6, 6 3, 0 0))'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')); +select ST_DISTANCE(geomfromtext('polygon((0 0, 3 6, 6 3, 0 0),(2 2, 3 4, 4 3, 2 2))'), geomfromtext('point(3 3)')); +select ST_DISTANCE(geomfromtext('linestring(0 0, 3 6, 6 3, 0 0)'), geomfromtext('polygon((2 2, 3 4, 4 3, 2 2))')); + + +# Operations tests +select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))'))); +select astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50, 0 0)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45, 50 5)'))); +select astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45)'))); +select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POINT(20 20)'))); +select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200)'))); +select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))); +select astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))); + +select astext(ST_intersection(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromtext('polygon((0 0, 1 1, 0 2, 0 0))'))); + +select astext(ST_symdifference(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromtext('polygon((0 0, 1 1, 0 2, 0 0))'))); +select astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))); + +# Buffer() tests +select astext(ST_buffer(geometryfromtext('point(1 1)'), 1)); +create table t1(geom geometrycollection); +insert into t1 values (geomfromtext('POLYGON((0 0, 10 10, 0 8, 0 0))')); +insert into t1 values (geomfromtext('POLYGON((1 1, 10 10, 0 8, 1 1))')); +select astext(geom), area(geom),area(ST_buffer(geom,2)) from t1; +select astext(ST_buffer(geom,2)) from t1; + +set @geom=geomfromtext('LINESTRING(2 1, 4 2, 2 3, 2 5)'); +set @buff=ST_buffer(@geom,1); +select astext(@buff); + +# cleanup +DROP TABLE t1; + +#Touches tests +select st_touches(geomfromtext('point(0 0)'), geomfromtext('point(1 1)')); +select st_touches(geomfromtext('point(1 1)'), geomfromtext('point(1 1)')); +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)')); +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)')); +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 2)')); +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')); +select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')); + +#Equals test +SELECT ST_Equals(PolyFromText('POLYGON((67 13, 67 18, 67 18, 59 18, 59 13, 67 13) )'),PolyFromText('POLYGON((67 13, 67 18, 59 19, 59 13, 59 13, 67 13) )')) as result; +SELECT ST_Equals(PolyFromText('POLYGON((67 13, 67 18, 67 18, 59 18, 59 13, 67 13) )'),PolyFromText('POLYGON((67 13, 67 18, 59 18, 59 13, 59 13, 67 13) )')) as result; +SELECT ST_Equals(PointFromText('POINT (12 13)'),PointFromText('POINT (12 13)')) as result; diff --git a/mysql-test/t/gis-rt-precise.test b/mysql-test/t/gis-rt-precise.test new file mode 100644 index 00000000000..4cae10a9076 --- /dev/null +++ b/mysql-test/t/gis-rt-precise.test @@ -0,0 +1,64 @@ +-- source include/have_geometry.inc + +# +# test of rtree (using with spatial data) +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 ( + fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + g GEOMETRY NOT NULL, + SPATIAL KEY(g) +) ENGINE=MyISAM; + +SHOW CREATE TABLE t1; + +--disable_query_log +let $1=150; +let $2=150; +while ($1) +{ + eval INSERT INTO t1 (g) VALUES (GeomFromText('LineString($1 $1, $2 $2)')); + dec $1; + inc $2; +} +--enable_query_log + +SELECT count(*) FROM t1; +EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE ST_Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 140))')); +SELECT fid, AsText(g) FROM t1 WHERE ST_Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); + +DROP TABLE t1; + +CREATE TABLE t1 ( + fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + g GEOMETRY NOT NULL +) ENGINE=MyISAM; + +--disable_query_log +let $1=10; +while ($1) +{ + let $2=10; + while ($2) + { + eval INSERT INTO t1 (g) VALUES (LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10))); + dec $2; + } + dec $1; +} +--enable_query_log + +ALTER TABLE t1 ADD SPATIAL KEY(g); +SHOW CREATE TABLE t1; +SELECT count(*) FROM t1; +EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE ST_Within(g, + GeomFromText('Polygon((40 40,60 40,60 60,40 40))')); +SELECT fid, AsText(g) FROM t1 WHERE ST_Within(g, + GeomFromText('Polygon((40 40,60 40,60 60,40 40))')); + +DROP TABLE t1; + +--echo End of 5.5 tests. From 4f49cdf8d303b431343bbc77428169fdfcaae34c Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 30 Jun 2011 18:18:27 +0500 Subject: [PATCH 04/40] fix for bug #801243 Assertion `(0)' failed in Gis_geometry_collection::init_from_opresult on ST_UNION If the result contains a polygon with a hole, consequitive shapes weren't calculated properly, as the hole appeared as shape in the result, but actually it's a single shape with the surrounding polygon. It's more natural to use the size of the result as a border instead of the number of resulting shapes. per-file comments: mysql-test/r/gis-precise.result fix for bug #801243 Assertion `(0)' failed in Gis_geometry_collection::init_from_opresult on ST_UNION test result updated. mysql-test/t/gis-precise.test fix for bug #801243 Assertion `(0)' failed in Gis_geometry_collection::init_from_opresult on ST_UNION test case added. sql/spatial.cc fix for bug #801243 Assertion `(0)' failed in Gis_geometry_collection::init_from_opresult on ST_UNION check the data lenght instead of number of shapes. sql/spatial.h fix for bug #801243 Assertion `(0)' failed in Gis_geometry_collection::init_from_opresult on ST_UNION check the data lenght instead of number of shapes. --- mysql-test/r/gis-precise.result | 7 ++++ mysql-test/t/gis-precise.test | 6 +++ sql/spatial.cc | 73 ++++++++++++++++++--------------- sql/spatial.h | 18 +++----- 4 files changed, 59 insertions(+), 45 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 3bdc535e6f0..b60ec2e2e8d 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -202,3 +202,10 @@ result SELECT ST_Equals(PointFromText('POINT (12 13)'),PointFromText('POINT (12 13)')) as result; result 1 +SELECT astext(ST_UNION ( +PolyFromText('POLYGON(( 2 2 ,3 2,2 7,2 2),( 0 0,8 2,1 9,0 0))'), +ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0,0 5))'))))); +astext(ST_UNION ( +PolyFromText('POLYGON(( 2 2 ,3 2,2 7,2 2),( 0 0,8 2,1 9,0 0))'), +ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0,0 5))'))))) +GEOMETRYCOLLECTION(POLYGON((0 0,1 9,8 2,0 0),(2 2,2 7,3 2,2 2)),LINESTRING(0 0,5 0,5 1.25),LINESTRING(0 0,0 5,0.555555555555556 5),LINESTRING(2.4 5,2 5)) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index f37249aedee..b5c54c6b0c4 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -105,3 +105,9 @@ select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('p SELECT ST_Equals(PolyFromText('POLYGON((67 13, 67 18, 67 18, 59 18, 59 13, 67 13) )'),PolyFromText('POLYGON((67 13, 67 18, 59 19, 59 13, 59 13, 67 13) )')) as result; SELECT ST_Equals(PolyFromText('POLYGON((67 13, 67 18, 67 18, 59 18, 59 13, 67 13) )'),PolyFromText('POLYGON((67 13, 67 18, 59 18, 59 13, 59 13, 67 13) )')) as result; SELECT ST_Equals(PointFromText('POINT (12 13)'),PointFromText('POINT (12 13)')) as result; + +# bug #801243 Assertion `(0)' failed in Gis_geometry_collection::init_from_opresult on ST_UNION + +SELECT astext(ST_UNION ( + PolyFromText('POLYGON(( 2 2 ,3 2,2 7,2 2),( 0 0,8 2,1 9,0 0))'), + ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0,0 5))'))))); diff --git a/sql/spatial.cc b/sql/spatial.cc index 48f6f466a30..7fb8c0f251d 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -275,7 +275,7 @@ int Geometry::create_from_opresult(Geometry_buffer *g_buf, res->q_append((char) wkb_ndr); res->q_append(geom_type); - return obj->init_from_opresult(res, rr.result(), rr.get_nshapes()); + return obj->init_from_opresult(res, rr.result(), rr.length()); } @@ -789,19 +789,18 @@ bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) } -uint Gis_polygon::priv_init_from_opresult(String *bin, - const char *opres, uint32 n_shapes, - uint32 *poly_shapes) +uint Gis_polygon::init_from_opresult(String *bin, + const char *opres, uint res_len) { const char *opres_orig= opres; uint32 position= bin->length(); + uint32 poly_shapes= 0; - *poly_shapes= 0; if (bin->reserve(4, 512)) return 0; - bin->q_append(*poly_shapes); + bin->q_append(poly_shapes); - while (n_shapes--) + while (opres_orig + res_len > opres) { uint32 n_points, proper_length; const char *op_end, *p1_position; @@ -809,9 +808,9 @@ uint Gis_polygon::priv_init_from_opresult(String *bin, Gcalc_function::shape_type st; st= (Gcalc_function::shape_type) uint4korr(opres); - if (*poly_shapes && st != Gcalc_function::shape_hole) + if (poly_shapes && st != Gcalc_function::shape_hole) break; - (*poly_shapes)++; + poly_shapes++; n_points= uint4korr(opres + 4) + 1; /* skip shape type id */ proper_length= 4 + n_points * POINT_DATA_SIZE; @@ -830,7 +829,7 @@ uint Gis_polygon::priv_init_from_opresult(String *bin, return 0; } - bin->write_at_position(position, *poly_shapes); + bin->write_at_position(position, poly_shapes); return (uint) (opres - opres_orig); } @@ -1202,20 +1201,20 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) uint Gis_multi_point::init_from_opresult(String *bin, - const char *opres, uint32 n_shapes) + const char *opres, uint res_len) { - uint bin_size, opres_size; + uint bin_size, n_points; Gis_point p; const char *opres_end; - bin_size= n_shapes * (WKB_HEADER_SIZE + POINT_DATA_SIZE) + 4; - opres_size= n_shapes * (4 + 8*2); + n_points= res_len/(4+8*2); + bin_size= n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE) + 4; if (bin->reserve(bin_size, 512)) return 0; - bin->q_append(n_shapes); - opres_end= opres + opres_size; + bin->q_append(n_points); + opres_end= opres + res_len; for (; opres < opres_end; opres+= (4 + 8*2)) { bin->q_append((char)wkb_ndr); @@ -1223,7 +1222,7 @@ uint Gis_multi_point::init_from_opresult(String *bin, if (!p.init_from_wkb(opres + 4, POINT_DATA_SIZE, wkb_ndr, bin)) return 0; } - return opres_size; + return res_len; } @@ -1395,16 +1394,17 @@ bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) uint Gis_multi_line_string::init_from_opresult(String *bin, - const char *opres, - uint32 n_shapes) + const char *opres, uint res_len) { const char *opres_orig= opres; + int ns_pos= bin->length(); + uint n_linestring= 0; if (bin->reserve(4, 512)) return 0; - bin->q_append(n_shapes); + bin->q_append(n_linestring); - while (n_shapes--) + while (res_len) { Gis_line_string ls; int ls_len; @@ -1415,10 +1415,13 @@ uint Gis_multi_line_string::init_from_opresult(String *bin, bin->q_append((char) wkb_ndr); bin->q_append((uint32) wkb_linestring); - if (!(ls_len= ls.init_from_opresult(bin, opres))) + if (!(ls_len= ls.init_from_opresult(bin, opres, res_len))) return 0; opres+= ls_len; + res_len-= ls_len; + n_linestring++; } + bin->write_at_position(ns_pos, n_linestring); return (uint) (opres - opres_orig); } @@ -1744,29 +1747,28 @@ uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len, uint Gis_multi_polygon::init_from_opresult(String *bin, - const char *opres, uint32 n_shapes) + const char *opres, uint res_len) { Gis_polygon p; const char *opres_orig= opres; uint p_len; - uint poly_shapes; - uint n_poly= 0; + uint32 n_poly= 0; uint32 np_pos= bin->length(); if (bin->reserve(4, 512)) return 0; - bin->q_append(n_shapes); - while (n_shapes) + bin->q_append(n_poly); + while (res_len) { if (bin->reserve(1 + 4, 512)) return 0; bin->q_append((char)wkb_ndr); bin->q_append((uint32)wkb_polygon); - if (!(p_len= p.priv_init_from_opresult(bin, opres, n_shapes, &poly_shapes))) + if (!(p_len= p.init_from_opresult(bin, opres, res_len))) return 0; - n_shapes-= poly_shapes; opres+= p_len; + res_len-= p_len; n_poly++; } bin->write_at_position(np_pos, n_poly); @@ -2063,19 +2065,21 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb) uint Gis_geometry_collection::init_from_opresult(String *bin, const char *opres, - uint32 n_shapes) + uint res_len) { const char *opres_orig= opres; Geometry_buffer buffer; Geometry *geom; int g_len; uint32 wkb_type; + int no_pos= bin->length(); + uint32 n_objects= 0; if (bin->reserve(4, 512)) return 0; - bin->q_append(n_shapes); + bin->q_append(n_objects); - while (n_shapes--) + while (res_len) { switch ((Gcalc_function::shape_type) uint4korr(opres)) { @@ -2092,10 +2096,13 @@ uint Gis_geometry_collection::init_from_opresult(String *bin, bin->q_append(wkb_type); if (!(geom= create_by_typeid(&buffer, wkb_type)) || - !(g_len= geom->init_from_opresult(bin, opres, 1))) + !(g_len= geom->init_from_opresult(bin, opres, res_len))) return 0; opres+= g_len; + res_len-= g_len; + n_objects++; } + bin->write_at_position(no_pos, n_objects); return (uint) (opres - opres_orig); } diff --git a/sql/spatial.h b/sql/spatial.h index 6f6c39b5b42..e8f230f9127 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -251,7 +251,7 @@ public: virtual uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res)=0; virtual uint init_from_opresult(String *bin, - const char *opres, uint32 n_shapes=1) + const char *opres, uint res_len) { return init_from_wkb(opres + 4, UINT_MAX32, wkb_ndr, bin) + 4; } virtual bool get_data_as_wkt(String *txt, const char **end) const=0; @@ -425,13 +425,7 @@ public: uint32 get_data_size() const; bool init_from_wkt(Gis_read_stream *trs, String *wkb); uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); - uint priv_init_from_opresult(String *bin, const char *opres, - uint32 n_shapes, uint32 *poly_shapes); - uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes) - { - uint32 foo; - return priv_init_from_opresult(bin, opres, n_shapes, &foo); - } + uint init_from_opresult(String *bin, const char *opres, uint res_len); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int area(double *ar, const char **end) const; @@ -461,7 +455,7 @@ public: uint32 get_data_size() const; bool init_from_wkt(Gis_read_stream *trs, String *wkb); uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); - uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes); + uint init_from_opresult(String *bin, const char *opres, uint res_len); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int num_geometries(uint32 *num) const; @@ -487,7 +481,7 @@ public: uint32 get_data_size() const; bool init_from_wkt(Gis_read_stream *trs, String *wkb); uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); - uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes); + uint init_from_opresult(String *bin, const char *opres, uint res_len); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int num_geometries(uint32 *num) const; @@ -529,7 +523,7 @@ public: } int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; - uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes); + uint init_from_opresult(String *bin, const char *opres, uint res_len); }; @@ -543,7 +537,7 @@ public: uint32 get_data_size() const; bool init_from_wkt(Gis_read_stream *trs, String *wkb); uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); - uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes); + uint init_from_opresult(String *bin, const char *opres, uint res_len); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int num_geometries(uint32 *num) const; From a9a6597d598c735ba6b8a136864b888d8d626b70 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 30 Jun 2011 19:24:52 +0500 Subject: [PATCH 05/40] fix for bug #201189 ST_BUFFER asserts if radius = 0. Internal caclucations can't handle zero distance properly. As the ST_BUFFER(geom, 0) is in fact NOOP, we'll just return the 'geom' as the result here. per-file comments: mysql-test/r/gis-precise.result fix for bug #201189 ST_BUFFER asserts if radius = 0. test result updated. mysql-test/t/gis-precise.test fix for bug #201189 ST_BUFFER asserts if radius = 0. test case added. sql/item_geofunc.cc fix for bug #201189 ST_BUFFER asserts if radius = 0. return the first argument as the result of the ST_BUFFER, if the distance is 0 there. --- mysql-test/r/gis-precise.result | 3 +++ mysql-test/t/gis-precise.test | 3 +++ sql/item_geofunc.cc | 12 ++++++++++++ 3 files changed, 18 insertions(+) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index b60ec2e2e8d..48c00c4a468 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -209,3 +209,6 @@ astext(ST_UNION ( PolyFromText('POLYGON(( 2 2 ,3 2,2 7,2 2),( 0 0,8 2,1 9,0 0))'), ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0,0 5))'))))) GEOMETRYCOLLECTION(POLYGON((0 0,1 9,8 2,0 0),(2 2,2 7,3 2,2 2)),LINESTRING(0 0,5 0,5 1.25),LINESTRING(0 0,0 5,0.555555555555556 5),LINESTRING(2.4 5,2 5)) +SELECT astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)); +astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)) +LINESTRING(0 0,1 1) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index b5c54c6b0c4..e75316a0805 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -111,3 +111,6 @@ SELECT ST_Equals(PointFromText('POINT (12 13)'),PointFromText('POINT (12 13)')) SELECT astext(ST_UNION ( PolyFromText('POLYGON(( 2 2 ,3 2,2 7,2 2),( 0 0,8 2,1 9,0 0))'), ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0,0 5))'))))); + +#bug 801189 ST_BUFFER asserts if radius = 0 +SELECT astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 9432de95182..f65df790dfb 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1406,6 +1406,18 @@ String *Item_func_buffer::val_str(String *str_value) !(g= Geometry::construct(&buffer, obj->ptr(), obj->length()))) goto mem_error; + /* + If the distance given is 0, the Buffer function is in fact NOOP, + so it's natural just to return the argument1. + Besides, internal calculations here can't handle zero distance anyway. + */ + if (fabs(dist) < GIS_ZERO) + { + null_value= 0; + str_result= obj; + goto mem_error; + } + if (func.reserve_op_buffer(2)) goto mem_error; /* will specify operands later */ From 0e6c889c83bcf6c37526e3a3fee192bb59cab92e Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 4 Jul 2011 16:03:36 +0500 Subject: [PATCH 06/40] bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT Collections were treated mistakenly, so the counter for the final UNION operation received the wrong value. As a fix we implement Item_func_buffer::Transporter::start_collection() method, where we set the proper operation and the operand counter. start_poly() and start_line() were also modified to function correctly for the polygon as a part of a collection. per-file comments: mysql-test/r/gis-precise.result bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT test result updated. mysql-test/t/gis-precise.test bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT test case added. sql/item_geofunc.cc bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT start_collection() implemented. sql/item_geofunc.h bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT Item_func_buffer::Transporter::start_collection() defined. --- mysql-test/r/gis-precise.result | 3 ++ mysql-test/t/gis-precise.test | 3 ++ sql/item_geofunc.cc | 60 ++++++++++++++++++++++++++------- sql/item_geofunc.h | 15 +++++++-- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 48c00c4a468..e4cc9028236 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -212,3 +212,6 @@ GEOMETRYCOLLECTION(POLYGON((0 0,1 9,8 2,0 0),(2 2,2 7,3 2,2 2)),LINESTRING(0 0,5 SELECT astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)); astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)) LINESTRING(0 0,1 1) +SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5); +Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5) +78.68426 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index e75316a0805..e267bcf57c1 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -114,3 +114,6 @@ SELECT astext(ST_UNION ( #bug 801189 ST_BUFFER asserts if radius = 0 SELECT astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)); + +#buf 801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT +SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index f65df790dfb..8cae6dd6564 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1284,6 +1284,18 @@ int Item_func_buffer::Transporter::add_point_buffer(double x, double y) int Item_func_buffer::Transporter::start_line() { + if (buffer_op == Gcalc_function::op_difference) + { + skip_line= TRUE; + return 0; + } + + m_nshapes= 0; + + if (m_fn->reserve_op_buffer(2)) + return 1; + last_shape_pos= m_fn->get_next_operation_pos(); + m_fn->add_operation(buffer_op, 0); m_npoints= 0; int_start_line(); return 0; @@ -1292,11 +1304,25 @@ int Item_func_buffer::Transporter::start_line() int Item_func_buffer::Transporter::start_poly() { - ++m_nshapes; + m_nshapes= 1; + + if (m_fn->reserve_op_buffer(2)) + return 1; + last_shape_pos= m_fn->get_next_operation_pos(); + m_fn->add_operation(buffer_op, 0); return Gcalc_operation_transporter::start_poly(); } +int Item_func_buffer::Transporter::complete_poly() +{ + if (Gcalc_operation_transporter::complete_poly()) + return 1; + m_fn->add_operands_to_op(last_shape_pos, m_nshapes); + return 0; +} + + int Item_func_buffer::Transporter::start_ring() { m_npoints= 0; @@ -1304,8 +1330,20 @@ int Item_func_buffer::Transporter::start_ring() } +int Item_func_buffer::Transporter::start_collection(int n_objects) +{ + if (m_fn->reserve_op_buffer(1)) + return 1; + m_fn->add_operation(Gcalc_function::op_union, n_objects); + return 0; +} + + int Item_func_buffer::Transporter::add_point(double x, double y) { + if (skip_line) + return 0; + if (m_npoints && x == x2 && y == y2) return 0; @@ -1374,9 +1412,14 @@ int Item_func_buffer::Transporter::complete() int Item_func_buffer::Transporter::complete_line() { - if (complete()) - return 1; - int_complete_line(); + if (!skip_line) + { + if (complete()) + return 1; + int_complete_line(); + m_fn->add_operands_to_op(last_shape_pos, m_nshapes); + } + skip_line= FALSE; return 0; } @@ -1396,7 +1439,6 @@ String *Item_func_buffer::val_str(String *str_value) double dist= args[1]->val_real(); Geometry_buffer buffer; Geometry *g; - uint32 union_pos; uint32 srid= 0; String *str_result= NULL; Transporter trn(&func, &collector, dist); @@ -1418,17 +1460,9 @@ String *Item_func_buffer::val_str(String *str_value) goto mem_error; } - if (func.reserve_op_buffer(2)) - goto mem_error; - /* will specify operands later */ - union_pos= func.get_next_operation_pos(); - func.add_operation((dist > 0.0) ? Gcalc_function::op_union : - Gcalc_function::op_difference, 0); - if (g->store_shapes(&trn)) goto mem_error; - func.add_operands_to_op(union_pos, trn.m_nshapes); collector.prepare_operation(); if (func.alloc_states()) goto mem_error; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 1838a3783e8..d5ed2c1f764 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -26,6 +26,7 @@ #endif #include "gcalc_slicescan.h" +#include "gcalc_tools.h" class Item_geometry_func: public Item_str_func { @@ -298,18 +299,28 @@ protected: int add_last_edge_buffer(); int add_point_buffer(double x, double y); int complete(); - public: int m_nshapes; + Gcalc_function::op_type buffer_op; + int last_shape_pos; + bool skip_line; + + public: Transporter(Gcalc_function *fn, Gcalc_heap *heap, double d) : - Gcalc_operation_transporter(fn, heap), m_npoints(0), m_d(d), m_nshapes(0) + Gcalc_operation_transporter(fn, heap), m_npoints(0), m_d(d), + m_nshapes(0), buffer_op((d > 0.0) ? Gcalc_function::op_union : + Gcalc_function::op_difference), + skip_line(FALSE) {} int single_point(double x, double y); int start_line(); int complete_line(); int start_poly(); + int complete_poly(); int start_ring(); int complete_ring(); int add_point(double x, double y); + + int start_collection(int n_objects); }; Gcalc_heap collector; Gcalc_function func; From 7f55ea121191131723c99889943f8a278c5a7b4b Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 4 Jul 2011 16:17:34 +0500 Subject: [PATCH 07/40] fix for bug #801212 Assertion with ST_INTERSECTION on NULL values The ::val_str() method has to return NULL if it calculated the null_value, not just set the related flag. per-file comments: mysql-test/r/gis-precise.result fix for bug #801212 Assertion with ST_INTERSECTION on NULL values test result updated. mysql-test/t/gis-precise.test fix for bug #801212 Assertion with ST_INTERSECTION on NULL values test case added. sql/item_geofunc.cc fix for bug #801212 Assertion with ST_INTERSECTION on NULL values return NULL from the val_str if we get the null_value. --- mysql-test/r/gis-precise.result | 3 +++ mysql-test/t/gis-precise.test | 6 +++++- sql/item_geofunc.cc | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index e4cc9028236..4f07333e6a3 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -215,3 +215,6 @@ LINESTRING(0 0,1 1) SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5); Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5) 78.68426 +SELECT ST_INTERSECTION(NULL, NULL); +ST_INTERSECTION(NULL, NULL) +NULL diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index e267bcf57c1..72ba6b748be 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -115,5 +115,9 @@ SELECT astext(ST_UNION ( #bug 801189 ST_BUFFER asserts if radius = 0 SELECT astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)); -#buf 801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT +#bug 801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5); + +#bug 801212 Assertion with ST_INTERSECTION on NULL values +SELECT ST_INTERSECTION(NULL, NULL); + diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 8cae6dd6564..b1fe72e99e0 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1014,7 +1014,10 @@ String *Item_func_spatial_operation::val_str(String *str_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)))) + { + str_value= 0; goto exit; + } collector.prepare_operation(); From f3b850a7b52b5947eb694b5a1f73d0425de5bb0e Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 5 Jul 2011 19:42:35 +0500 Subject: [PATCH 08/40] bug #804305 Crash in wkb_get_double with ST_INTERSECTION. That crash happened with the complicated topology of the result. If we found a hole in a polygon whose outside border was already found, we need to paste the hole right after it and respectively shift polygons after it. Also we need to update poly_position fields in these polygons. That last thing wasn't properly done that led to the crash. To fix that we keep the list of the found polygons and update the poly_positions that are bigger or equal to where we placed the next hole. per-file comments: mysql-test/r/gis-precise.result bug #804305 Crash in wkb_get_double with ST_INTERSECTION. test result updated. mysql-test/t/gis-precise.test bug #804305 Crash in wkb_get_double with ST_INTERSECTION. test result added. sql/gcalc_tools.cc bug #804305 Crash in wkb_get_double with ST_INTERSECTION. keep the list of the found polygons and update their poly_position fields respectively. sql/gcalc_tools.h bug #804305 Crash in wkb_get_double with ST_INTERSECTION. Gcalc_result_receiver::move_hole interface changed. --- mysql-test/r/gis-precise.result | 14 +++++++++++++ mysql-test/t/gis-precise.test | 9 +++++++++ sql/gcalc_tools.cc | 35 +++++++++++++++++++++------------ sql/gcalc_tools.h | 11 ++++++++++- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 4f07333e6a3..75028e484dd 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -218,3 +218,17 @@ Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), SELECT ST_INTERSECTION(NULL, NULL); ST_INTERSECTION(NULL, NULL) NULL +SELECT ASTEXT(ST_INTERSECTION( +MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)), + ((0 5,3 5,3 0,0 0,0 1,2 1,2 2,0 2,0 5), (1 3,2 3,2 4,1 4,1 3)), + ((2 2,5 2,4 4,2 8,2 2)))'), +MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((3 5,2 4,2 5,3 5)), + ((2 2,9 2,0 2,2 6,2 2)), + ((2 2,2 8,8 8,8 2,2 2), (4 4,4 6,6 6,6 4,4 4)), + ((9 9,6 8,7 0,9 9)))'))); +ASTEXT(ST_INTERSECTION( +MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)), + ((0 5,3 5,3 0,0 0,0 1,2 1,2 2,0 2,0 5), (1 3,2 3,2 4,1 4,1 3)), + ((2 2,5 2,4 4,2 8,2 2)))'), +MULTIPOLY +MULTIPOLYGON(((2 2,3 2,2 2)),((5 2,0 2,5 2)),((2 2,0 2,1.5 5,2 5,2 2),(1 3,1 4,2 4,2 3,1 3)),((2 2,2 8,8 8,8 2,5 2,2 2),(6 4,4 4,4 6,6 6,6 4))) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 72ba6b748be..87b56dc0040 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -121,3 +121,12 @@ SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 #bug 801212 Assertion with ST_INTERSECTION on NULL values SELECT ST_INTERSECTION(NULL, NULL); +#bug 804305 Crash in wkb_get_double with ST_INTERSECTION +SELECT ASTEXT(ST_INTERSECTION( + MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)), + ((0 5,3 5,3 0,0 0,0 1,2 1,2 2,0 2,0 5), (1 3,2 3,2 4,1 4,1 3)), + ((2 2,5 2,4 4,2 8,2 2)))'), + MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((3 5,2 4,2 5,3 5)), + ((2 2,9 2,0 2,2 6,2 2)), + ((2 2,2 8,8 8,8 2,2 2), (4 4,4 6,6 6,6 4,4 4)), + ((9 9,6 8,7 0,9 9)))'))); diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 0e2970116ce..11d452cd8cf 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -419,17 +419,16 @@ int Gcalc_result_receiver::get_result_typeid() int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_position, - uint32 *new_dest_position) + uint32 *position_shift) { char *ptr; int source_len; - if (dest_position == source_position) - { - *new_dest_position= position(); - return 0; - } - source_len= buffer.length() - source_position; + *position_shift= source_len= buffer.length() - source_position; + + if (dest_position == source_position) + return 0; + if (buffer.reserve(source_len, MY_ALIGN(source_len, 512))) return 1; @@ -437,7 +436,6 @@ int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_positio memmove(ptr + dest_position + source_len, ptr + dest_position, buffer.length() - dest_position); memcpy(ptr + dest_position, ptr + buffer.length(), source_len); - *new_dest_position= dest_position + source_len; return 0; } @@ -1098,6 +1096,8 @@ int Gcalc_operation_reducer::get_line_result(res_point *cur, int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) { + poly_instance *polygons= NULL; + *m_res_hook= NULL; while (m_result) { @@ -1112,19 +1112,28 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) { if (m_result->outer_poly) { - uint32 *insert_position, hole_position; - insert_position= &m_result->outer_poly->first_poly_node->poly_position; - DBUG_ASSERT(*insert_position); + uint32 insert_position, hole_position, position_shift; + poly_instance *cur_poly; + insert_position= m_result->outer_poly->first_poly_node->poly_position; + DBUG_ASSERT(insert_position); hole_position= storage->position(); storage->start_shape(Gcalc_function::shape_hole); if (get_polygon_result(m_result, storage) || - storage->move_hole(*insert_position, hole_position, - insert_position)) + storage->move_hole(insert_position, hole_position, + &position_shift)) return 1; + for (cur_poly= polygons; + cur_poly && *cur_poly->after_poly_position >= insert_position; + cur_poly= cur_poly->get_next()) + *cur_poly->after_poly_position+= position_shift; } else { uint32 *poly_position= &m_result->poly_position; + poly_instance *p= new_poly(); + p->after_poly_position= poly_position; + p->next= polygons; + polygons= p; storage->start_shape(Gcalc_function::shape_polygon); if (get_polygon_result(m_result, storage)) return 1; diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index 7df236618fb..32835d68666 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -170,7 +170,7 @@ public: int get_result_typeid(); uint32 position() { return buffer.length(); } int move_hole(uint32 dest_position, uint32 source_position, - uint32 *new_dest_position); + uint32 *position_shift); }; @@ -233,6 +233,13 @@ public: active_thread *get_next() { return (active_thread *)next; } }; + class poly_instance : public Gcalc_dyn_list::Item + { + public: + uint32 *after_poly_position; + poly_instance *get_next() { return (poly_instance *)next; } + }; + protected: Gcalc_function *m_fn; Gcalc_dyn_list::Item **m_res_hook; @@ -253,6 +260,8 @@ protected: active_thread *new_active_thread() { return (active_thread *)new_item(); } + poly_instance *new_poly() { return (poly_instance *) new_item(); } + private: int continue_range(active_thread *t, const Gcalc_heap::Info *p); int continue_i_range(active_thread *t, const Gcalc_heap::Info *p, From 13f6e1119f831ecde5a8e82e8a68f2848b2b54a1 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 7 Jul 2011 16:59:45 +0500 Subject: [PATCH 09/40] Fix for bug #804324 Assertion 0 in Gcalc_scan_iterator::pop_suitable_intersection There were actually two bugs. One was when the line that intersects itself the intersection point treated as it doesn't belong to the line. Second when edges partly coincide, wrong result produced when we try to find their intersection. per-file comments: mysql-test/r/gis-precise.result Fix for bug #804324 Assertion 0 in Gcalc_scan_iterator::pop_suitable_intersection test result updated. mysql-test/t/gis-precise.test Fix for bug #804324 Assertion 0 in Gcalc_scan_iterator::pop_suitable_intersection test case added. sql/gcalc_slicescan.cc Fix for bug #804324 Assertion 0 in Gcalc_scan_iterator::pop_suitable_intersection skip the intersection if it just line that intersects itself. sql/gcalc_tools.cc Fix for bug #804324 Assertion 0 in Gcalc_scan_iterator::pop_suitable_intersection if edges coincide, just pick the first coinciding poing as an intersection. --- mysql-test/r/gis-precise.result | 26 ++++++++++++++++++++++++++ mysql-test/t/gis-precise.test | 21 +++++++++++++++++++++ sql/gcalc_slicescan.cc | 5 +++++ sql/gcalc_tools.cc | 3 ++- 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 75028e484dd..4be2a093119 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -232,3 +232,29 @@ MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)) ((2 2,5 2,4 4,2 8,2 2)))'), MULTIPOLY MULTIPOLYGON(((2 2,3 2,2 2)),((5 2,0 2,5 2)),((2 2,0 2,1.5 5,2 5,2 2),(1 3,1 4,2 4,2 3,1 3)),((2 2,2 8,8 8,8 2,5 2,2 2),(6 4,4 4,4 6,6 6,6 4))) +SELECT ASTEXT(ST_UNION( +MULTILINESTRINGFROMTEXT('MULTILINESTRING((6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), + (8 2,1 3,9 0,4 4))'), +MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 5,6 7,9 7,5 2,1 6,3 6))'))); +ASTEXT(ST_UNION( +MULTILINESTRINGFROMTEXT('MULTILINESTRING((6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), + (8 2,1 3,9 0,4 4))'), +MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 5,6 7,9 7,5 2,1 6,3 6))'))) +MULTILINESTRING((8 2,1 3,9 0,4 4),(5 0,2 9,8 4,3 7,0 7,3 9,6 4,4 3,3 6,3 5,4 0,6 2),(3 6,1 6,5 2,9 7,6 7,2 5)) +SELECT ST_NUMGEOMETRIES((ST_UNION(ST_UNION( +MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), + (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), + (7 8,3 1,0 9,6 0,4 8), + (9 3,0 4,5 9,6 4), + (8 2,1 3,9 0,4 4))'), +MULTILINESTRINGFROMTEXT('MULTILINESTRING((6 0,9 3,2 5,3 6,3 2), + (2 5,6 7,9 7,5 2,1 6,3 6))')), +MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((7 7,3 7,3 1,7 8,7 7)), + ((3 5,2 4,2 5,3 5)), + ((7 7,8 7,3 7,7 7,7 7)), + ((0 5,3 5,3 4,1 4,1 3,3 3,3 0,0 0,0 5), (1 1,2 1,2 2,1 2,1 1)))')))); +ST_NUMGEOMETRIES((ST_UNION(ST_UNION( +MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), + (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), + +32 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 87b56dc0040..117daa275ee 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -130,3 +130,24 @@ SELECT ASTEXT(ST_INTERSECTION( ((2 2,9 2,0 2,2 6,2 2)), ((2 2,2 8,8 8,8 2,2 2), (4 4,4 6,6 6,6 4,4 4)), ((9 9,6 8,7 0,9 9)))'))); + +#bug 804324 Assertion 0 in Gcalc_scan_iterator::pop_suitable_intersection + +SELECT ASTEXT(ST_UNION( + MULTILINESTRINGFROMTEXT('MULTILINESTRING((6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), + (8 2,1 3,9 0,4 4))'), + MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 5,6 7,9 7,5 2,1 6,3 6))'))); + +SELECT ST_NUMGEOMETRIES((ST_UNION(ST_UNION( + MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), + (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), + (7 8,3 1,0 9,6 0,4 8), + (9 3,0 4,5 9,6 4), + (8 2,1 3,9 0,4 4))'), + MULTILINESTRINGFROMTEXT('MULTILINESTRING((6 0,9 3,2 5,3 6,3 2), + (2 5,6 7,9 7,5 2,1 6,3 6))')), + MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((7 7,3 7,3 1,7 8,7 7)), + ((3 5,2 4,2 5,3 5)), + ((7 7,8 7,3 7,7 7,7 7)), + ((0 5,3 5,3 4,1 4,1 3,3 3,3 0,0 0,0 5), (1 1,2 1,2 2,1 2,1 1)))')))); + diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 4a77f309f46..a0b3c354d7e 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -510,6 +510,8 @@ int Gcalc_scan_iterator::normal_scan() } +#define INTERSECTION_ZERO 0.000000000001 + int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, int isc_kind, Gcalc_dyn_list::Item ***p_hook) { @@ -536,6 +538,9 @@ int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, { double dk= a0->dx_dy - b0->dx_dy; double dy= (b0->x - a0->x)/dk; + + if (fabs(dk) < INTERSECTION_ZERO) + dy= 0.0; isc->y= m_y0 + dy; isc->x= a0->x + dy*a0->dx_dy; return 0; diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 11d452cd8cf..a360a4c100a 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -701,7 +701,8 @@ handle_lines_intersection(active_thread *t0, active_thread *t1, double x, double y) { m_fn->invert_state(p0->shape); - m_fn->invert_state(p1->shape); + if (p0->shape != p1->shape) + m_fn->invert_state(p1->shape); int intersection_state= m_fn->count(); if ((t0->result_range | t1->result_range) == intersection_state) return 0; From e182ae27cd11548feeb59306799aea3c342e8af9 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 7 Jul 2011 21:30:51 +0500 Subject: [PATCH 10/40] Fix for bug #805860 Second assertion Assertion `n > 0 && n < SINUSES_CALCULATED*2+1' in get_n_sincos. Just typo-style mistake. Should be '||' instead of '&&'. per-file comments: mysql-test/r/gis-precise.result Fix for bug #805860 Second assertion Assertion `n > 0 && n < SINUSES_CALCULATED*2+1' in get_n_sincos. test result updated. mysql-test/t/gis-precise.test Fix for bug #805860 Second assertion Assertion `n > 0 && n < SINUSES_CALCULATED*2+1' in get_n_sincos. test case added. sql/item_geofunc.cc Fix for bug #805860 Second assertion Assertion `n > 0 && n < SINUSES_CALCULATED*2+1' in get_n_sincos. condition fixed. --- mysql-test/r/gis-precise.result | 11 +++++++++-- mysql-test/t/gis-precise.test | 5 +++++ sql/item_geofunc.cc | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 4be2a093119..42cc2758a03 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -160,11 +160,11 @@ insert into t1 values (geomfromtext('POLYGON((0 0, 10 10, 0 8, 0 0))')); insert into t1 values (geomfromtext('POLYGON((1 1, 10 10, 0 8, 1 1))')); select astext(geom), area(geom),area(ST_buffer(geom,2)) from t1; astext(geom) area(geom) area(ST_buffer(geom,2)) -POLYGON((0 0,10 10,0 8,0 0)) 40 101.671508403749 +POLYGON((0 0,10 10,0 8,0 0)) 40 117.241676395915 POLYGON((1 1,10 10,0 8,1 1)) 36 108.555395892665 select astext(ST_buffer(geom,2)) from t1; astext(ST_buffer(geom,2)) -POLYGON((1.41421356237309 -1.41421356237309,-1.41421356237309 1.41421356237309,0 2.82842712474619,0 6.00005026122218,-0.0960457772985613 6.00230752900675,-0.193952209526528 6.00942657999767,-0.29139139389354 6.02134109671101,-0.388128590869789 6.03802237603243,-0.483930752074584 6.05943023129893,-0.578567081710303 6.08551308911207,-0.671809592569691 6.11620811358278,-0.763433655277008 6.15144135770856,-0.853218539439872 6.19112794151823,-0.940947945408108 6.23517225655526,-1.02641052535855 6.2834681962069,-1.10940039245046 6.33589941132431,-1.18971761682496 6.39233959051784,-1.26716870725357 6.45265276445223,-1.34156707727553 6.51669363340867,-1.41273349470095 6.58430791732451,-1.48049651339678 6.65533272746751,-1.54469288631567 6.72959695884898,-1.6051679587723 6.80692170243074,-1.66177604102015 6.88712067613267,-1.71438075923078 6.97000067360251,-1.76285538403041 7.05536202966692,-1.80708313580201 7.14299910134239,-1.84695746601768 7.23270076324713,-1.88238231392335 7.32425091622068,-1.91327233795755 7.41742900792569,-1.93955312134675 7.5120105641778,-1.96116135138184 7.60776772972363,-1.978044971944 7.70446981716405,-1.99016330891247 7.8018838627003,-1.99748716815206 7.89977518736424,-1.99999890584435 7.99790796238047,-1.99769247099325 8.09604577729856,-1.99057342000233 8.19395220952653,-1.97865890328899 8.29139139389354,-1.96197762396757 8.38812859086979,-1.94056976870107 8.48393075207458,-1.91448691088793 8.5785670817103,-1.88379188641722 8.67180959256969,-1.84855864229144 8.76343365527701,-1.80887205848177 8.85321853943987,-1.76482774344474 8.94094794540811,-1.7165318037931 9.02641052535855,-1.66410058867569 9.10940039245046,-1.60766040948216 9.18971761682496,-1.54734723554777 9.26716870725357,-1.48330636659133 9.34156707727553,-1.41569208267549 9.41273349470094,-1.34466727253249 9.48049651339678,-1.27040304115102 9.54469288631567,-1.19307829756926 9.6051679587723,-1.11287932386733 9.66177604102015,-1.02999932639749 9.71438075923078,-0.944637970333077 9.76285538403041,-0.857000898657614 9.80708313580201,-0.767299236752872 9.84695746601768,-0.675749083779317 9.88238231392335,-0.582570992074307 9.91327233795755,-0.487989435822199 9.93955312134675,-0.392232270276368 9.96116135138184,-0.295530182835952 9.978044971944,-0.392232270276368 9.96116135138184,9.60776772972363 11.9611613513818,9.60981935596774 11.9615705608065,9.70653905108928 11.9783530199296,9.80396571934088 11.9903694533444,9.90186465134516 11.9975909124103,10 12,10.0981353486548 11.9975909124103,10.1960342806591 11.9903694533444,10.2934609489107 11.9783530199296,10.3901806440323 11.9615705608065,10.4859603598065 11.9400625063891,10.5805693545089 11.9138806714644,10.6737797067844 11.883088130366,10.7653668647302 11.8477590650226,10.8551101868606 11.8079785862469,10.942793473652 11.7638425286967,11.0282054883864 11.7154572200005,11.1111404660392 11.6629392246051,11.1913986089849 11.6064150629613,11.2687865683273 11.5460209067255,11.343117909694 11.4819022507099,11.4142135623731 11.4142135623731,11.4819022507099 11.343117909694,11.5460209067255 11.2687865683273,11.6064150629613 11.1913986089849,11.6629392246051 11.1111404660392,11.7154572200005 11.0282054883864,11.7638425286967 10.942793473652,11.8079785862469 10.8551101868606,11.8477590650226 10.7653668647302,11.883088130366 10.6737797067844,11.9138806714644 10.5805693545089,11.9400625063891 10.4859603598065,11.9615705608065 10.3901806440323,11.9783530199296 10.2934609489107,11.9903694533444 10.1960342806591,11.9975909124103 10.0981353486548,12 10,11.9975909124103 9.90186465134516,11.9903694533444 9.80396571934088,11.9783530199296 9.70653905108928,11.9615705608065 9.60981935596774,11.9400625063891 9.51403964019347,11.9138806714644 9.41943064549108,11.883088130366 9.32622029321556,11.8477590650226 9.23463313526982,11.8079785862469 9.14488981313944,11.7638425286967 9.057206526348,11.7154572200005 8.97179451161356,11.6629392246051 8.8888595339608,11.6064150629613 8.80860139101513,11.5460209067255 8.73121343167271,11.4819022507099 8.65688209030596,11.4142135623731 8.5857864376269,1.41421356237309 -1.41421356237309)) +POLYGON((0 -2,-0.098135348654836 -1.99759091241034,-0.196034280659121 -1.99036945334439,-0.293460948910724 -1.97835301992956,-0.390180644032257 -1.96157056080646,-0.485960359806528 -1.94006250638909,-0.580569354508925 -1.91388067146442,-0.67377970678444 -1.88308813036604,-0.76536686473018 -1.84775906502257,-0.855110186860564 -1.80797858624689,-0.942793473651995 -1.76384252869671,-1.02820548838644 -1.71545722000054,-1.1111404660392 -1.66293922460509,-1.19139860898487 -1.60641506296129,-1.26878656832729 -1.54602090672547,-1.34311790969404 -1.48190225070992,-1.41421356237309 -1.41421356237309,-1.48190225070992 -1.34311790969404,-1.54602090672547 -1.26878656832729,-1.60641506296129 -1.19139860898487,-1.66293922460509 -1.1111404660392,-1.71545722000054 -1.02820548838644,-1.76384252869671 -0.942793473651995,-1.80797858624689 -0.855110186860564,-1.84775906502257 -0.76536686473018,-1.88308813036604 -0.67377970678444,-1.91388067146442 -0.580569354508925,-1.94006250638909 -0.485960359806528,-1.96157056080646 -0.390180644032257,-1.97835301992956 -0.293460948910724,-1.99036945334439 -0.196034280659121,-1.99759091241034 -0.098135348654836,-2 0,-2 8,-1.99769247099325 8.09604577729856,-1.99057342000233 8.19395220952653,-1.97865890328899 8.29139139389354,-1.96197762396757 8.38812859086979,-1.94056976870107 8.48393075207458,-1.91448691088793 8.5785670817103,-1.88379188641722 8.67180959256969,-1.84855864229144 8.76343365527701,-1.80887205848177 8.85321853943987,-1.76482774344474 8.94094794540811,-1.7165318037931 9.02641052535855,-1.66410058867569 9.10940039245046,-1.60766040948216 9.18971761682496,-1.54734723554777 9.26716870725357,-1.48330636659133 9.34156707727553,-1.41569208267549 9.41273349470094,-1.34466727253249 9.48049651339678,-1.27040304115102 9.54469288631567,-1.19307829756926 9.6051679587723,-1.11287932386733 9.66177604102015,-1.02999932639749 9.71438075923078,-0.944637970333077 9.76285538403041,-0.857000898657614 9.80708313580201,-0.767299236752872 9.84695746601768,-0.675749083779317 9.88238231392335,-0.582570992074307 9.91327233795755,-0.487989435822199 9.93955312134675,-0.392232270276368 9.96116135138184,9.60776772972363 11.9611613513818,9.60981935596774 11.9615705608065,9.70653905108928 11.9783530199296,9.80396571934088 11.9903694533444,9.90186465134516 11.9975909124103,10 12,10.0981353486548 11.9975909124103,10.1960342806591 11.9903694533444,10.2934609489107 11.9783530199296,10.3901806440323 11.9615705608065,10.4859603598065 11.9400625063891,10.5805693545089 11.9138806714644,10.6737797067844 11.883088130366,10.7653668647302 11.8477590650226,10.8551101868606 11.8079785862469,10.942793473652 11.7638425286967,11.0282054883864 11.7154572200005,11.1111404660392 11.6629392246051,11.1913986089849 11.6064150629613,11.2687865683273 11.5460209067255,11.343117909694 11.4819022507099,11.4142135623731 11.4142135623731,11.4819022507099 11.343117909694,11.5460209067255 11.2687865683273,11.6064150629613 11.1913986089849,11.6629392246051 11.1111404660392,11.7154572200005 11.0282054883864,11.7638425286967 10.942793473652,11.8079785862469 10.8551101868606,11.8477590650226 10.7653668647302,11.883088130366 10.6737797067844,11.9138806714644 10.5805693545089,11.9400625063891 10.4859603598065,11.9615705608065 10.3901806440323,11.9783530199296 10.2934609489107,11.9903694533444 10.1960342806591,11.9975909124103 10.0981353486548,12 10,11.9975909124103 9.90186465134516,11.9903694533444 9.80396571934088,11.9783530199296 9.70653905108928,11.9615705608065 9.60981935596774,11.9400625063891 9.51403964019347,11.9138806714644 9.41943064549108,11.883088130366 9.32622029321556,11.8477590650226 9.23463313526982,11.8079785862469 9.14488981313944,11.7638425286967 9.057206526348,11.7154572200005 8.97179451161356,11.6629392246051 8.8888595339608,11.6064150629613 8.80860139101513,11.5460209067255 8.73121343167271,11.4819022507099 8.65688209030596,11.4142135623731 8.5857864376269,1.41421356237309 -1.41421356237309,1.34311790969404 -1.48190225070992,1.26878656832729 -1.54602090672547,1.19139860898487 -1.60641506296129,1.1111404660392 -1.66293922460509,1.02820548838644 -1.71545722000054,0.942793473651995 -1.76384252869671,0.855110186860564 -1.80797858624689,0.76536686473018 -1.84775906502257,0.67377970678444 -1.88308813036604,0.580569354508925 -1.91388067146442,0.485960359806528 -1.94006250638909,0.390180644032257 -1.96157056080646,0.293460948910724 -1.97835301992956,0.196034280659121 -1.99036945334439,0.098135348654836 -1.99759091241034,0 -2)) POLYGON((0.989269849411119 -0.999971215759952,0.891148838068309 -0.997035659307595,0.793290058708828 -0.989289069032301,0.69592926170357 -0.976750107148565,0.599300997740319 -0.959448981113848,0.503638052770599 -0.937427370856167,0.409170887207927 -0.910738328363497,0.316127080728489 -0.879446149876889,0.22473078401177 -0.843626220995187,0.135202178741929 -0.803364835064523,0.0477569471708416 -0.758758985290084,-0.0373942474793394 -0.709916131070988,-0.120046268522338 -0.656953939121177,-0.2 -0.6,-0.277062826370076 -0.539191520735374,-0.351049096533933 -0.474674994280042,-0.421780571086316 -0.406605846597216,-0.489086851709682 -0.335148062225815,-0.552805791678675 -0.260473789227354,-0.61278388648579 -0.182762924466179,-0.668876643647177 -0.102202680222169,-0.720948930797688 -0.0189871331799512,-0.768875301236584 0.0666832431188291,-0.812540296139623 0.154602061233829,-0.851838722709481 0.244557517031431,-0.886675907594418 0.33633289993945,-0.916967924964667 0.429707115021888,-0.942641798697117 0.524455215615996,-0.963635678181181 0.620348945248487,-0.979898987322333 0.717157287525381,-1.97989898732233 7.71715728752538,-1.99016330891247 7.8018838627003,-1.99748716815206 7.89977518736424,-1.99999890584435 7.99790796238047,-1.99769247099325 8.09604577729856,-1.99057342000233 8.19395220952653,-1.97865890328899 8.29139139389354,-1.96197762396757 8.38812859086979,-1.94056976870107 8.48393075207458,-1.91448691088793 8.5785670817103,-1.88379188641722 8.67180959256969,-1.84855864229144 8.76343365527701,-1.80887205848177 8.85321853943987,-1.76482774344474 8.94094794540811,-1.7165318037931 9.02641052535855,-1.66410058867569 9.10940039245046,-1.60766040948216 9.18971761682496,-1.54734723554777 9.26716870725357,-1.48330636659133 9.34156707727553,-1.41569208267549 9.41273349470094,-1.34466727253249 9.48049651339678,-1.27040304115102 9.54469288631567,-1.19307829756926 9.6051679587723,-1.11287932386733 9.66177604102015,-1.02999932639749 9.71438075923078,-0.944637970333077 9.76285538403041,-0.857000898657614 9.80708313580201,-0.767299236752872 9.84695746601768,-0.675749083779317 9.88238231392335,-0.582570992074307 9.91327233795755,-0.487989435822199 9.93955312134675,-0.392232270276368 9.96116135138184,9.60776772972363 11.9611613513818,9.60981935596774 11.9615705608065,9.70653905108928 11.9783530199296,9.80396571934088 11.9903694533444,9.90186465134516 11.9975909124103,10 12,10.0981353486548 11.9975909124103,10.1960342806591 11.9903694533444,10.2934609489107 11.9783530199296,10.3901806440323 11.9615705608065,10.4859603598065 11.9400625063891,10.5805693545089 11.9138806714644,10.6737797067844 11.883088130366,10.7653668647302 11.8477590650226,10.8551101868606 11.8079785862469,10.942793473652 11.7638425286967,11.0282054883864 11.7154572200005,11.1111404660392 11.6629392246051,11.1913986089849 11.6064150629613,11.2687865683273 11.5460209067255,11.343117909694 11.4819022507099,11.4142135623731 11.4142135623731,11.4819022507099 11.343117909694,11.5460209067255 11.2687865683273,11.6064150629613 11.1913986089849,11.6629392246051 11.1111404660392,11.7154572200005 11.0282054883864,11.7638425286967 10.942793473652,11.8079785862469 10.8551101868606,11.8477590650226 10.7653668647302,11.883088130366 10.6737797067844,11.9138806714644 10.5805693545089,11.9400625063891 10.4859603598065,11.9615705608065 10.3901806440323,11.9783530199296 10.2934609489107,11.9903694533444 10.1960342806591,11.9975909124103 10.0981353486548,12 10,11.9975909124103 9.90186465134516,11.9903694533444 9.80396571934088,11.9783530199296 9.70653905108928,11.9615705608065 9.60981935596774,11.9400625063891 9.51403964019347,11.9138806714644 9.41943064549108,11.883088130366 9.32622029321556,11.8477590650226 9.23463313526982,11.8079785862469 9.14488981313944,11.7638425286967 9.057206526348,11.7154572200005 8.97179451161356,11.6629392246051 8.8888595339608,11.6064150629613 8.80860139101513,11.5460209067255 8.73121343167271,11.4819022507099 8.65688209030596,11.4142135623731 8.5857864376269,2.41421356237309 -0.414213562373095,2.40660584659722 -0.421780571086316,2.33514806222581 -0.489086851709682,2.26047378922735 -0.552805791678675,2.18276292446618 -0.61278388648579,2.10220268022217 -0.668876643647177,2.01898713317995 -0.720948930797688,1.93331675688117 -0.768875301236584,1.84539793876617 -0.812540296139623,1.75544248296857 -0.851838722709481,1.66366710006055 -0.886675907594418,1.57029288497811 -0.916967924964667,1.475544784384 -0.942641798697117,1.37965105475151 -0.963635678181181,1.28284271247462 -0.979898987322333,1.18535297732928 -0.991392546384357,1.08741671062655 -0.998088666376754,0.989269849411119 -0.999971215759952)) set @geom=geomfromtext('LINESTRING(2 1, 4 2, 2 3, 2 5)'); set @buff=ST_buffer(@geom,1); @@ -258,3 +258,10 @@ MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), 32 +SELECT Round(ST_AREA(ST_BUFFER( ST_UNION( +POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), +POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6); +Round(ST_AREA(ST_BUFFER( ST_UNION( +POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), +POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6) +21.901403 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 117daa275ee..8e3bc73849f 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -151,3 +151,8 @@ SELECT ST_NUMGEOMETRIES((ST_UNION(ST_UNION( ((7 7,8 7,3 7,7 7,7 7)), ((0 5,3 5,3 4,1 4,1 3,3 3,3 0,0 0,0 5), (1 1,2 1,2 2,1 2,1 1)))')))); +#bug #805860 Second assertion Assertion `n > 0 && n < SINUSES_CALCULATED*2+1' in get_n_sinco + +SELECT Round(ST_AREA(ST_BUFFER( ST_UNION( + POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), + POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index b1fe72e99e0..4afc56eaf87 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1395,7 +1395,7 @@ int Item_func_buffer::Transporter::complete() } else { - if (x2 != x00 && y2 != y00) + if (x2 != x00 || y2 != y00) { if (add_edge_buffer(x00, y00, false, false)) return 1; From 67e937095cec8aa922ff3ea971204d59ee3047ff Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 8 Jul 2011 15:38:15 +0500 Subject: [PATCH 11/40] Fix for bug #804259 Second assertion in Gis_geometry_collection::init_from_opresult. A polygon has no right to have holes that are actually points. So just skip them when we collect the result of an operation. per-file comments: mysql-test/r/gis-precise.result Fix for bug #804259 Second assertion in Gis_geometry_collection::init_from_opresult. test result updated. mysql-test/t/gis-precise.test Fix for bug #804259 Second assertion in Gis_geometry_collection::init_from_opresult. test case added. sql/gcalc_tools.cc Fix for bug #804259 Second assertion in Gis_geometry_collection::init_from_opresult. Skip the point in the result if it's the hole inside a polygon. --- mysql-test/r/gis-precise.result | 14 ++++++++++++++ mysql-test/t/gis-precise.test | 12 ++++++++++++ sql/gcalc_tools.cc | 5 +++++ 3 files changed, 31 insertions(+) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 42cc2758a03..98d081f48e3 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -265,3 +265,17 @@ Round(ST_AREA(ST_BUFFER( ST_UNION( POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6) 21.901403 +SELECT AsText(ST_UNION(MultiPolygonFromText(' + MULTIPOLYGON(((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)), + ((0 0, 8 3, 7 4, 0 0)), + ((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)))'), +MultiPolygonFromText(' MULTIPOLYGON(((0 0, 1 9, 4 6, 0 0)), + ((0 5, 3 5, 3 4, 1 4, 1 3, 3 3, 3 0, 0 0, 0 5), (1 1, 2 1, 2 2, 1 2, 1 1)), + ((7 7, 4 7, 6 3, 7 2, 7 7)), + ((0 5, 3 5, 3 4, 1 4, 1 3, 3 3, 3 0, 0 0, 0 5), (1 1, 2 1, 2 2, 1 2, 1 1))) '))); +AsText(ST_UNION(MultiPolygonFromText(' + MULTIPOLYGON(((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)), + ((0 0, 8 3, 7 4, 0 0)), + ((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)))'), +MultiPolygonFr +POLYGON((0 0,0 5,0.555555555555556 5,1 9,2 8,8 8,8 2,7 2,5.33333333333333 2,3 1.125,3 0,0 0),(1 1,1 1.5,1.33333333333333 2,1 2,2 2,2 1.14285714285714,1.75 1,1 1),(3 1.71428571428571,3 2,3.5 2,3 1.71428571428571),(4 4,4 6,4.5 6,5.5 4,4 4)) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 8e3bc73849f..30445219d90 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -156,3 +156,15 @@ SELECT ST_NUMGEOMETRIES((ST_UNION(ST_UNION( SELECT Round(ST_AREA(ST_BUFFER( ST_UNION( POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6); + + +#buf #804259 Second assertion in Gis_geometry_collection::init_from_opresult + +SELECT AsText(ST_UNION(MultiPolygonFromText(' + MULTIPOLYGON(((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)), + ((0 0, 8 3, 7 4, 0 0)), + ((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)))'), +MultiPolygonFromText(' MULTIPOLYGON(((0 0, 1 9, 4 6, 0 0)), + ((0 5, 3 5, 3 4, 1 4, 1 3, 3 3, 3 0, 0 0, 0 5), (1 1, 2 1, 2 2, 1 2, 1 1)), + ((7 7, 4 7, 6 3, 7 2, 7 7)), + ((0 5, 3 5, 3 4, 1 4, 1 3, 3 3, 3 0, 0 0, 0 5), (1 1, 2 1, 2 2, 1 2, 1 1))) '))); diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index a360a4c100a..2a9090a04a1 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -319,6 +319,11 @@ int Gcalc_result_receiver::complete_shape() { if (cur_shape != Gcalc_function::shape_point) { + if (cur_shape == Gcalc_function::shape_hole) + { + buffer.length(shape_pos); + return 0; + } cur_shape= Gcalc_function::shape_point; buffer.length(buffer.length()-4); } From e7c9f52fd960440614c30c3f852bf74f1febe6b3 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 12 Jul 2011 11:21:20 +0500 Subject: [PATCH 12/40] Fix for bug #801217 Assertion `t1->result_range' in Gcalc_operation_reducer::end_couple. We cannot cut a line from a polygon. So if the polygon fits the condition, and the intersection of a line and the polygon doesn't, we just skip the line. That rule wasn't applied if the line start was inside the polygon, which leaded to the assertion. per-file comments: mysql-test/r/gis-precise.result Fix for bug #801217 Assertion `t1->result_range' in Gcalc_operation_reducer::end_couple. test result updated. mysql-test/t/gis-precise.test Fix for bug #801217 Assertion `t1->result_range' in Gcalc_operation_reducer::end_couple. test case added. sql/gcalc_tools.cc Fix for bug #801217 Assertion `t1->result_range' in Gcalc_operation_reducer::end_couple. Don't mark the line as a border if it's inside a polygon that fits the result condition. --- mysql-test/r/gis-precise.result | 9 +++++++++ mysql-test/t/gis-precise.test | 11 ++++++++++- sql/gcalc_tools.cc | 9 +++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 98d081f48e3..d943a534137 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -279,3 +279,12 @@ AsText(ST_UNION(MultiPolygonFromText(' ((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)))'), MultiPolygonFr POLYGON((0 0,0 5,0.555555555555556 5,1 9,2 8,8 8,8 2,7 2,5.33333333333333 2,3 1.125,3 0,0 0),(1 1,1 1.5,1.33333333333333 2,1 2,2 2,2 1.14285714285714,1.75 1,1 1),(3 1.71428571428571,3 2,3.5 2,3 1.71428571428571),(4 4,4 6,4.5 6,5.5 4,4 4)) +SELECT AsText(ST_SYMDIFFERENCE( +MultiLineStringFromText('MULTILINESTRING((7 7, 1 7, 8 5, 7 8, 7 7), + (6 3, 3 4, 1 1, 9 9, 9 0, 8 4, 9 9))'), +Envelope(GeometryFromText('MULTIPOINT(7 9, 0 0, 3 7, 1 6, 0 0)')))); +AsText(ST_SYMDIFFERENCE( +MultiLineStringFromText('MULTILINESTRING((7 7, 1 7, 8 5, 7 8, 7 7), + (6 3, 3 4, 1 1, 9 9, 9 0, 8 4, 9 9))'), +Envelope(GeometryFromText('MULTIPOINT(7 9, 0 0, 3 7, 1 6, 0 0)')))) +GEOMETRYCOLLECTION(LINESTRING(9 9,8 4,9 0,9 9,7 7),POLYGON((0 0,0 9,7 9,7 0,0 0)),LINESTRING(7 5.28571428571429,8 5,7 8)) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 30445219d90..bf36e6e9628 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -158,7 +158,7 @@ SELECT Round(ST_AREA(ST_BUFFER( ST_UNION( POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6); -#buf #804259 Second assertion in Gis_geometry_collection::init_from_opresult +#bug #804259 Second assertion in Gis_geometry_collection::init_from_opresult SELECT AsText(ST_UNION(MultiPolygonFromText(' MULTIPOLYGON(((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)), @@ -168,3 +168,12 @@ MultiPolygonFromText(' MULTIPOLYGON(((0 0, 1 9, 4 6, 0 0)), ((0 5, 3 5, 3 4, 1 4, 1 3, 3 3, 3 0, 0 0, 0 5), (1 1, 2 1, 2 2, 1 2, 1 1)), ((7 7, 4 7, 6 3, 7 2, 7 7)), ((0 5, 3 5, 3 4, 1 4, 1 3, 3 3, 3 0, 0 0, 0 5), (1 1, 2 1, 2 2, 1 2, 1 1))) '))); + + +#bug 801217 Assertion `t1->result_range' in Gcalc_operation_reducer::end_couple + +SELECT AsText(ST_SYMDIFFERENCE( + MultiLineStringFromText('MULTILINESTRING((7 7, 1 7, 8 5, 7 8, 7 7), + (6 3, 3 4, 1 1, 9 9, 9 0, 8 4, 9 9))'), + Envelope(GeometryFromText('MULTIPOINT(7 9, 0 0, 3 7, 1 6, 0 0)')))); + diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 2a9090a04a1..d89385fa78c 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -879,7 +879,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) if (!new_t) return 1; m_fn->invert_state(pi.get_shape()); - new_t->result_range= prev_state ^ m_fn->count(); + new_t->result_range= ~prev_state & m_fn->count(); new_t->next= *at_hook; *at_hook= new_t; if (new_t->result_range && @@ -891,12 +891,17 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { active_thread *new_t0, *new_t1; int fn_result; + const Gcalc_heap::Info *p= pi.get_pi(); + bool line= m_fn->get_shape_kind(p->shape) == Gcalc_function::shape_line; if (!(new_t0= new_active_thread()) || !(new_t1= new_active_thread())) return 1; m_fn->invert_state(pi.get_shape()); fn_result= m_fn->count(); - new_t0->result_range= new_t1->result_range= prev_state ^ fn_result; + if (line) + new_t0->result_range= new_t1->result_range= ~prev_state & fn_result; + else + new_t0->result_range= new_t1->result_range= prev_state ^ fn_result; new_t1->next= *at_hook; new_t0->next= new_t1; *at_hook= new_t0; From 90c4df7a4af542707d884e53990827672bb8feea Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 13 Jul 2011 14:57:27 +0500 Subject: [PATCH 13/40] Fix for bug #804266 Memory corruption/valgrind warning/crash in move_hole() with ST_UNION. Second smaller hole in the polygon got link to the bigger one as it's the outer ring. Fixed by specifying the outer ring explicitly. per-file comments: mysql-test/r/gis-precise.result Fix for bug #804266 Memory corruption/valgrind warning/crash in move_hole() with ST_UNION. test result updated. mysql-test/t/gis-precise.test Fix for bug #804266 Memory corruption/valgrind warning/crash in move_hole() with ST_UNION. test case added. sql/gcalc_tools.cc Fix for bug #804266 Memory corruption/valgrind warning/crash in move_hole() with ST_UNION. specify the outer ring explicitly in the get_polygon_result parameter. sql/gcalc_tools.h Fix for bug #804266 Memory corruption/valgrind warning/crash in move_hole() with ST_UNION. add the outer ring as a parameter to the get_polygon_result. --- mysql-test/r/gis-precise.result | 13 +++++++++++++ mysql-test/t/gis-precise.test | 10 ++++++++++ sql/gcalc_tools.cc | 16 +++++++++------- sql/gcalc_tools.h | 5 +++-- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index d943a534137..dd27470ab5d 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -288,3 +288,16 @@ MultiLineStringFromText('MULTILINESTRING((7 7, 1 7, 8 5, 7 8, 7 7), (6 3, 3 4, 1 1, 9 9, 9 0, 8 4, 9 9))'), Envelope(GeometryFromText('MULTIPOINT(7 9, 0 0, 3 7, 1 6, 0 0)')))) GEOMETRYCOLLECTION(LINESTRING(9 9,8 4,9 0,9 9,7 7),POLYGON((0 0,0 9,7 9,7 0,0 0)),LINESTRING(7 5.28571428571429,8 5,7 8)) +SELECT AsText(ST_UNION( +MultiPolygonFromText('MULTIPOLYGON(((9 9, 7 9, 1 1, 9 9)), + ((2 2, 1 2, 3 3, 2 2, 2 2)), + ((0 0, 7 5, 9 6, 0 0)), + ((7 7, 5 7, 1 5, 7 1, 7 7)))'), +MultiPolygonFromText('MULTIPOLYGON(((2 2, 2 2, 1 5, 2 7, 2 2)), + ((0 5, 3 5, 3 0, 0 0, 0 5), (1 1, 2 1, 2 4, 1 4, 1 1)))'))); +AsText(ST_UNION( +MultiPolygonFromText('MULTIPOLYGON(((9 9, 7 9, 1 1, 9 9)), + ((2 2, 1 2, 3 3, 2 2, 2 2)), + ((0 0, 7 5, 9 6, 0 0)), + +POLYGON((0 0,0 5,1 5,2 7,2 5.5,5 7,5.5 7,7 9,9 9,7 7,7 5,9 6,7 4.66666666666667,7 1,4.25 2.83333333333333,3 2,3 0,0 0),(1 1,1 4,1.33333333333333 4,1.85714285714286 2.42857142857143,1 2,1.75 2,1 1,2 2,2 1.42857142857143,1.4 1,1 1),(1.5 1,2 1.33333333333333,2 1,1.5 1),(3 2.14285714285714,3 3,3.4 3.4,4.10344827586207 2.93103448275862,3 2.14285714285714)) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index bf36e6e9628..bb223b685e4 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -177,3 +177,13 @@ SELECT AsText(ST_SYMDIFFERENCE( (6 3, 3 4, 1 1, 9 9, 9 0, 8 4, 9 9))'), Envelope(GeometryFromText('MULTIPOINT(7 9, 0 0, 3 7, 1 6, 0 0)')))); +#bug 804266 Memory corruption/valgrind warning/crash in move_hole() with ST_UNION + +SELECT AsText(ST_UNION( + MultiPolygonFromText('MULTIPOLYGON(((9 9, 7 9, 1 1, 9 9)), + ((2 2, 1 2, 3 3, 2 2, 2 2)), + ((0 0, 7 5, 9 6, 0 0)), + ((7 7, 5 7, 1 5, 7 1, 7 7)))'), + MultiPolygonFromText('MULTIPOLYGON(((2 2, 2 2, 1 5, 2 7, 2 2)), + ((0 5, 3 5, 3 0, 0 0, 0 5), (1 1, 2 1, 2 4, 1 4, 1 1)))'))); + diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index d89385fa78c..25e71d7bfca 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -1023,11 +1023,11 @@ inline int Gcalc_operation_reducer::get_single_result(res_point *res, int Gcalc_operation_reducer::get_result_thread(res_point *cur, Gcalc_result_receiver *storage, - int move_upward) + int move_upward, + res_point *first_poly_node) { res_point *next; bool glue_step= false; - res_point *first_poly_node= cur; double x, y; while (cur) { @@ -1068,12 +1068,13 @@ int Gcalc_operation_reducer::get_result_thread(res_point *cur, int Gcalc_operation_reducer::get_polygon_result(res_point *cur, - Gcalc_result_receiver *storage) + Gcalc_result_receiver *storage, + res_point *first_poly_node) { res_point *glue= cur->glue; glue->up->down= NULL; free_result(glue); - return get_result_thread(cur, storage, 1) || + return get_result_thread(cur, storage, 1, first_poly_node) || storage->complete_shape(); } @@ -1100,7 +1101,7 @@ int Gcalc_operation_reducer::get_line_result(res_point *cur, } } - return get_result_thread(cur, storage, move_upward) || + return get_result_thread(cur, storage, move_upward, 0) || storage->complete_shape(); } @@ -1129,7 +1130,8 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) DBUG_ASSERT(insert_position); hole_position= storage->position(); storage->start_shape(Gcalc_function::shape_hole); - if (get_polygon_result(m_result, storage) || + if (get_polygon_result(m_result, storage, + m_result->outer_poly->first_poly_node) || storage->move_hole(insert_position, hole_position, &position_shift)) return 1; @@ -1146,7 +1148,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) p->next= polygons; polygons= p; storage->start_shape(Gcalc_function::shape_polygon); - if (get_polygon_result(m_result, storage)) + if (get_polygon_result(m_result, storage, m_result)) return 1; *poly_position= storage->position(); } diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index 32835d68666..5e55d1bdae3 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -304,8 +304,9 @@ private: int get_single_result(res_point *res, Gcalc_result_receiver *storage); int get_result_thread(res_point *cur, Gcalc_result_receiver *storage, - int move_upward); - int get_polygon_result(res_point *cur, Gcalc_result_receiver *storage); + int move_upward, res_point *first_poly_node); + int get_polygon_result(res_point *cur, Gcalc_result_receiver *storage, + res_point *first_poly_node); int get_line_result(res_point *cur, Gcalc_result_receiver *storage); void free_result(res_point *res); From 152f3c5e28fe2ae3fd950f15bb3de7064500ced5 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 1 Sep 2011 11:44:56 +0500 Subject: [PATCH 14/40] PostGIS-style 'same point' handling. --- mysql-test/r/archive_gis.result | 10 +- mysql-test/r/gis-precise.result | 26 +- mysql-test/r/gis-rtree.result | 1 + mysql-test/r/gis.result | 12 +- mysql-test/suite/innodb/r/innodb_gis.result | 10 +- .../suite/innodb_plugin/r/innodb_gis.result | 10 +- .../maria/r/maria-gis-rtree-dynamic.result | 201 ++-- .../maria/r/maria-gis-rtree-trans.result | 201 ++-- .../suite/maria/r/maria-gis-rtree.result | 201 ++-- sql/gcalc_slicescan.cc | 686 ++++++++----- sql/gcalc_slicescan.h | 83 +- sql/gcalc_tools.cc | 933 ++++++++++-------- sql/gcalc_tools.h | 121 ++- sql/item_geofunc.cc | 112 ++- sql/spatial.cc | 32 + 15 files changed, 1494 insertions(+), 1145 deletions(-) diff --git a/mysql-test/r/archive_gis.result b/mysql-test/r/archive_gis.result index e4cf705a76f..7f1715ab093 100644 --- a/mysql-test/r/archive_gis.result +++ b/mysql-test/r/archive_gis.result @@ -392,10 +392,10 @@ Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; first second w c o e d t i r -120 120 0 0 0 1 0 1 1 0 +120 120 1 1 0 1 0 1 1 1 120 121 0 0 1 0 0 0 1 0 121 120 0 0 1 0 0 0 1 0 -121 121 0 0 0 1 0 1 1 0 +121 121 1 1 0 1 0 1 1 1 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -494,12 +494,13 @@ mbroverlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrtouches FROM t1 a1 JOIN t1 a2 ON MBRTouches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrtouches -down2,left2,right2,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrwithin FROM t1 a1 JOIN t1 a2 ON MBRWithin( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrwithin big,center SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS contains FROM t1 a1 JOIN t1 a2 ON Contains( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; contains +center,small SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS disjoint FROM t1 a1 JOIN t1 a2 ON Disjoint( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; disjoint down3,left3,right3,up3 @@ -514,9 +515,10 @@ overlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS touches FROM t1 a1 JOIN t1 a2 ON Touches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; touches -down2,left2,right2,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS within FROM t1 a1 JOIN t1 a2 ON Within( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; within +big,center SET @vert1 = GeomFromText('POLYGON ((0 -2, 0 2, 0 -2))'); SET @horiz1 = GeomFromText('POLYGON ((-2 0, 2 0, -2 0))'); SET @horiz2 = GeomFromText('POLYGON ((-1 0, 3 0, -1 0))'); diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index dd27470ab5d..80d44da6cbf 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -79,7 +79,7 @@ select 1, ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText(' 1 1 select 0, ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText('LINESTRING(16 16, 51 51)')); 0 ST_Intersects(GeomFromText('LINESTRING(15 15, 50 50)'), GeomFromText('LINESTRING(16 16, 51 51)')) -0 0 +0 1 select 1, ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))')); 1 ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POLYGON((50 5, 55 10, 0 45, 50 5))')) 1 1 @@ -127,10 +127,10 @@ astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFr POLYGON((26.4705882352941 23.8235294117647,21.9512195121951 27.4390243902439,23.855421686747 29.8192771084337,29.2899408284024 26.3609467455621,26.4705882352941 23.8235294117647)) select astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50, 0 0)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45, 50 5)'))); astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50, 0 0)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45, 50 5)'))) -MULTIPOINT(26.4705882352941 23.8235294117647,29.2899408284024 26.3609467455621,21.9512195121951 27.4390243902439,23.855421686747 29.8192771084337) +MULTIPOINT(23.8235294117647 26.4705882352941,26.3609467455621 29.2899408284024,27.4390243902439 21.9512195121951,29.8192771084337 23.855421686747) select astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45)'))); astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45)'))) -POINT(29.2899408284024 26.3609467455621) +POINT(26.3609467455621 29.2899408284024) select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POINT(20 20)'))); astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POINT(20 20)'))) POINT(20 20) @@ -148,7 +148,7 @@ astext(ST_intersection(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromte POLYGON((0 0,0 1,0.5 0.5,0 0)) select astext(ST_symdifference(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromtext('polygon((0 0, 1 1, 0 2, 0 0))'))); astext(ST_symdifference(geomfromtext('polygon((0 0, 1 0, 0 1, 0 0))'), geomfromtext('polygon((0 0, 1 1, 0 2, 0 0))'))) -MULTIPOLYGON(((0 0,0 1,0 0,0.5 0.5,1 0,0 0)),((0.5 0.5,0 1,0 2,1 1,0.5 0.5))) +MULTIPOLYGON(((0 0,0.5 0.5,1 0,0 0)),((0.5 0.5,0 1,0 2,1 1,0.5 0.5))) select astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))); astext(ST_UNION(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('LINESTRING(-10 -10, 200 200, 199 201, -11 -9)'))) GEOMETRYCOLLECTION(LINESTRING(-10 -10,0 0),LINESTRING(-11 -9,8 10),POLYGON((0 0,40 50,50 45,0 0)),LINESTRING(46.6666666666667 46.6666666666667,200 200,199 201,45.3333333333333 47.3333333333333)) @@ -189,7 +189,7 @@ st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')) -0 +1 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')) 1 @@ -208,13 +208,13 @@ ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0, astext(ST_UNION ( PolyFromText('POLYGON(( 2 2 ,3 2,2 7,2 2),( 0 0,8 2,1 9,0 0))'), ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0,0 5))'))))) -GEOMETRYCOLLECTION(POLYGON((0 0,1 9,8 2,0 0),(2 2,2 7,3 2,2 2)),LINESTRING(0 0,5 0,5 1.25),LINESTRING(0 0,0 5,0.555555555555556 5),LINESTRING(2.4 5,2 5)) +GEOMETRYCOLLECTION(POLYGON((0 0,1 9,8 2,0 0),(2 2,2 7,3 2,2 2)),LINESTRING(0.555555555555556 5,0 5,0 0,5 0,5 1.25),LINESTRING(2 5,2.4 5)) SELECT astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)); astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)) LINESTRING(0 0,1 1) SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5); Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5) -78.68426 +78.68303 SELECT ST_INTERSECTION(NULL, NULL); ST_INTERSECTION(NULL, NULL) NULL @@ -231,7 +231,7 @@ MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)) ((0 5,3 5,3 0,0 0,0 1,2 1,2 2,0 2,0 5), (1 3,2 3,2 4,1 4,1 3)), ((2 2,5 2,4 4,2 8,2 2)))'), MULTIPOLY -MULTIPOLYGON(((2 2,3 2,2 2)),((5 2,0 2,5 2)),((2 2,0 2,1.5 5,2 5,2 2),(1 3,1 4,2 4,2 3,1 3)),((2 2,2 8,8 8,8 2,5 2,2 2),(6 4,4 4,4 6,6 6,6 4))) +POLYGON((0 2,1 4,1 3,2 3,2 4,1 4,1.5 5,2 5,2 8,8 8,8 2,0 2),(4 4,4 6,6 6,6 4,4 4)) SELECT ASTEXT(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), (8 2,1 3,9 0,4 4))'), @@ -240,7 +240,7 @@ ASTEXT(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), (8 2,1 3,9 0,4 4))'), MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 5,6 7,9 7,5 2,1 6,3 6))'))) -MULTILINESTRING((8 2,1 3,9 0,4 4),(5 0,2 9,8 4,3 7,0 7,3 9,6 4,4 3,3 6,3 5,4 0,6 2),(3 6,1 6,5 2,9 7,6 7,2 5)) +MULTILINESTRING((3.59459459459459 2.02702702702703,4 0,4.75 0.75),(5 0,4.75 0.75),(5.36363636363636 1.36363636363636,9 0,6.17391304347826 2.26086956521739),(4.75 0.75,4.42857142857143 1.71428571428571),(4.75 0.75,5.36363636363636 1.36363636363636),(5.36363636363636 1.36363636363636,4.42857142857143 1.71428571428571),(5.36363636363636 1.36363636363636,6 2),(4.42857142857143 1.71428571428571,3.59459459459459 2.02702702702703),(4.42857142857143 1.71428571428571,4.15 2.55),(4.5 2.5,5 2,5.30769230769231 2.38461538461538),(8 2,6.17391304347826 2.26086956521739),(3.59459459459459 2.02702702702703,1 3,3.47058823529412 2.64705882352941),(3.59459459459459 2.02702702702703,3.47058823529412 2.64705882352941),(6.17391304347826 2.26086956521739,5.30769230769231 2.38461538461538),(6.17391304347826 2.26086956521739,5.58536585365854 2.73170731707317),(5.30769230769231 2.38461538461538,4.5 2.5),(5.30769230769231 2.38461538461538,5.58536585365854 2.73170731707317),(4.5 2.5,4.15 2.55),(4.5 2.5,4 3),(4.15 2.55,3.47058823529412 2.64705882352941),(4.15 2.55,4 3),(3.47058823529412 2.64705882352941,3.25 3.75),(5.58536585365854 2.73170731707317,4.76923076923077 3.38461538461538),(5.58536585365854 2.73170731707317,7.05405405405405 4.56756756756757),(4 3,3.25 3.75),(4 3,3.14285714285714 5.57142857142857),(4 3,4.76923076923077 3.38461538461538),(4.76923076923077 3.38461538461538,4 4),(4.76923076923077 3.38461538461538,6 4,4.875 5.875),(3.25 3.75,2 5),(3.25 3.75,3 5,3 5.5),(7.05405405405405 4.56756756756757,8 4,7.16 4.7),(7.05405405405405 4.56756756756757,4.875 5.875),(7.05405405405405 4.56756756756757,7.16 4.7),(7.16 4.7,5 6.5),(7.16 4.7,9 7,6 7,5 6.5),(2 5,1 6,3 6),(2 5,3 5.5),(3 5.5,3 6),(3 5.5,3.14285714285714 5.57142857142857),(3.14285714285714 5.57142857142857,3 6),(3.14285714285714 5.57142857142857,4.36363636363636 6.18181818181818),(4.875 5.875,4.36363636363636 6.18181818181818),(4.875 5.875,4.61538461538461 6.30769230769231),(3 6,2.66666666666667 7),(4.36363636363636 6.18181818181818,3 7,2.66666666666667 7),(4.36363636363636 6.18181818181818,4.61538461538461 6.30769230769231),(4.61538461538461 6.30769230769231,4 7.33333333333333),(4.61538461538461 6.30769230769231,5 6.5),(5 6.5,4 7.33333333333333),(2.18181818181818 8.45454545454546,0 7,2.66666666666667 7),(2.66666666666667 7,2.18181818181818 8.45454545454546),(4 7.33333333333333,2.44444444444444 8.62962962962963),(4 7.33333333333333,3 9,2.44444444444444 8.62962962962963),(2.18181818181818 8.45454545454546,2 9,2.44444444444444 8.62962962962963),(2.18181818181818 8.45454545454546,2.44444444444444 8.62962962962963)) SELECT ST_NUMGEOMETRIES((ST_UNION(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), @@ -257,14 +257,14 @@ ST_NUMGEOMETRIES((ST_UNION(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), -32 +183 SELECT Round(ST_AREA(ST_BUFFER( ST_UNION( POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6); Round(ST_AREA(ST_BUFFER( ST_UNION( POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6) -21.901403 +21.901344 SELECT AsText(ST_UNION(MultiPolygonFromText(' MULTIPOLYGON(((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)), ((0 0, 8 3, 7 4, 0 0)), @@ -278,7 +278,7 @@ AsText(ST_UNION(MultiPolygonFromText(' ((0 0, 8 3, 7 4, 0 0)), ((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4)))'), MultiPolygonFr -POLYGON((0 0,0 5,0.555555555555556 5,1 9,2 8,8 8,8 2,7 2,5.33333333333333 2,3 1.125,3 0,0 0),(1 1,1 1.5,1.33333333333333 2,1 2,2 2,2 1.14285714285714,1.75 1,1 1),(3 1.71428571428571,3 2,3.5 2,3 1.71428571428571),(4 4,4 6,4.5 6,5.5 4,4 4)) +POLYGON((0 0,0 5,0.555555555555556 5,1 9,2 8,8 8,8 2,5.33333333333333 2,3 1.125,3 0,0 0),(1 1,1 1.5,1.33333333333333 2,2 2,2 1.14285714285714,1.75 1,1 1),(3 1.71428571428571,3 2,3.5 2,3 1.71428571428571),(4 4,4 6,4.5 6,5.5 4,4 4)) SELECT AsText(ST_SYMDIFFERENCE( MultiLineStringFromText('MULTILINESTRING((7 7, 1 7, 8 5, 7 8, 7 7), (6 3, 3 4, 1 1, 9 9, 9 0, 8 4, 9 9))'), @@ -287,7 +287,7 @@ AsText(ST_SYMDIFFERENCE( MultiLineStringFromText('MULTILINESTRING((7 7, 1 7, 8 5, 7 8, 7 7), (6 3, 3 4, 1 1, 9 9, 9 0, 8 4, 9 9))'), Envelope(GeometryFromText('MULTIPOINT(7 9, 0 0, 3 7, 1 6, 0 0)')))) -GEOMETRYCOLLECTION(LINESTRING(9 9,8 4,9 0,9 9,7 7),POLYGON((0 0,0 9,7 9,7 0,0 0)),LINESTRING(7 5.28571428571429,8 5,7 8)) +GEOMETRYCOLLECTION(POLYGON((0 0,0 9,7 9,7 0,0 0)),LINESTRING(9 9,8 4,9 0,9 9),LINESTRING(7 5.28571428571429,8 5,7.25 7.25),LINESTRING(7 7,7.25 7.25),LINESTRING(7.25 7.25,7 8),LINESTRING(7.25 7.25,9 9)) SELECT AsText(ST_UNION( MultiPolygonFromText('MULTIPOLYGON(((9 9, 7 9, 1 1, 9 9)), ((2 2, 1 2, 3 3, 2 2, 2 2)), diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 31e79a52b49..d3133389321 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -170,6 +170,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range g g 34 NULL 8 Using where SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); fid AsText(g) +11 LINESTRING(140 140,160 160) DROP TABLE t1; CREATE TABLE t2 ( fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index d30431e5419..8dabc431e8f 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -384,10 +384,10 @@ Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; first second w c o e d t i r -120 120 0 0 0 1 0 1 1 0 +120 120 1 1 0 1 0 1 1 1 120 121 0 0 1 0 0 0 1 0 121 120 0 0 1 0 0 0 1 0 -121 121 0 0 0 1 0 1 1 0 +121 121 1 1 0 1 0 1 1 1 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -835,12 +835,13 @@ mbroverlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrtouches FROM t1 a1 JOIN t1 a2 ON MBRTouches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrtouches -down2,left2,right2,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrwithin FROM t1 a1 JOIN t1 a2 ON MBRWithin( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrwithin big,center SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS contains FROM t1 a1 JOIN t1 a2 ON Contains( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; contains +center,small SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS disjoint FROM t1 a1 JOIN t1 a2 ON Disjoint( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; disjoint down3,left3,right3,up3 @@ -855,9 +856,10 @@ overlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS touches FROM t1 a1 JOIN t1 a2 ON Touches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; touches -down2,left2,right2,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS within FROM t1 a1 JOIN t1 a2 ON Within( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; within +big,center SET @vert1 = GeomFromText('POLYGON ((0 -2, 0 2, 0 -2))'); SET @horiz1 = GeomFromText('POLYGON ((-2 0, 2 0, -2 0))'); SET @horiz2 = GeomFromText('POLYGON ((-1 0, 3 0, -1 0))'); @@ -1410,7 +1412,7 @@ FROM lakes, named_places WHERE lakes.name = 'Blue Lake' AND named_places.name = 'Ashton'; AsText(ST_SymDifference(shore, boundary)) -MULTIPOLYGON(((48 6,52 18,66 23,73 9,48 6),(67 13,59 13,59 18,67 18,67 13)),((56 30,56 34,62 48,84 48,84 30,56 30))) +MULTIPOLYGON(((48 6,52 18,66 23,73 9,48 6),(59 13,59 18,67 18,67 13,59 13)),((56 30,56 34,62 48,84 48,84 30,56 30))) # Conformance Item T51 SELECT count(*) FROM buildings, bridges diff --git a/mysql-test/suite/innodb/r/innodb_gis.result b/mysql-test/suite/innodb/r/innodb_gis.result index 57d61bbd586..710c403e9a0 100644 --- a/mysql-test/suite/innodb/r/innodb_gis.result +++ b/mysql-test/suite/innodb/r/innodb_gis.result @@ -392,10 +392,10 @@ Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; first second w c o e d t i r -120 120 0 0 0 1 0 1 1 0 +120 120 1 1 0 1 0 1 1 1 120 121 0 0 1 0 0 0 1 0 121 120 0 0 1 0 0 0 1 0 -121 121 0 0 0 1 0 1 1 0 +121 121 1 1 0 1 0 1 1 1 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -494,12 +494,13 @@ mbroverlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrtouches FROM t1 a1 JOIN t1 a2 ON MBRTouches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrtouches -down2,left2,right2,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrwithin FROM t1 a1 JOIN t1 a2 ON MBRWithin( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrwithin big,center SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS contains FROM t1 a1 JOIN t1 a2 ON Contains( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; contains +center,small SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS disjoint FROM t1 a1 JOIN t1 a2 ON Disjoint( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; disjoint down3,left3,right3,up3 @@ -514,9 +515,10 @@ overlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS touches FROM t1 a1 JOIN t1 a2 ON Touches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; touches -down2,left2,right2,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS within FROM t1 a1 JOIN t1 a2 ON Within( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; within +big,center SET @vert1 = GeomFromText('POLYGON ((0 -2, 0 2, 0 -2))'); SET @horiz1 = GeomFromText('POLYGON ((-2 0, 2 0, -2 0))'); SET @horiz2 = GeomFromText('POLYGON ((-1 0, 3 0, -1 0))'); diff --git a/mysql-test/suite/innodb_plugin/r/innodb_gis.result b/mysql-test/suite/innodb_plugin/r/innodb_gis.result index 57d61bbd586..710c403e9a0 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_gis.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_gis.result @@ -392,10 +392,10 @@ Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; first second w c o e d t i r -120 120 0 0 0 1 0 1 1 0 +120 120 1 1 0 1 0 1 1 1 120 121 0 0 1 0 0 0 1 0 121 120 0 0 1 0 0 0 1 0 -121 121 0 0 0 1 0 1 1 0 +121 121 1 1 0 1 0 1 1 1 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -494,12 +494,13 @@ mbroverlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrtouches FROM t1 a1 JOIN t1 a2 ON MBRTouches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrtouches -down2,left2,right2,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrwithin FROM t1 a1 JOIN t1 a2 ON MBRWithin( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrwithin big,center SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS contains FROM t1 a1 JOIN t1 a2 ON Contains( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; contains +center,small SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS disjoint FROM t1 a1 JOIN t1 a2 ON Disjoint( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; disjoint down3,left3,right3,up3 @@ -514,9 +515,10 @@ overlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS touches FROM t1 a1 JOIN t1 a2 ON Touches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; touches -down2,left2,right2,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS within FROM t1 a1 JOIN t1 a2 ON Within( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; within +big,center SET @vert1 = GeomFromText('POLYGON ((0 -2, 0 2, 0 -2))'); SET @horiz1 = GeomFromText('POLYGON ((-2 0, 2 0, -2 0))'); SET @horiz2 = GeomFromText('POLYGON ((-1 0, 3 0, -1 0))'); diff --git a/mysql-test/suite/maria/r/maria-gis-rtree-dynamic.result b/mysql-test/suite/maria/r/maria-gis-rtree-dynamic.result index e8df5e5c8ab..843e5ae3d37 100644 --- a/mysql-test/suite/maria/r/maria-gis-rtree-dynamic.result +++ b/mysql-test/suite/maria/r/maria-gis-rtree-dynamic.result @@ -181,6 +181,7 @@ fid AsText(g) 8 LINESTRING(143 143,157 157) 9 LINESTRING(142 142,158 158) 10 LINESTRING(141 141,159 159) +11 LINESTRING(140 140,160 160) DROP TABLE t1; CREATE TABLE t2 ( fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -308,403 +309,403 @@ fid AsText(g) DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +99 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +98 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +97 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +96 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +95 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +94 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +93 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +92 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +91 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +90 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +89 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +88 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +87 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +86 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +85 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +84 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +83 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +82 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +81 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +80 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +79 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +78 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +77 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +76 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +75 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +74 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +73 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +72 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +71 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +70 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +69 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +68 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +67 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +66 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +65 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +64 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +63 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +62 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +61 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +60 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +59 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +58 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +57 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +56 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +55 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +54 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +53 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +52 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +51 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +50 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +49 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +48 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +47 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +46 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +45 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +44 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +43 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +42 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +41 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +40 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +39 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +38 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +37 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +36 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +35 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +34 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +33 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +32 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +31 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +30 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +29 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +28 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +27 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +26 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +25 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +24 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +23 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +22 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +21 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +20 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +19 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +18 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +17 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +16 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +15 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +14 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +13 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +12 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +11 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +10 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +9 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +8 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +7 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +6 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +5 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +4 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +3 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +2 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +1 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +0 DROP TABLE t2; drop table if exists t1; Warnings: diff --git a/mysql-test/suite/maria/r/maria-gis-rtree-trans.result b/mysql-test/suite/maria/r/maria-gis-rtree-trans.result index b529cde47ca..8ccc1f5bfdf 100644 --- a/mysql-test/suite/maria/r/maria-gis-rtree-trans.result +++ b/mysql-test/suite/maria/r/maria-gis-rtree-trans.result @@ -181,6 +181,7 @@ fid AsText(g) 8 LINESTRING(143 143,157 157) 9 LINESTRING(142 142,158 158) 10 LINESTRING(141 141,159 159) +11 LINESTRING(140 140,160 160) DROP TABLE t1; CREATE TABLE t2 ( fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -308,403 +309,403 @@ fid AsText(g) DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +99 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +98 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +97 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +96 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +95 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +94 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +93 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +92 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +91 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +90 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +89 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +88 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +87 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +86 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +85 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +84 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +83 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +82 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +81 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +80 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +79 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +78 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +77 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +76 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +75 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +74 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +73 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +72 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +71 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +70 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +69 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +68 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +67 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +66 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +65 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +64 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +63 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +62 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +61 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +60 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +59 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +58 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +57 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +56 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +55 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +54 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +53 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +52 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +51 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +50 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +49 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +48 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +47 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +46 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +45 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +44 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +43 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +42 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +41 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +40 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +39 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +38 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +37 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +36 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +35 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +34 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +33 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +32 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +31 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +30 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +29 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +28 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +27 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +26 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +25 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +24 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +23 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +22 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +21 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +20 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +19 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +18 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +17 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +16 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +15 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +14 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +13 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +12 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +11 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +10 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +9 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +8 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +7 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +6 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +5 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +4 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +3 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +2 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +1 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +0 DROP TABLE t2; drop table if exists t1; Warnings: diff --git a/mysql-test/suite/maria/r/maria-gis-rtree.result b/mysql-test/suite/maria/r/maria-gis-rtree.result index 514883729af..9945daae75e 100644 --- a/mysql-test/suite/maria/r/maria-gis-rtree.result +++ b/mysql-test/suite/maria/r/maria-gis-rtree.result @@ -181,6 +181,7 @@ fid AsText(g) 8 LINESTRING(143 143,157 157) 9 LINESTRING(142 142,158 158) 10 LINESTRING(141 141,159 159) +11 LINESTRING(140 140,160 160) DROP TABLE t1; CREATE TABLE t2 ( fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -308,403 +309,403 @@ fid AsText(g) DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +99 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +98 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +97 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +96 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +95 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +94 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +93 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +92 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +91 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +90 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +89 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +88 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +87 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +86 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +85 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +84 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +83 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +82 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +81 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +80 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +79 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +78 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +77 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +76 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +75 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +74 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +73 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +72 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +71 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +70 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +69 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +68 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +67 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +66 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +65 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +64 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +63 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +62 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +61 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +60 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +59 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +58 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +57 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +56 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +55 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +54 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +53 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +52 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +51 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +50 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +49 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +48 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +47 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +46 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +45 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +44 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +43 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +42 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +41 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +40 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +39 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +38 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +37 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +36 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +35 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +34 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +33 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +32 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +31 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +30 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +29 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +28 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +27 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +26 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +25 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +24 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +23 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +22 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +21 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +20 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +19 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +18 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +17 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +16 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +15 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +14 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +13 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +12 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +11 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +10 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))))); SELECT count(*) FROM t2; count(*) -100 +9 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))))); SELECT count(*) FROM t2; count(*) -100 +8 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))))); SELECT count(*) FROM t2; count(*) -100 +7 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))))); SELECT count(*) FROM t2; count(*) -100 +6 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))))); SELECT count(*) FROM t2; count(*) -100 +5 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))))); SELECT count(*) FROM t2; count(*) -100 +4 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))))); SELECT count(*) FROM t2; count(*) -100 +3 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))))); SELECT count(*) FROM t2; count(*) -100 +2 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))))); SELECT count(*) FROM t2; count(*) -100 +1 DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))))); SELECT count(*) FROM t2; count(*) -100 +0 DROP TABLE t2; drop table if exists t1; Warnings: diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index a0b3c354d7e..c5f288388f8 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -23,6 +23,7 @@ #define PH_DATA_OFFSET 8 #define coord_to_float(d) ((double) d) +#define coord_eq(a, b) (a == b) typedef int (*sc_compare_func)(const void*, const void*); @@ -126,28 +127,13 @@ static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node } -static double find_first_different(const Gcalc_heap::Info *p) -{ - if (p->left && (p->left->y != p->y)) - return p->left->y; - if (p->right && (p->right->y != p->y)) - return p->right->y; - if (p->left && p->left->left && (p->left->left->y != p->y)) - return p->left->left->y; - if (p->right && p->right->right && (p->right->right->y != p->y)) - return p->right->right->y; - - return p->y; -} - - static int compare_point_info(const void *e0, const void *e1) { const Gcalc_heap::Info *i0= (const Gcalc_heap::Info *)e0; const Gcalc_heap::Info *i1= (const Gcalc_heap::Info *)e1; - if (i0->y != i1->y) + if (!coord_eq(i0->y, i1->y)) return i0->y > i1->y; - return find_first_different(i0) > find_first_different(i1); + return i0->x > i1->x; } @@ -197,6 +183,8 @@ int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info, double x, double y) { Gcalc_heap::Info *point; + DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y); + if (!(point= m_heap->new_point_info(x, y, Info))) return 1; if (m_first) @@ -234,6 +222,7 @@ void Gcalc_shape_transporter::int_complete() return; } + 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; @@ -253,15 +242,14 @@ inline int GET_DX_DY(double *dxdy, Gcalc_scan_iterator::Gcalc_scan_iterator(size_t blk_size) : Gcalc_dyn_list(blk_size, (sizeof(point) > sizeof(intersection)) ? - sizeof(point) : sizeof(intersection)), - m_slice0(NULL), m_slice1(NULL) + sizeof(point) : sizeof(intersection)) {} Gcalc_scan_iterator::point *Gcalc_scan_iterator::new_slice(Gcalc_scan_iterator::point *example) { point *result= NULL; - Gcalc_dyn_list::Item **result_hook= (Gcalc_dyn_list::Item **)&result; + Gcalc_dyn_list::Item **result_hook= (Gcalc_dyn_list::Item **) &result; while (example) { *result_hook= new_slice_point(); @@ -276,55 +264,156 @@ Gcalc_scan_iterator::point void Gcalc_scan_iterator::init(Gcalc_heap *points) { DBUG_ASSERT(points->ready()); - DBUG_ASSERT(!m_slice0 && !m_slice1); + DBUG_ASSERT(!state0.slice && !state1.slice); if (!(m_cur_pi= points->get_first())) return; m_cur_thread= 0; - m_sav_slice= NULL; m_intersections= NULL; - m_cur_intersection= NULL; - m_y1= m_cur_pi->y; m_next_is_top_point= true; - m_bottom_points_count= 0; + m_events= NULL; + current_state= &state0; + next_state= &state1; + saved_state= &state_s; + next_state->y= m_cur_pi->y; } void Gcalc_scan_iterator::reset() { - if (m_slice0) - free_list(m_slice0); - if (m_slice1) - free_list(m_slice1); - m_slice0= m_slice1= NULL; + state0.slice= state1.slice= m_events= state_s.slice= NULL; + m_intersections= NULL; Gcalc_dyn_list::reset(); } -static bool slice_first_equal_x(const Gcalc_scan_iterator::point *p0, - const Gcalc_scan_iterator::point *p1) + +void Gcalc_scan_iterator::point::copy_core(point *from) { - if (p0->horiz_dir == p1->horiz_dir) - return p0->dx_dy <= p1->dx_dy; - if (p0->horiz_dir) - return p0->dx_dy < 0; - return p1->dx_dy > 0; /* p1->horiz_dir case */ + dx_dy= from->dx_dy; + horiz_dir= from->horiz_dir; + pi= from->pi; + next_pi= from->next_pi; + thread= from->thread; +#ifdef TO_REMOVE + from->next_link= this; +#endif /*TO_REMOVE*/ } -static inline bool slice_first(const Gcalc_scan_iterator::point *p0, - const Gcalc_scan_iterator::point *p1) +int Gcalc_scan_iterator::point::compare_dx_dy(int horiz_dir_a, double dx_dy_a, + int horiz_dir_b, double dx_dy_b) { - if (p0->x != p1->x) - return p0->x < p1->x; - return slice_first_equal_x(p0, p1); + if (!horiz_dir_a && !horiz_dir_b) + { + if (coord_eq(dx_dy_a, dx_dy_b)) + return 0; + return dx_dy_a < dx_dy_b ? -1 : 1; + } + if (!horiz_dir_a) + return -1; + if (!horiz_dir_b) + return 1; + + return 0; +} + + +int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const +{ + if (is_bottom()) + return p->is_bottom() ? 0 : -1; + if (p->is_bottom()) + return 1; + return compare_dx_dy(horiz_dir, dx_dy, p->horiz_dir, p->dx_dy); +} + + +void Gcalc_scan_iterator::mark_event_position1( + point *ep, Gcalc_dyn_list::Item **ep_hook) +{ + if (!next_state->event_position) + { + next_state->event_position= ep; + next_state->event_position_hook= ep_hook; + } + next_state->event_end_hook= &ep->next; +} + + +static int compare_events(const void *e0, const void *e1) +{ + const Gcalc_scan_iterator::point *p0= (const Gcalc_scan_iterator::point *)e0; + const Gcalc_scan_iterator::point *p1= (const Gcalc_scan_iterator::point *)e1; + return p0->cmp_dx_dy(p1) > 0; +} + + +int Gcalc_scan_iterator::arrange_event() +{ + int ev_counter; + point *sp, *new_sp; + point *after_event; + Gcalc_dyn_list::Item **ae_hook= (Gcalc_dyn_list::Item **) &after_event; + + if (m_events) + free_list(m_events); + ev_counter= 0; + DBUG_ASSERT(current_state->event_position == + *current_state->event_position_hook); + for (sp= current_state->event_position; + sp != *current_state->event_end_hook; sp= sp->get_next()) + { + if (sp->is_bottom()) + continue; + if (!(new_sp= new_slice_point())) + return 1; + *new_sp= *sp; + *ae_hook= new_sp; + ae_hook= &new_sp->next; +#ifdef TO_REMOVE + sp->intersection_link= new_sp; +#endif /*TO_REMOVE*/ + ev_counter++; + } + *ae_hook= NULL; + m_events= current_state->event_position; + if (after_event) + { + if (after_event->get_next()) + { + point *cur_p; + after_event= (point *) sort_list(compare_events, after_event, ev_counter); + /* Find last item in the list, ae_hook can change after the sorting */ + for (cur_p= after_event->get_next(); cur_p->get_next(); + cur_p= cur_p->get_next()); + ae_hook= &cur_p->next; + + } + *ae_hook= *current_state->event_end_hook; + *current_state->event_end_hook= NULL; + *current_state->event_position_hook= after_event; + current_state->event_end_hook= ae_hook; + current_state->event_position= after_event; + } + else + { + *current_state->event_position_hook= *current_state->event_end_hook; + *current_state->event_end_hook= NULL; + current_state->event_position= sp; + current_state->event_end_hook= current_state->event_position_hook; + } + + return 0; } int Gcalc_scan_iterator::insert_top_point() { - point *sp= m_slice1; - Gcalc_dyn_list::Item **prev_hook= (Gcalc_dyn_list::Item **)&m_slice1; + point *sp= next_state->slice; + Gcalc_dyn_list::Item **prev_hook= + (Gcalc_dyn_list::Item **) &next_state->slice; point *sp1; point *sp0= new_slice_point(); + point *sp_inc; if (!sp0) return 1; @@ -335,116 +424,182 @@ int Gcalc_scan_iterator::insert_top_point() if (m_cur_pi->left) { sp0->horiz_dir= GET_DX_DY(&sp0->dx_dy, m_cur_pi, m_cur_pi->left); - m_event1= scev_thread; + sp0->event= scev_thread; /*Now just to increase the size of m_slice0 to be same*/ - if (!(sp1= new_slice_point())) + if (!(sp_inc= new_slice_point())) return 1; - sp1->next= m_slice0; - m_slice0= sp1; + sp_inc->next= current_state->slice; + current_state->slice= sp_inc; + if (m_cur_pi->right) + { + if (!(sp1= new_slice_point())) + return 1; + sp1->event= sp0->event= scev_two_threads; +#ifdef TO_REMOVE + sp1->event_pair= sp0; + sp0->event_pair= sp1; +#endif /*TO_REMOVE*/ + sp1->pi= m_cur_pi; + sp1->next_pi= m_cur_pi->right; + sp1->thread= m_cur_thread++; + sp1->x= sp0->x; + sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->right); + /* We have two threads so should decide which one will be first */ + if (sp0->cmp_dx_dy(sp1)>0) + { + point *tmp= sp0; + sp0= sp1; + sp1= tmp; + } + + /*Now just to increase the size of m_slice0 to be same*/ + if (!(sp_inc= new_slice_point())) + return 1; + sp_inc->next= current_state->slice; + current_state->slice= sp_inc; + } } else { - m_event1= scev_single_point; + sp0->event= scev_single_point; sp0->horiz_dir= 0; sp0->dx_dy= 0.0; } - /* First we need to find the place to insert. - Binary search could probably make things faster here, - but structures used aren't suitable, and the - scan is usually not really long */ - for (; sp && slice_first(sp, sp0); - prev_hook= &sp->next, sp=sp->get_next()) + + /* We need to find the place to insert. */ + for (; sp && (sp->x < sp0->x); prev_hook= &sp->next, sp=sp->get_next()) {} - if (m_cur_pi->right) + next_state->event_position_hook= prev_hook; + if (sp && coord_eq(sp->x, sp0->x)) { - m_event1= scev_two_threads; - /*We have two threads so should decide which one will be first*/ - sp1= new_slice_point(); - if (!sp1) - return 1; - sp1->pi= m_cur_pi; - sp1->next_pi= m_cur_pi->right; - sp1->thread= m_cur_thread++; - sp1->x= sp0->x; - sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->right); - if (slice_first_equal_x(sp1, sp0)) + next_state->event_position= sp; + do { - point *tmp= sp0; - sp0= sp1; - sp1= tmp; - } - sp1->next= sp; - sp0->next= sp1; - - /*Now just to increase the size of m_slice0 to be same*/ - if (!(sp1= new_slice_point())) - return 1; - sp1->next= m_slice0; - m_slice0= sp1; + if (!sp->event) + sp->event= scev_intersection; + prev_hook= &sp->next; + sp= sp->get_next(); + } while (sp && coord_eq(sp->x, sp0->x)); } else - sp0->next= sp; + next_state->event_position= sp0; *prev_hook= sp0; - m_event_position1= sp0; - - return 0; -} - -enum -{ - intersection_normal= 1, - intersection_forced= 2 -}; - - -static int intersection_found(const Gcalc_scan_iterator::point *sp0, - const Gcalc_scan_iterator::point *sp1, - unsigned int bottom_points_count) -{ - if (sp1->x < sp0->x) - return intersection_normal; - if (sp1->is_bottom() && !sp0->is_bottom() && - (bottom_points_count > 1)) - return intersection_forced; + if (sp0->event == scev_two_threads) + { + sp1->next= sp; + sp0->next= sp1; + next_state->event_end_hook= &sp1->next; + } + else + { + sp0->next= sp; + next_state->event_end_hook= &sp0->next; + } return 0; } int Gcalc_scan_iterator::normal_scan() { - if (m_next_is_top_point) - if (insert_top_point()) - return 1; + point *sp; + Gcalc_dyn_list::Item **sp_hook; + Gcalc_heap::Info *next_pi; + point *first_bottom_point= NULL; - point *tmp= m_slice0; - m_slice0= m_slice1; - m_slice1= tmp; - m_event0= m_event1; - m_event_position0= m_event_position1; - m_y0= m_y1; - - if (!(m_cur_pi= m_cur_pi->get_next())) + if (m_next_is_top_point && insert_top_point()) + return 1; + + for (next_pi= m_cur_pi->get_next(); + next_pi && + coord_eq(m_cur_pi->x, next_pi->x) && + coord_eq(m_cur_pi->y, next_pi->y); + next_pi= next_pi->get_next()) { - free_list(m_slice1); - m_slice1= NULL; + DBUG_ASSERT(coord_eq(next_state->event_position->x, next_pi->x)); + next_state->clear_event_position(); + m_next_is_top_point= true; + for (sp= next_state->slice, + sp_hook= (Gcalc_dyn_list::Item **) &next_state->slice; sp; + sp_hook= &sp->next, sp= sp->get_next()) + { + if (sp->next_pi == next_pi) /* End of the segment */ + { + sp->x= coord_to_float(next_pi->x); + sp->pi= next_pi; + sp->next_pi= next_pi->left; + m_next_is_top_point= false; + if (next_pi->is_bottom()) + { + if (first_bottom_point) + { + first_bottom_point->event= sp->event= scev_two_ends; +#ifdef TO_REMOVE + first_bottom_point->event_pair= sp; + sp->event_pair= first_bottom_point; +#endif /*TO_REMOVE*/ + } + else + { + first_bottom_point= sp; + sp->event= scev_end; + } + } + else + { + sp->event= scev_point; + sp->horiz_dir= GET_DX_DY(&sp->dx_dy, next_pi, next_pi->left); + } + mark_event_position1(sp, sp_hook); + } + else if (coord_eq(sp->x, next_pi->x)) + { + if (!sp->event) + sp->event= scev_intersection; + mark_event_position1(sp, sp_hook); + } + } + m_cur_pi= next_pi; + if (m_next_is_top_point && insert_top_point()) + return 1; + } + + /* Swap current <-> next */ + { + slice_state *tmp= current_state; + current_state= next_state; + next_state= tmp; + } + + if (arrange_event()) + return 1; + + point *sp0= current_state->slice; + point *sp1= next_state->slice; + point *prev_sp1= NULL; + + if (!(m_cur_pi= next_pi)) + { + free_list(sp1); + next_state->slice= NULL; +#ifdef TO_REMOVE + for (; sp0; sp0= sp0->get_next()) + sp0->next_link= NULL; +#endif /*TO_REMOVE*/ return 0; } Gcalc_heap::Info *cur_pi= m_cur_pi; - m_y1= coord_to_float(cur_pi->y); - m_h= m_y1 - m_y0; + next_state->y= coord_to_float(cur_pi->y); - point *sp0= m_slice0; - point *sp1= m_slice1; - point *prev_sp1= NULL; - m_bottom_points_count= 0; + first_bottom_point= NULL; m_next_is_top_point= true; bool intersections_found= false; + next_state->clear_event_position(); for (; sp0; sp0= sp0->get_next()) { @@ -454,41 +609,57 @@ int Gcalc_scan_iterator::normal_scan() sp1->pi= cur_pi; sp1->thread= sp0->thread; sp1->next_pi= cur_pi->left; - if (cur_pi->left) - sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->left); +#ifdef TO_REMOVE + sp0->next_link= sp1; +#endif /*TO_REMOVE*/ m_next_is_top_point= false; if (sp1->is_bottom()) { - ++m_bottom_points_count; - if (m_bottom_points_count == 1) + if (!first_bottom_point) { - m_event1= scev_end; - m_event_position1= sp1; + sp1->event= scev_end; + first_bottom_point= sp1; } else - m_event1= scev_two_ends; + { + first_bottom_point->event= sp1->event= scev_two_ends; +#ifdef TO_REMOVE + sp1->event_pair= first_bottom_point; + first_bottom_point->event_pair= sp1; +#endif /*TO_REMOVE*/ + } } else { - m_event1= scev_point; - m_event_position1= sp1; + sp1->event= scev_point; + sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->left); } + mark_event_position1(sp1, + prev_sp1 ? &prev_sp1->next : + (Gcalc_dyn_list::Item **) &next_state->slice); } - else if (!sp0->is_bottom()) + else { /* Cut current string with the height of the new point*/ sp1->copy_core(sp0); - sp1->x= sp1->horiz_dir ? sp0->x : + sp1->x= sp1->horiz_dir ? coord_to_float(cur_pi->x) : (coord_to_float(sp1->pi->x) + - (m_y1-coord_to_float(sp1->pi->y)) * sp1->dx_dy); + (next_state->y-coord_to_float(sp1->pi->y)) * sp1->dx_dy); + if (coord_eq(sp1->x, cur_pi->x)) + { + mark_event_position1(sp1, + prev_sp1 ? &prev_sp1->next : + (Gcalc_dyn_list::Item **) &next_state->slice); + sp1->event= scev_intersection; + } + else + sp1->event= scev_none; } - else /* Skip the bottom point in slice0 */ - continue; intersections_found= intersections_found || - (prev_sp1 && intersection_found(prev_sp1, sp1, m_bottom_points_count)); + (prev_sp1 && prev_sp1->x > sp1->x); prev_sp1= sp1; sp1= sp1->get_next(); @@ -499,7 +670,7 @@ int Gcalc_scan_iterator::normal_scan() if (prev_sp1) prev_sp1->next= NULL; else - m_slice1= NULL; + next_state->slice= NULL; free_list(sp1); } @@ -513,7 +684,7 @@ int Gcalc_scan_iterator::normal_scan() #define INTERSECTION_ZERO 0.000000000001 int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, - int isc_kind, Gcalc_dyn_list::Item ***p_hook) + Gcalc_dyn_list::Item ***p_hook) { intersection *isc= new_intersection(); @@ -524,16 +695,12 @@ int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, *p_hook= &isc->next; isc->thread_a= a->thread; isc->thread_b= b->thread; - if (isc_kind == intersection_forced) - { - isc->y= m_y1; - isc->x= a->x; - return 0; - } /* intersection_normal */ - const point *a0= a->precursor; - const point *b0= b->precursor; + const point *a0= a->intersection_link; + const point *b0= b->intersection_link; + DBUG_ASSERT(!a0->horiz_dir || !b0->horiz_dir); + if (!a0->horiz_dir && !b0->horiz_dir) { double dk= a0->dx_dy - b0->dx_dy; @@ -541,11 +708,11 @@ int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, if (fabs(dk) < INTERSECTION_ZERO) dy= 0.0; - isc->y= m_y0 + dy; + isc->y= current_state->y + dy; isc->x= a0->x + dy*a0->dx_dy; return 0; } - isc->y= m_y1; + isc->y= next_state->y; isc->x= a0->horiz_dir ? b->x : a->x; return 0; } @@ -553,19 +720,18 @@ int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, int Gcalc_scan_iterator::find_intersections() { - point *sp1= m_slice1; + point *sp1= next_state->slice; Gcalc_dyn_list::Item **hook; m_n_intersections= 0; { /* Set links between slicepoints */ - point *sp0= m_slice0; + point *sp0= current_state->slice; for (; sp1; sp0= sp0->get_next(),sp1= sp1->get_next()) { - while (sp0->is_bottom()) - sp0= sp0->get_next(); + DBUG_ASSERT(!sp0->is_bottom()); DBUG_ASSERT(sp0->thread == sp1->thread); - sp1->precursor= sp0; + sp1->intersection_link= sp0; } } @@ -575,23 +741,18 @@ int Gcalc_scan_iterator::find_intersections() point *last_possible_isc= NULL; do { - sp1= m_slice1; - point **pprev_s1= &m_slice1; + point **pprev_s1= &next_state->slice; intersections_found= false; - unsigned int bottom_points_count= sp1->is_bottom() ? 1:0; - sp1= m_slice1->get_next(); - int isc_kind; + sp1= next_state->slice->get_next(); point *cur_possible_isc= NULL; for (; sp1 != last_possible_isc; pprev_s1= (point **)(&(*pprev_s1)->next), sp1= sp1->get_next()) { - if (sp1->is_bottom()) - ++bottom_points_count; - if (!(isc_kind=intersection_found(*pprev_s1, sp1, bottom_points_count))) - continue; point *prev_s1= *pprev_s1; + if (prev_s1->x <= sp1->x) + continue; intersections_found= true; - if (add_intersection(prev_s1, sp1, isc_kind, &hook)) + if (add_intersection(prev_s1, sp1, &hook)) return 1; *pprev_s1= sp1; prev_s1->next= sp1->next; @@ -611,7 +772,9 @@ static int compare_intersections(const void *e0, const void *e1) { Gcalc_scan_iterator::intersection *i0= (Gcalc_scan_iterator::intersection *)e0; Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1; - return i0->y > i1->y; + if (i0->y != i1->y) + return i0->y > i1->y; + return i0->x > i1->x; } @@ -624,144 +787,131 @@ inline void Gcalc_scan_iterator::sort_intersections() int Gcalc_scan_iterator::handle_intersections() { - DBUG_ASSERT(m_slice1->next); + DBUG_ASSERT(next_state->slice->next); if (find_intersections()) return 1; sort_intersections(); - m_sav_slice= m_slice1; - m_sav_y= m_y1; - m_slice1= new_slice(m_sav_slice); - - m_cur_intersection= m_intersections; - m_pre_intersection_hook= NULL; - return intersection_scan(); -} - - -void Gcalc_scan_iterator::pop_suitable_intersection() -{ - intersection *prev_i= m_cur_intersection; - intersection *cur_i= prev_i->get_next(); - for (; cur_i; prev_i= cur_i, cur_i= cur_i->get_next()) + /* Swap saved <-> next */ { - point *prev_p= m_slice0; - point *sp= prev_p->get_next(); - for (; sp; prev_p= sp, sp= sp->get_next()) - { - if ((prev_p->thread == cur_i->thread_a) && - (sp->thread == cur_i->thread_b)) - { - /* Move cur_t on the top of the list */ - if (prev_i == m_cur_intersection) - { - m_cur_intersection->next= cur_i->next; - cur_i->next= m_cur_intersection; - m_cur_intersection= cur_i; - } - else - { - Gcalc_dyn_list::Item *tmp= m_cur_intersection->next; - m_cur_intersection->next= cur_i->next; - prev_i->next= m_cur_intersection; - m_cur_intersection= cur_i; - cur_i->next= tmp; - } - return; - } - } + slice_state *tmp= next_state; + next_state= saved_state; + saved_state= tmp; } - DBUG_ASSERT(0); + /* We need the next slice to be just equal */ + next_state->slice= new_slice(saved_state->slice); + m_cur_intersection= m_intersections; + return intersection_scan(); } int Gcalc_scan_iterator::intersection_scan() { - if (m_pre_intersection_hook) /*Skip the first point*/ + point *sp0, *sp1; + Gcalc_dyn_list::Item **hook; + intersection *next_intersection; + + if (m_cur_intersection != m_intersections) { - point *next= (*m_pre_intersection_hook)->get_next(); - (*m_pre_intersection_hook)->next= next->next; - next->next= *m_pre_intersection_hook; - *m_pre_intersection_hook= next; - m_event0= scev_intersection; - m_event_position0= next; - point *tmp= m_slice1; - m_slice1= m_slice0; - m_slice0= tmp; - m_y0= m_y1; - m_cur_intersection= m_cur_intersection->get_next(); + /* Swap current <-> next */ + { + slice_state *tmp= current_state; + current_state= next_state; + next_state= tmp; + } + + if (arrange_event()) + return 1; + if (!m_cur_intersection) { - m_h= m_sav_y - m_y1; - m_y1= m_sav_y; - free_list(m_slice1); - m_slice1= m_sav_slice; + saved_state->event_position_hook= + (Gcalc_dyn_list::Item **) &saved_state->slice; +#ifdef TO_REMOVE + for (sp0= current_state->slice, sp1= saved_state->slice; + sp0; + sp0= sp0->get_next(), sp1= sp1->get_next()) + { + sp0->next_link= sp1; + if (sp1->get_next() == saved_state->event_position) + saved_state->event_position_hook= &sp1->next; + } +#endif /*TO_REMOVE*/ + for (sp1= saved_state->slice; sp1; sp1= sp1->get_next()) + { + if (sp1->get_next() == saved_state->event_position) + saved_state->event_position_hook= &sp1->next; + } + /* Swap saved <-> next */ + { + slice_state *tmp= next_state; + next_state= saved_state; + saved_state= tmp; + } + free_list(saved_state->slice); + saved_state->slice= NULL; + free_list(m_intersections); + m_intersections= NULL; return 0; } } - m_y1= m_cur_intersection->y; - m_h= m_y1 - m_y0; + next_state->y= m_cur_intersection->y; - point *sp0; - point **psp1; +found_equal_intersection: + sp0= current_state->slice; + hook= (Gcalc_dyn_list::Item **) &next_state->slice; + sp1= next_state->slice; + next_state->clear_event_position(); -redo_loop: - sp0= m_slice0; - psp1= &m_slice1; - for (; sp0; sp0= sp0->get_next()) + for (; sp0; + hook= &sp1->next, sp1= sp1->get_next(), sp0= sp0->get_next()) { - point *sp1= *psp1; - if (sp0->thread == m_cur_intersection->thread_a) - { - point *next_s0= sp0; - /* Skip Bottom points */ - do - next_s0= next_s0->get_next(); - while(next_s0->is_bottom()); /* We always find nonbottom point here*/ - /* If the next point's thread isn't the thread of intersection, - we try to find suitable intersection */ - if (next_s0->thread != m_cur_intersection->thread_b) - { - /* It's really rare case - sometimes happen when - there's two intersections with the same Y - Move suitable one to the beginning of the list - */ - pop_suitable_intersection(); - goto redo_loop; - } - m_pre_intersection_hook= psp1; - sp1->copy_core(sp0); - sp1->x= m_cur_intersection->x; - sp0= next_s0; - sp1= sp1->get_next(); - sp1->copy_core(sp0); - sp1->x= m_cur_intersection->x; - psp1= (point **)&sp1->next; - continue; - } - if (!sp0->is_bottom()) + if (sp0->thread == m_cur_intersection->thread_a || + sp0->thread == m_cur_intersection->thread_b) { sp1->copy_core(sp0); - sp1->x= sp1->horiz_dir ? sp0->x : - (coord_to_float(sp1->pi->x) + - (m_y1-coord_to_float(sp1->pi->y)) * sp1->dx_dy); + sp1->x= m_cur_intersection->x; + sp1->event= scev_intersection; + mark_event_position1(sp1, hook); } else - /* Skip bottom point */ - continue; - psp1= (point **)&sp1->next; + { + sp1->copy_core(sp0); + sp1->x= sp1->horiz_dir ? + m_cur_intersection->x : + coord_to_float(sp1->pi->x) + + (next_state->y-coord_to_float(sp1->pi->y)) * sp1->dx_dy; + if (coord_eq(sp1->x, m_cur_intersection->x)) + { + sp1->event= scev_intersection; + mark_event_position1(sp1, hook); + } + else + sp1->event= scev_none; + } } - if (*psp1) + if (sp1) { - free_list(*psp1); - *psp1= NULL; + free_list(sp1); + *hook= NULL; } + next_intersection= m_cur_intersection->get_next(); + if (next_intersection && + coord_eq(next_intersection->x, m_cur_intersection->x) && + coord_eq(next_intersection->y, m_cur_intersection->y)) + { + m_cur_intersection= next_intersection; + goto found_equal_intersection; + } + m_cur_intersection= next_intersection; + return 0; } #endif /* HAVE_SPATIAL */ + diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index 3ea910dc4fd..9ffe39dd370 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -236,6 +236,7 @@ public: enum Gcalc_scan_events { + scev_none= 0, scev_point= 1, /* Just a new point in thread */ scev_thread= 2, /* Start of the new thread */ scev_two_threads= 4, /* A couple of new threads started */ @@ -268,7 +269,13 @@ public: Gcalc_heap::Info *pi; Gcalc_heap::Info *next_pi; sc_thread_id thread; - const point *precursor; /* used as a temporary field */ + + const point *intersection_link; + Gcalc_scan_events event; +#ifdef TO_REMOVE + const point *event_pair; + point *next_link; +#endif /*TO_REMOVE*/ inline const point *c_get_next() const { return (const point *)next; } @@ -276,15 +283,17 @@ public: gcalc_shape_info get_shape() const { return pi->shape; } inline point *get_next() { return (point *)next; } inline const point *get_next() const { return (const point *)next; } - /* copies all but 'next' 'x' and 'precursor' */ - void copy_core(const point *from) + void copy_core(point *from); + /* Compare the dx_dy parameters regarding the horiz_dir */ + /* returns -1 if less, 0 if equal, 1 if bigger */ + static int compare_dx_dy(int horiz_dir_a, double dx_dy_a, + int horiz_dir_b, double dx_dy_b); + int cmp_dx_dy(const point *p) const; + int simple_event() const { - dx_dy= from->dx_dy; - horiz_dir= from->horiz_dir; - pi= from->pi; - next_pi= from->next_pi; - thread= from->thread; + return !next ? (event & (scev_point | scev_end)) : + (!next->next && event == scev_two_ends); } #ifndef DBUG_OFF void dbug_print(); @@ -301,6 +310,22 @@ public: inline intersection *get_next() { return (intersection *)next; } }; + class slice_state + { + public: + point *slice; + point *event_position; + Gcalc_dyn_list::Item **event_position_hook; + Gcalc_dyn_list::Item **event_end_hook; + double y; + slice_state() : slice(NULL) {} + void clear_event_position() + { + event_position= NULL; + event_end_hook= (Gcalc_dyn_list::Item **) &event_position; + } + }; + public: Gcalc_scan_iterator(size_t blk_size= 8192); @@ -309,50 +334,46 @@ public: int step() { DBUG_ASSERT(more_points()); - return m_cur_intersection ? intersection_scan() : normal_scan(); + return m_intersections ? intersection_scan() : normal_scan(); } inline Gcalc_heap::Info *more_points() { return m_cur_pi; } inline bool more_trapezoids() { return m_cur_pi && m_cur_pi->next; } - inline Gcalc_scan_events get_event() const { return m_event0; } + inline const point *get_events() const + { return m_events; } inline const point *get_event_position() const - { return m_event_position0; } - inline const point *get_b_slice() const { return m_slice0; } - inline const point *get_t_slice() const { return m_slice1; } - inline double get_h() const { return m_h; } - inline double get_y() const { return m_y0; } + { return current_state->event_position; } + inline const point *get_event_end() const + { return (point *) *current_state->event_end_hook; } + inline const point *get_b_slice() const { return current_state->slice; } + inline const point *get_t_slice() const { return next_state->slice; } + inline double get_h() const { return current_state->y - next_state->y; } + inline double get_y() const { return current_state->y; } private: Gcalc_heap::Info *m_cur_pi; - point *m_slice0; - point *m_slice1; - point *m_sav_slice; + slice_state state0, state1, state_s; + slice_state *current_state; + slice_state *next_state; + slice_state *saved_state; + intersection *m_intersections; int m_n_intersections; intersection *m_cur_intersection; - point **m_pre_intersection_hook; - double m_h; - double m_y0; - double m_y1; - double m_sav_y; bool m_next_is_top_point; - unsigned int m_bottom_points_count; sc_thread_id m_cur_thread; - Gcalc_scan_events m_event0, m_event1; - point *m_event_position0; - point *m_event_position1; + point *m_events; int normal_scan(); int intersection_scan(); void sort_intersections(); int handle_intersections(); int insert_top_point(); int add_intersection(const point *a, const point *b, - int isc_kind, Gcalc_dyn_list::Item ***p_hook); + Gcalc_dyn_list::Item ***p_hook); int find_intersections(); - void pop_suitable_intersection(); intersection *new_intersection() { @@ -363,6 +384,8 @@ private: return (point *)new_item(); } point *new_slice(point *example); + int arrange_event(); + void mark_event_position1(point *ep, Gcalc_dyn_list::Item **ep_hook); }; @@ -427,6 +450,8 @@ public: inline const Gcalc_heap::Info *get_pi() const { return sp->pi; } inline gcalc_shape_info get_shape() const { return sp->get_shape(); } inline double get_x() const { return sp->x; } + inline void restart(const Gcalc_scan_iterator *scan_i) + { sp= scan_i->get_b_slice(); } }; #endif /*GCALC_SLICESCAN_INCLUDED*/ diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 25e71d7bfca..ab173803323 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -106,13 +106,26 @@ int Gcalc_function::reserve_op_buffer(uint n_ops) int Gcalc_function::alloc_states() { - if (function_buffer.reserve((n_shapes+1) * sizeof(int))) + if (function_buffer.reserve((n_shapes+1) * 2 * sizeof(int))) return 1; i_states= (int *) (function_buffer.ptr() + ALIGN_SIZE(function_buffer.length())); + saved_i_states= i_states + (n_shapes + 1); return 0; } +void Gcalc_function::save_states() +{ + memcpy(saved_i_states, i_states, (n_shapes+1) * sizeof(int)); +} + + +void Gcalc_function::restore_states() +{ + memcpy(i_states, saved_i_states, (n_shapes+1) * sizeof(int)); +} + + int Gcalc_function::count_internal() { int c_op= uint4korr(cur_func); @@ -170,36 +183,64 @@ void Gcalc_function::reset() int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it) { + const Gcalc_scan_iterator::point *eq_start, *cur_eq, *events; + while (scan_it.more_points()) { if (scan_it.step()) return -1; - Gcalc_scan_events ev= scan_it.get_event(); - const Gcalc_scan_iterator::point *evpos= scan_it.get_event_position(); - if (ev & (scev_point | scev_end | scev_two_ends)) + events= scan_it.get_events(); + + /* these kinds of events don't change the function */ + if (events->simple_event()) continue; + Gcalc_point_iterator pit(&scan_it); clear_state(); - for (Gcalc_point_iterator pit(&scan_it); pit.point() != evpos; ++pit) + /* Walk to the event, marking polygons we met */ + for (; pit.point() != scan_it.get_event_position(); ++pit) { gcalc_shape_info si= pit.point()->get_shape(); if ((get_shape_kind(si) == Gcalc_function::shape_polygon)) invert_state(si); } - invert_state(evpos->get_shape()); - - if (ev == scev_intersection) - { - const Gcalc_scan_iterator::point *evnext= evpos->c_get_next(); - if ((get_shape_kind(evpos->get_shape()) != - Gcalc_function::shape_polygon) || - (get_shape_kind(evnext->get_shape()) != - Gcalc_function::shape_polygon)) - invert_state(evnext->get_shape()); - } + save_states(); + /* Check the status of the event point */ + for (; events; events= events->get_next()) + set_on_state(events->get_shape()); if (count()) return 1; + + if (scan_it.get_event_position() == scan_it.get_event_end()) + continue; + + /* Check the status after the event */ + restore_states(); + eq_start= pit.point(); + do + { + ++pit; + if (pit.point() != scan_it.get_event_end() && + eq_start->cmp_dx_dy(pit.point()) == 0) + continue; + save_states(); + for (cur_eq= eq_start; cur_eq != pit.point(); + cur_eq= cur_eq->get_next()) + set_on_state(cur_eq->get_shape()); + if (count()) + return 1; + restore_states(); + for (cur_eq= eq_start; cur_eq != pit.point(); cur_eq= cur_eq->get_next()) + { + gcalc_shape_info si= cur_eq->get_shape(); + if ((get_shape_kind(si) == Gcalc_function::shape_polygon)) + invert_state(si); + } + if (count()) + return 1; + eq_start= pit.point(); + } while (pit.point() != scan_it.get_event_end()); } return 0; } @@ -457,6 +498,10 @@ void Gcalc_operation_reducer::init(Gcalc_function *fn, modes mode) m_fn= fn; m_mode= mode; m_first_active_thread= NULL; + m_lines= NULL; + m_lines_hook= (Gcalc_dyn_list::Item **) &m_lines; + m_poly_borders= NULL; + m_poly_borders_hook= (Gcalc_dyn_list::Item **) &m_poly_borders; } @@ -470,10 +515,10 @@ Gcalc_operation_reducer(Gcalc_function *fn, modes mode, size_t blk_size) : inline int Gcalc_operation_reducer::continue_range(active_thread *t, - const Gcalc_heap::Info *p) + const Gcalc_heap::Info *p, + int horiz_dir, double dx_dy) { - DBUG_ASSERT(t->result_range); - res_point *rp= add_res_point(); + res_point *rp= add_res_point(t->rp->type); if (!rp) return 1; rp->glue= NULL; @@ -482,16 +527,17 @@ inline int Gcalc_operation_reducer::continue_range(active_thread *t, rp->intersection_point= false; rp->pi= p; t->rp= rp; + t->horiz_dir= horiz_dir; + t->dx_dy= dx_dy; return 0; } inline int Gcalc_operation_reducer::continue_i_range(active_thread *t, - const Gcalc_heap::Info *p, - double x, double y) + double x, double y, + int horiz_dir, double dx_dy) { - DBUG_ASSERT(t->result_range); - res_point *rp= add_res_point(); + res_point *rp= add_res_point(t->rp->type); if (!rp) return 1; rp->glue= NULL; @@ -499,133 +545,10 @@ inline int Gcalc_operation_reducer::continue_i_range(active_thread *t, t->rp->up= rp; rp->intersection_point= true; rp->x= x; - rp->pi= p; rp->y= y; t->rp= rp; - return 0; -} - -inline int Gcalc_operation_reducer::start_range(active_thread *t, - const Gcalc_heap::Info *p) -{ - res_point *rp= add_res_point(); - if (!rp) - return 1; - rp->glue= rp->down= NULL; - rp->intersection_point= false; - rp->pi= p; - t->result_range= 1; - t->rp= rp; - return 0; -} - -inline int Gcalc_operation_reducer::start_i_range(active_thread *t, - const Gcalc_heap::Info *p, - double x, double y) -{ - res_point *rp= add_res_point(); - if (!rp) - return 1; - rp->glue= rp->down= NULL; - rp->intersection_point= true; - rp->x= x; - rp->y= y; - rp->pi= p; - t->result_range= 1; - t->rp= rp; - return 0; -} - -inline int Gcalc_operation_reducer::end_range(active_thread *t, - const Gcalc_heap::Info *p) -{ - res_point *rp= add_res_point(); - if (!rp) - return 1; - rp->glue= rp->up= NULL; - rp->down= t->rp; - rp->intersection_point= false; - rp->pi= p; - t->rp->up= rp; - t->result_range= 0; - return 0; -} - -inline int Gcalc_operation_reducer::end_i_range(active_thread *t, - const Gcalc_heap::Info *p, - double x, double y) -{ - res_point *rp= add_res_point(); - if (!rp) - return 1; - rp->glue= rp->up= NULL; - rp->down= t->rp; - rp->intersection_point= true; - rp->x= x; - rp->pi= p; - rp->y= y; - t->rp->up= rp; - t->result_range= 0; - return 0; -} - -int Gcalc_operation_reducer::start_couple(active_thread *t0, active_thread *t1, - const Gcalc_heap::Info *p, - const active_thread *prev_range) -{ - res_point *rp0, *rp1; - if (!(rp0= add_res_point()) || !(rp1= add_res_point())) - return 1; - rp0->glue= rp1; - rp1->glue= rp0; - rp0->intersection_point= rp1->intersection_point= false; - rp0->down= rp1->down= NULL; - rp0->pi= rp1->pi= p; - t0->rp= rp0; - t1->rp= rp1; - if (prev_range) - { - rp0->outer_poly= prev_range->thread_start; - t1->thread_start= prev_range->thread_start; - } - else - { - rp0->outer_poly= 0; - t0->thread_start= rp0; - } - return 0; -} - -int Gcalc_operation_reducer::start_i_couple(active_thread *t0, active_thread *t1, - const Gcalc_heap::Info *p0, - const Gcalc_heap::Info *p1, - double x, double y, - const active_thread *prev_range) -{ - res_point *rp0, *rp1; - if (!(rp0= add_res_point()) || !(rp1= add_res_point())) - return 1; - rp0->glue= rp1; - rp1->glue= rp0; - rp0->pi= p0; - rp1->pi= p1; - rp0->intersection_point= rp1->intersection_point= true; - rp0->down= rp1->down= NULL; - rp0->x= rp1->x= x; - rp0->y= rp1->y= y; - t0->result_range= t1->result_range= 1; - t0->rp= rp0; - t1->rp= rp1; - if (prev_range) - { - rp0->outer_poly= prev_range->thread_start; - t1->thread_start= prev_range->thread_start; - } - else - { - rp0->outer_poly= 0; - t0->thread_start= rp0; - } + t->horiz_dir= horiz_dir; + t->dx_dy= dx_dy; return 0; } @@ -633,8 +556,9 @@ int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p) { res_point *rp0, *rp1; - DBUG_ASSERT(t1->result_range); - if (!(rp0= add_res_point()) || !(rp1= add_res_point())) + DBUG_ASSERT(t0->rp->type == t1->rp->type); + if (!(rp0= add_res_point(t0->rp->type)) || + !(rp1= add_res_point(t0->rp->type))) return 1; rp0->down= t0->rp; rp1->down= t1->rp; @@ -645,208 +569,69 @@ int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1, t1->rp->up= rp1; rp0->intersection_point= rp1->intersection_point= false; rp0->pi= rp1->pi= p; - t0->result_range= t1->result_range= 0; return 0; } -int Gcalc_operation_reducer::end_i_couple(active_thread *t0, active_thread *t1, - const Gcalc_heap::Info *p0, - const Gcalc_heap::Info *p1, - double x, double y) -{ - res_point *rp0, *rp1; - if (!(rp0= add_res_point()) || !(rp1= add_res_point())) - return 1; - rp0->down= t0->rp; - rp1->down= t1->rp; - rp0->pi= p0; - rp1->pi= p1; - rp1->glue= rp0; - rp0->glue= rp1; - rp0->up= rp1->up= NULL; - rp0->intersection_point= rp1->intersection_point= true; - rp0->x= rp1->x= x; - rp0->y= rp1->y= y; - t0->result_range= t1->result_range= 0; - t0->rp->up= rp0; - t1->rp->up= rp1; - return 0; -} - -int Gcalc_operation_reducer::add_single_point(const Gcalc_heap::Info *p) -{ - res_point *rp= add_res_point(); - if (!rp) - return 1; - rp->glue= rp->up= rp->down= NULL; - rp->intersection_point= false; - rp->pi= p; - rp->x= p->x; - rp->y= p->y; - return 0; -} - -int Gcalc_operation_reducer::add_i_single_point(const Gcalc_heap::Info *p, - double x, double y) -{ - res_point *rp= add_res_point(); - if (!rp) - return 1; - rp->glue= rp->up= rp->down= NULL; - rp->intersection_point= true; - rp->x= x; - rp->pi= p; - rp->y= y; - return 0; -} - -int Gcalc_operation_reducer:: -handle_lines_intersection(active_thread *t0, active_thread *t1, - const Gcalc_heap::Info *p0, const Gcalc_heap::Info *p1, - double x, double y) -{ - m_fn->invert_state(p0->shape); - if (p0->shape != p1->shape) - m_fn->invert_state(p1->shape); - int intersection_state= m_fn->count(); - if ((t0->result_range | t1->result_range) == intersection_state) - return 0; - - if (t0->result_range && - (end_i_range(t0, p1, x, y) || start_i_range(t0, p1, x, y))) - return 1; - - if (t1->result_range && - (end_i_range(t1, p0, x, y) || start_i_range(t1, p0, x, y))) - return 1; - - if (intersection_state && - add_i_single_point(p0, x, y)) - return 1; - - return 0; -} - -inline int Gcalc_operation_reducer:: -handle_line_polygon_intersection(active_thread *l, const Gcalc_heap::Info *pl, - int line_state, int poly_state, - double x, double y) -{ - int range_after= ~poly_state & line_state; - if (l->result_range == range_after) - return 0; - return range_after ? start_i_range(l, pl, x, y) : end_i_range(l, pl, x, y); -} - -static inline void switch_athreads(Gcalc_operation_reducer::active_thread *t0, - Gcalc_operation_reducer::active_thread *t1, - Gcalc_dyn_list::Item **hook) -{ - *hook= t1; - t0->next= t1->next; - t1->next= t0; -} - -inline int Gcalc_operation_reducer:: -handle_polygons_intersection(active_thread *t0, active_thread *t1, - Gcalc_dyn_list::Item **t_hook, - const Gcalc_heap::Info *p0, - const Gcalc_heap::Info *p1, - int prev_state, double x, double y, - const active_thread *prev_range) -{ - m_fn->invert_state(p0->shape); - int state_11= m_fn->count(); - m_fn->invert_state(p1->shape); - int state_2= m_fn->count(); - int state_01= prev_state ^ t0->result_range; - if ((prev_state == state_01) && (prev_state == state_2)) - { - if (state_11 == prev_state) - { - switch_athreads(t0, t1, t_hook); - return 0; - } - return start_i_couple(t0, t1, p0, p1, x, y, prev_range); - } - if (prev_state == state_2) - { - if (state_01 == state_11) - { - if (m_mode & polygon_selfintersections_allowed) - { - switch_athreads(t0, t1, t_hook); - return 0; - } - if (prev_state != (m_mode & prefer_big_with_holes)) - return continue_i_range(t0, p0, x, y) || continue_i_range(t1, p1, x, y); - return end_i_couple(t0, t1, p0, p1, x, y) || - start_i_couple(t0, t1, p0, p1, x, y, prev_range); - } - else - return end_i_couple(t0, t1, p0, p1, x, y); - } - if (state_01 ^ state_11) - { - switch_athreads(t0, t1, t_hook); - return 0; - } - - active_thread *thread_to_continue; - const Gcalc_heap::Info *way_to_go; - if (prev_state == state_01) - { - thread_to_continue= t1; - way_to_go= p1; - } - else - { - thread_to_continue= t0; - way_to_go= p0; - } - return continue_i_range(thread_to_continue, way_to_go, x, y); -} int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { Gcalc_point_iterator pi(si); - active_thread *cur_t= m_first_active_thread; - Gcalc_dyn_list::Item **at_hook= (Gcalc_dyn_list::Item **)&m_first_active_thread; - const active_thread *prev_range; - int prev_state; + const Gcalc_heap::Info *event_point= NULL; + int prev_state= 0; + int sav_prev_state; + active_thread *prev_range= NULL; + const Gcalc_scan_iterator::point *events; + const Gcalc_scan_iterator::point *eq_start; + active_thread **cur_t_hook= &m_first_active_thread; + active_thread **starting_t_hook; + active_thread *bottom_threads= NULL; + active_thread *eq_thread, *point_thread;; - if (si->get_event() & (scev_point | scev_end | scev_two_ends)) + m_fn->clear_state(); + /* Walk to the event, remembering what is needed. */ + for (; pi.point() != si->get_event_position(); + ++pi, cur_t_hook= (active_thread **) &(*cur_t_hook)->next) { - for (; pi.point() != si->get_event_position(); ++pi, cur_t= cur_t->get_next()) - at_hook= &cur_t->next; + active_thread *cur_t= *cur_t_hook; + if (cur_t->enabled() && + cur_t->rp->type == Gcalc_function::shape_polygon) + { + prev_state^= 1; + prev_range= prev_state ? cur_t : 0; + } + if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon) + m_fn->invert_state(pi.get_shape()); + } - switch (si->get_event()) + events= si->get_events(); + if (events->simple_event()) + { + active_thread *cur_t= *cur_t_hook; + switch (events->event) { case scev_point: { - if (cur_t->result_range && - continue_range(cur_t, pi.get_pi())) + if (cur_t->enabled() && + continue_range(cur_t, events->pi, events->horiz_dir, events->dx_dy)) return 1; break; } case scev_end: { - if (cur_t->result_range && - end_range(cur_t, pi.get_pi())) + if (cur_t->enabled() && end_line(cur_t, events->pi, si)) return 1; - *at_hook= cur_t->next; + *cur_t_hook= cur_t->get_next(); free_item(cur_t); break; } case scev_two_ends: { - active_thread *cur_t1= cur_t->get_next(); - if (cur_t->result_range && - end_couple(cur_t, cur_t1, pi.get_pi())) + if (cur_t->enabled() && + end_couple(cur_t, cur_t->get_next(), events->pi)) return 1; - - *at_hook= cur_t1->next; - free_list(cur_t, &cur_t1->next); + *cur_t_hook= cur_t->get_next()->get_next(); + free_item(cur_t->next); + free_item(cur_t); break; } default: @@ -855,131 +640,421 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) return 0; } - prev_state= 0; - prev_range= 0; + starting_t_hook= cur_t_hook; + sav_prev_state= prev_state; - m_fn->clear_state(); - for (; pi.point() != si->get_event_position(); ++pi, cur_t= cur_t->get_next()) + /* Walk through the event, collecting all the 'incoming' threads */ + for (; events; events= events->get_next()) { - if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon) + active_thread *cur_t= *cur_t_hook; + + if (!event_point && events->event != scev_intersection) + event_point= events->pi; + if (events->event == scev_single_point) + continue; + + if (events->event == scev_thread || + events->event == scev_two_threads) { - m_fn->invert_state(pi.get_shape()); - prev_state^= cur_t->result_range; + active_thread *new_t= new_active_thread(); + if (!new_t) + return 1; + new_t->rp= NULL; + /* Insert into the main thread list before the current */ + new_t->next= cur_t; + *cur_t_hook= new_t; + cur_t_hook= (active_thread **) &new_t->next; } - at_hook= &cur_t->next; - if (cur_t->result_range) - prev_range= prev_state ? cur_t : 0; - } - - switch (si->get_event()) - { - case scev_thread: - { - active_thread *new_t= new_active_thread(); - if (!new_t) - return 1; - m_fn->invert_state(pi.get_shape()); - new_t->result_range= ~prev_state & m_fn->count(); - new_t->next= *at_hook; - *at_hook= new_t; - if (new_t->result_range && - start_range(new_t, pi.get_pi())) - return 1; - break; - } - case scev_two_threads: - { - active_thread *new_t0, *new_t1; - int fn_result; - const Gcalc_heap::Info *p= pi.get_pi(); - bool line= m_fn->get_shape_kind(p->shape) == Gcalc_function::shape_line; - if (!(new_t0= new_active_thread()) || !(new_t1= new_active_thread())) - return 1; - - m_fn->invert_state(pi.get_shape()); - fn_result= m_fn->count(); - if (line) - new_t0->result_range= new_t1->result_range= ~prev_state & fn_result; else - new_t0->result_range= new_t1->result_range= prev_state ^ fn_result; - new_t1->next= *at_hook; - new_t0->next= new_t1; - *at_hook= new_t0; - if (new_t0->result_range && - start_couple(new_t0, new_t1, pi.get_pi(), prev_range)) - return 1; - break; + { + if (events->is_bottom()) + { + /* Move thread from the main list to the bottom_threads. */ + *cur_t_hook= cur_t->get_next(); + cur_t->next= bottom_threads; + bottom_threads= cur_t; + } + if (cur_t->enabled()) + { + if (cur_t->rp->type == Gcalc_function::shape_line) + { + DBUG_ASSERT(!prev_state); + add_line(1, cur_t, events); + } + else + { + add_poly_border(1, cur_t, prev_state, events); + prev_state^= 1; + } + if (!events->is_bottom()) + { + active_thread *new_t= new_active_thread(); + if (!new_t) + return 1; + new_t->rp= NULL; + /* Replace the current thread with the new. */ + new_t->next= cur_t->next; + *cur_t_hook= new_t; + cur_t_hook= (active_thread **) &new_t->next; + /* And move old to the bottom list */ + cur_t->next= bottom_threads; + bottom_threads= cur_t; + } + } + else if (!events->is_bottom()) + cur_t_hook= (active_thread **) &cur_t->next; + } } - case scev_intersection: + prev_state= sav_prev_state; + cur_t_hook= starting_t_hook; + + eq_start= pi.point(); + eq_thread= point_thread= *starting_t_hook; + while (eq_start != si->get_event_end()) { - active_thread *cur_t1= cur_t->get_next(); - const Gcalc_heap::Info *p0, *p1; - p0= pi.get_pi(); + const Gcalc_scan_iterator::point *cur_eq; + int in_state, after_state; + ++pi; - p1= pi.get_pi(); - bool line0= m_fn->get_shape_kind(p0->shape) == Gcalc_function::shape_line; - bool line1= m_fn->get_shape_kind(p1->shape) == Gcalc_function::shape_line; + point_thread= point_thread->get_next(); - if (!line0 && !line1) /* two polygons*/ + if (pi.point() != si->get_event_end() && + eq_start->cmp_dx_dy(pi.point()) == 0) + continue; + + m_fn->save_states(); + for (cur_eq= eq_start; cur_eq != pi.point(); cur_eq= cur_eq->get_next()) + m_fn->set_on_state(cur_eq->get_shape()); + in_state= m_fn->count(); + + m_fn->restore_states(); + for (cur_eq= eq_start; cur_eq != pi.point(); cur_eq= cur_eq->get_next()) { - if (handle_polygons_intersection(cur_t, cur_t1, at_hook, p0, p1, - prev_state, pi.get_x(), si->get_y(), - prev_range)) - return 1; + gcalc_shape_info si= cur_eq->get_shape(); + if ((m_fn->get_shape_kind(si) == Gcalc_function::shape_polygon)) + m_fn->invert_state(si); } - else if (line0 && line1) + after_state= m_fn->count(); + if (prev_state != after_state) { - if (!prev_state && - handle_lines_intersection(cur_t, cur_t1, - p0, p1, pi.get_x(), si->get_y())) - return 1; - switch_athreads(cur_t, cur_t1, at_hook); + if (add_poly_border(0, eq_thread, prev_state, eq_start)) + return 1; + } + else if (!prev_state /* &&!after_state */ && in_state) + { + if (add_line(0, eq_thread, eq_start)) + return 1; + } + + prev_state= after_state; + eq_start= pi.point(); + eq_thread= point_thread; + } + + if (!sav_prev_state && !m_poly_borders && !m_lines) + { + /* Check if we need to add the event point itself */ + m_fn->clear_state(); + for (pi.restart(si); pi.point() != si->get_event_position(); ++pi) + { + if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon) + m_fn->invert_state(pi.get_shape()); + } + for (events= si->get_events(); events; events= events->get_next()) + m_fn->set_on_state(events->get_shape()); + + return m_fn->count() ? add_single_point(event_point, si) : 0; + } + + if (m_poly_borders) + { + *m_poly_borders_hook= NULL; + while (m_poly_borders) + { + poly_border *pb1, *pb2; + pb1= m_poly_borders; + DBUG_ASSERT(m_poly_borders->next); + + pb2= get_pair_border(pb1); + /* Remove pb1 from the list. The pb2 already removed in get_pair_border. */ + m_poly_borders= pb1->get_next(); + if (connect_threads(pb1->incoming, pb2->incoming, + pb1->t, pb2->t, pb1->p, pb2->p, + prev_range, event_point, si, + Gcalc_function::shape_polygon)) + return 1; + + free_item(pb1); + free_item(pb2); + } + m_poly_borders_hook= (Gcalc_dyn_list::Item **) &m_poly_borders; + m_poly_borders= NULL; + } + + if (m_lines) + { + *m_lines_hook= NULL; + if (m_lines->get_next() && + !m_lines->get_next()->get_next()) + { + if (connect_threads(m_lines->incoming, m_lines->get_next()->incoming, + m_lines->t, m_lines->get_next()->t, + m_lines->p, m_lines->get_next()->p, NULL, + event_point, si, Gcalc_function::shape_line)) + return 1; } else { - int poly_state; - int line_state; - const Gcalc_heap::Info *line; - active_thread *line_t; - m_fn->invert_state(p0->shape); - if (line0) + for (line *cur_line= m_lines; cur_line; cur_line= cur_line->get_next()) { - line_state= m_fn->count(); - poly_state= prev_state; - line= p0; - line_t= cur_t1; + if (cur_line->incoming) + { + if (end_line(cur_line->t, event_point, si)) + return 1; + } + else + start_line(cur_line->t, cur_line->p, event_point, si); } - else - { - poly_state= m_fn->count(); - m_fn->invert_state(p1->shape); - line_state= m_fn->count(); - line= p1; - line_t= cur_t; - } - if (handle_line_polygon_intersection(line_t, line, - line_state, poly_state, - pi.get_x(), si->get_y())) - return 1; - switch_athreads(cur_t, cur_t1, at_hook); } - break; + free_list(m_lines); + m_lines= NULL; + m_lines_hook= (Gcalc_dyn_list::Item **) &m_lines; } - case scev_single_point: + + if (bottom_threads) + free_list(bottom_threads); + + return 0; +} + + +int Gcalc_operation_reducer::add_single_point(const Gcalc_heap::Info *p, + const Gcalc_scan_iterator *si) +{ + res_point *rp= add_res_point(Gcalc_function::shape_point); + if (!rp) + return 1; + rp->glue= rp->up= rp->down= NULL; + if (p) { - m_fn->invert_state(pi.get_shape()); - if ((prev_state ^ m_fn->count()) && - add_single_point(pi.get_pi())) - return 1; - break; + rp->intersection_point= false; + rp->pi= p; } - default: - DBUG_ASSERT(0); + else + { + rp->intersection_point= true; + rp->x= si->get_y(); + rp->y= si->get_events()->x; + } + return 0; +} + + +Gcalc_operation_reducer::poly_border + *Gcalc_operation_reducer::get_pair_border(poly_border *b1) +{ + poly_border *prev_b= b1; + poly_border *result= b1->get_next(); + if (b1->prev_state) + { + if (b1->incoming) + { + /* Find the first outgoing, otherwise the last one. */ + while (result->incoming && result->get_next()) + { + prev_b= result; + result= result->get_next(); + } + } + else + { + /* Get the last one */ + while (result->get_next()) + { + prev_b= result; + result= result->get_next(); + } + } + } + else /* !b1->prev_state */ + { + if (b1->incoming) + { + /* Get the next incoming, otherwise the last one. */ + while (!result->incoming && result->get_next()) + { + prev_b= result; + result= result->get_next(); + } + } + else + { + /* Just pick the next one */ + } + } + /* Delete the result from the list. */ + prev_b->next= result->next; + return result; +} + + +int Gcalc_operation_reducer::connect_threads( + int incoming_a, int incoming_b, + active_thread *ta, active_thread *tb, + const Gcalc_scan_iterator::point *pa, const Gcalc_scan_iterator::point *pb, + active_thread *prev_range, const Gcalc_heap::Info *ev_p, + const Gcalc_scan_iterator *si, Gcalc_function::shape_type s_t) +{ + if (incoming_a && incoming_b) + { + res_point *rpa, *rpb; + DBUG_ASSERT(ta->rp->type == tb->rp->type); + if (!(rpa= add_res_point(ta->rp->type)) || + !(rpb= add_res_point(ta->rp->type))) + return 1; + rpa->down= ta->rp; + rpb->down= tb->rp; + rpb->glue= rpa; + rpa->glue= rpb; + rpa->up= rpb->up= NULL; + ta->rp->up= rpa; + tb->rp->up= rpb; + if (ev_p) + { + rpa->intersection_point= rpb->intersection_point= false; + rpa->pi= rpb->pi= ev_p; + } + else + { + rpa->intersection_point= rpb->intersection_point= true; + rpa->x= rpb->x= si->get_events()->x; + rpa->y= rpb->y= si->get_y(); + } + + ta->rp= tb->rp= NULL; + return 0; + } + if (!incoming_a) + { + DBUG_ASSERT(!incoming_b); + + res_point *rp0, *rp1; + if (!(rp0= add_res_point(s_t)) || !(rp1= add_res_point(s_t))) + return 1; + rp0->glue= rp1; + rp1->glue= rp0; + if (ev_p) + { + rp0->intersection_point= rp1->intersection_point= false; + rp0->pi= rp1->pi= ev_p; + } + else + { + rp0->intersection_point= rp1->intersection_point= true; + rp0->x= rp1->x= si->get_events()->x; + rp0->y= rp1->y= si->get_y(); + } + rp0->down= rp1->down= NULL; + ta->rp= rp0; + tb->rp= rp1; + ta->horiz_dir= pa->horiz_dir; + ta->dx_dy= pa->dx_dy; + + tb->horiz_dir= pb->horiz_dir; + tb->dx_dy= pb->dx_dy; + + if (prev_range) + { + rp0->outer_poly= prev_range->thread_start; + tb->thread_start= prev_range->thread_start; + } + else + { + rp0->outer_poly= 0; + ta->thread_start= rp0; + } + return 0; + } + /* else, if only ta is incoming */ + + DBUG_ASSERT(tb != ta); + tb->rp= ta->rp; + tb->thread_start= ta->thread_start; + if (Gcalc_scan_iterator::point:: + compare_dx_dy(ta->horiz_dir, ta->dx_dy, + pb->horiz_dir, pb->dx_dy) != 0) + { + if (ev_p ? continue_range(tb, ev_p, pb->horiz_dir, pb->dx_dy): + continue_i_range(tb, + si->get_events()->x, si->get_y(), + pb->horiz_dir, pb->dx_dy)) + return 1; + } + else + { + tb->horiz_dir= pb->horiz_dir; + tb->dx_dy= pb->dx_dy; } return 0; } + +int Gcalc_operation_reducer::start_line(active_thread *t, + const Gcalc_scan_iterator::point *p, + const Gcalc_heap::Info *ev_p, + const Gcalc_scan_iterator *si) +{ + res_point *rp= add_res_point(Gcalc_function::shape_line); + if (!rp) + return 1; + rp->glue= rp->down= NULL; + if (ev_p) + { + rp->intersection_point= false; + rp->pi= ev_p; + } + else + { + rp->intersection_point= true; + rp->x= si->get_events()->x; + rp->y= si->get_y(); + } + t->rp= rp; + t->horiz_dir= p->horiz_dir; + t->dx_dy= p->dx_dy; + return 0; +} + + +int Gcalc_operation_reducer::end_line(active_thread *t, + const Gcalc_heap::Info *ev_p, + const Gcalc_scan_iterator *si) +{ + DBUG_ASSERT(t->rp->type == Gcalc_function::shape_line); + res_point *rp= add_res_point(Gcalc_function::shape_line); + if (!rp) + return 1; + rp->glue= rp->up= NULL; + rp->down= t->rp; + if (ev_p) + { + rp->intersection_point= false; + rp->pi= ev_p; + } + else + { + rp->intersection_point= true; + rp->x= si->get_events()->x; + rp->y= si->get_y(); + } + t->rp->up= rp; + t->rp= NULL; + + return 0; +} + + int Gcalc_operation_reducer::count_all(Gcalc_heap *hp) { Gcalc_scan_iterator si; @@ -1014,7 +1089,7 @@ inline int Gcalc_operation_reducer::get_single_result(res_point *res, return 1; } else - if (storage->single_point(res->x, res->y)) + if (storage->single_point(res->pi->x, res->pi->y)) return 1; free_result(res); return 0; @@ -1113,13 +1188,13 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) *m_res_hook= NULL; while (m_result) { - if (!m_result->up) + Gcalc_function::shape_type shape= m_result->type; + if (shape == Gcalc_function::shape_point) { if (get_single_result(m_result, storage)) return 1; continue; } - Gcalc_function::shape_type shape= m_fn->get_shape_kind(m_result->pi->shape); if (shape == Gcalc_function::shape_polygon) { if (m_result->outer_poly) diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index 5e55d1bdae3..da7be1d9fa7 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -45,6 +45,7 @@ private: String function_buffer; const char *cur_func; int *i_states; + int *saved_i_states; uint32 cur_object_id; uint n_shapes; int count_internal(); @@ -90,7 +91,10 @@ public: void set_states(int *shape_states) { i_states= shape_states; } int alloc_states(); void invert_state(gcalc_shape_info shape) { i_states[shape]^= 1; } + void set_on_state(gcalc_shape_info shape) { i_states[shape]= 1; } int get_state(gcalc_shape_info shape) { return i_states[shape]; } + void save_states(); + void restore_states(); int count() { cur_func= function_buffer.ptr(); @@ -210,6 +214,7 @@ public: res_point *up; res_point *down; res_point *glue; + Gcalc_function::shape_type type; union { const Gcalc_heap::Info *pi; @@ -228,8 +233,10 @@ public: { public: res_point *rp; - int result_range; + int horiz_dir; + double dx_dy; res_point *thread_start; + res_point *enabled() { return rp; } active_thread *get_next() { return (active_thread *)next; } }; @@ -240,6 +247,60 @@ public: poly_instance *get_next() { return (poly_instance *)next; } }; + class line : public Gcalc_dyn_list::Item + { + public: + active_thread *t; + int incoming; + const Gcalc_scan_iterator::point *p; + line *get_next() { return (line *)next; } + }; + + class poly_border : public Gcalc_dyn_list::Item + { + public: + active_thread *t; + int incoming; + int prev_state; + const Gcalc_scan_iterator::point *p; + poly_border *get_next() { return (poly_border *)next; } + }; + + line *m_lines; + Gcalc_dyn_list::Item **m_lines_hook; + poly_border *m_poly_borders; + Gcalc_dyn_list::Item **m_poly_borders_hook; + line *new_line() { return (line *) new_item(); } + poly_border *new_poly_border() { return (poly_border *) new_item(); } + int add_line(int incoming, active_thread *t, + const Gcalc_scan_iterator::point *p) + { + line *l= new_line(); + if (!l) + return 1; + l->incoming= incoming; + l->t= t; + l->p= p; + *m_lines_hook= l; + m_lines_hook= &l->next; + return 0; + } + + int add_poly_border(int incoming, active_thread *t, int prev_state, + const Gcalc_scan_iterator::point *p) + { + poly_border *b= new_poly_border(); + if (!b) + return 1; + b->incoming= incoming; + b->t= t; + b->prev_state= prev_state; + b->p= p; + *m_poly_borders_hook= b; + m_poly_borders_hook= &b->next; + return 0; + } + protected: Gcalc_function *m_fn; Gcalc_dyn_list::Item **m_res_hook; @@ -249,12 +310,13 @@ protected: res_point *result_heap; active_thread *m_first_active_thread; - res_point *add_res_point() + res_point *add_res_point(Gcalc_function::shape_type type) { res_point *result= (res_point *)new_item(); *m_res_hook= result; result->prev_hook= m_res_hook; m_res_hook= &result->next; + result->type= type; return result; } @@ -263,44 +325,27 @@ protected: poly_instance *new_poly() { return (poly_instance *) new_item(); } private: - int continue_range(active_thread *t, const Gcalc_heap::Info *p); - int continue_i_range(active_thread *t, const Gcalc_heap::Info *p, - double x, double y); - int start_range(active_thread *t, const Gcalc_heap::Info *p); - int start_i_range(active_thread *t, const Gcalc_heap::Info *p, - double x, double y); - int end_range(active_thread *t, const Gcalc_heap::Info *p); - int end_i_range(active_thread *t, const Gcalc_heap::Info *p, - double x, double y); - int start_couple(active_thread *t0, active_thread *t1,const Gcalc_heap::Info *p, - const active_thread *prev_range); - int start_i_couple(active_thread *t0, active_thread *t1, - const Gcalc_heap::Info *p0, - const Gcalc_heap::Info *p1, - double x, double y, - const active_thread *prev_range); + int start_line(active_thread *t, const Gcalc_scan_iterator::point *p, + const Gcalc_heap::Info *ev_p, const Gcalc_scan_iterator *si); + int end_line(active_thread *t, const Gcalc_heap::Info *ev_p, + const Gcalc_scan_iterator *si); + int connect_threads(int incoming_a, int incoming_b, + active_thread *ta, active_thread *tb, + const Gcalc_scan_iterator::point *pa, + const Gcalc_scan_iterator::point *pb, + active_thread *prev_range, + const Gcalc_heap::Info *ev_p, + const Gcalc_scan_iterator *si, + Gcalc_function::shape_type s_t); + int add_single_point(const Gcalc_heap::Info *p, + const Gcalc_scan_iterator *si); + poly_border *get_pair_border(poly_border *b1); + int continue_range(active_thread *t, const Gcalc_heap::Info *p, + int horiz_dir, double dx_dy); + int continue_i_range(active_thread *t, double x, double y, + int horiz_dir, double dx_dy); int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p); - int end_i_couple(active_thread *t0, active_thread *t1, - const Gcalc_heap::Info *p0, - const Gcalc_heap::Info *p1, - double x, double y); int add_single_point(const Gcalc_heap::Info *p); - int add_i_single_point(const Gcalc_heap::Info *p, double x, double y); - - int handle_lines_intersection(active_thread *t0, active_thread *t1, - const Gcalc_heap::Info *p0, - const Gcalc_heap::Info *p1, - double x, double y); - int handle_polygons_intersection(active_thread *t0, active_thread *t1, - Gcalc_dyn_list::Item **t_hook, - const Gcalc_heap::Info *p0, - const Gcalc_heap::Info *p1, - int prev_state, double x, double y, - const active_thread *prev_range); - int handle_line_polygon_intersection(active_thread *l, - const Gcalc_heap::Info *pl, - int line_state, int poly_state, - double x, double y); int get_single_result(res_point *res, Gcalc_result_receiver *storage); int get_result_thread(res_point *cur, Gcalc_result_receiver *storage, diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 4afc56eaf87..a8abcd26b42 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -665,10 +665,12 @@ static int calc_distance(double *result, Gcalc_heap *collector, uint obj2_si, { bool above_cur_point, cur_point_edge; const Gcalc_scan_iterator::point *evpos; - const Gcalc_heap::Info *cur_point, *dist_point; - Gcalc_scan_events ev; + 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"); @@ -680,32 +682,39 @@ static int calc_distance(double *result, Gcalc_heap *collector, uint obj2_si, if (scan_it->step()) goto mem_error; evpos= scan_it->get_event_position(); - ev= scan_it->get_event(); - cur_point= evpos->pi; + 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 */ - if (ev == scev_intersection) + o1= 0; + o2= 0; + for (; ev; ev= ev->get_next()) { - if ((evpos->get_next()->pi->shape >= obj2_si) != - (cur_point->shape >= obj2_si)) + 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; } - continue; } + if (!cur_point) + continue; - /* - if we get 'scev_point | scev_end | scev_two_ends' we don't need - to check for intersection of objects. - Though we need to calculate distances. - */ - if (ev & (scev_point | scev_end | scev_two_ends)) - goto calculate_distance; - +#ifdef TO_REMOVE goto calculate_distance; /* having these events we need to check for possible intersection @@ -728,7 +737,7 @@ static int calc_distance(double *result, Gcalc_heap *collector, uint obj2_si, distance= 0; goto exit; } - +#endif /*TO_REMOVE*/ calculate_distance: if (cur_point->shape >= obj2_si) @@ -1516,6 +1525,7 @@ longlong Item_func_issimple::val_int() Gcalc_operation_transporter trn(&func, &collector); Geometry *g; int result= 1; + const Gcalc_scan_iterator::point *ev; DBUG_ENTER("Item_func_issimple::val_int"); DBUG_ASSERT(fixed == 1); @@ -1539,11 +1549,19 @@ longlong Item_func_issimple::val_int() if (scan_it.step()) goto mem_error; - if (scan_it.get_event() == scev_intersection) - { - result= 0; - break; - } + ev= scan_it.get_events(); + if (ev->simple_event()) + continue; + + if ((ev->event == scev_thread || ev->event == scev_single_point) && + !ev->get_next()) + continue; + + if (ev->event == scev_two_threads && !ev->get_next()->get_next()) + continue; + + result= 0; + break; } collector.reset(); @@ -1553,7 +1571,6 @@ longlong Item_func_issimple::val_int() mem_error: null_value= 1; DBUG_RETURN(0); - return 0; } @@ -1731,7 +1748,7 @@ double Item_func_distance::val_real() bool above_cur_point, cur_point_edge; const Gcalc_scan_iterator::point *evpos; const Gcalc_heap::Info *cur_point, *dist_point; - Gcalc_scan_events ev; + const Gcalc_scan_iterator::point *ev; double t, distance, cur_distance; double x1, x2, y1, y2; double ex, ey, vx, vy, e_sqrlen; @@ -1782,39 +1799,24 @@ double Item_func_distance::val_real() if (scan_it.step()) goto mem_error; evpos= scan_it.get_event_position(); - ev= scan_it.get_event(); - cur_point= evpos->pi; + ev= scan_it.get_events(); + if (ev->simple_event()) + { + cur_point= ev->pi; + goto count_distance; + } /* handling intersection we only need to check if it's the intersecion of objects 1 and 2. In this case distance is 0 */ - if (ev == scev_intersection) - { - if ((evpos->get_next()->pi->shape >= obj2_si) != - (cur_point->shape >= obj2_si)) - { - distance= 0; - goto exit; - } - continue; - } - - /* - if we get 'scev_point | scev_end | scev_two_ends' we don't need - to check for intersection of objects. - Though we need to calculate distances. - */ - if (ev & (scev_point | scev_end | scev_two_ends)) - goto count_distance; + cur_point= NULL; /* 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) { @@ -1822,14 +1824,22 @@ double Item_func_distance::val_real() if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon)) func.invert_state(si); } - func.invert_state(evpos->get_shape()); - if (func.count()) + + for (; ev; ev= ev->get_next()) { - /* Point of one object is inside the other - intersection found */ - distance= 0; - goto exit; + if (ev->event != scev_intersection) + cur_point= ev->pi; + func.set_on_state(evpos->get_shape()); + if (func.count()) + { + /* Point of one object is inside the other - intersection found */ + distance= 0; + goto exit; + } } + if (!cur_point) + continue; count_distance: if (cur_point->shape >= obj2_si) diff --git a/sql/spatial.cc b/sql/spatial.cc index 7fb8c0f251d..67ece027141 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -705,6 +705,8 @@ int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const { uint32 n_points; double x, y; + double prev_x, prev_y; + int first_point= 1; const char *data= m_data; if (no_data(m_data, 4)) @@ -720,8 +722,13 @@ int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const { get_point(&x, &y, data); data+= POINT_DATA_SIZE; + if (!first_point && x == prev_x && y == prev_y) + continue; if (trn->add_point(x, y)) return 1; + first_point= 0; + prev_x= x; + prev_y= y; } return trn->complete_line(); @@ -1119,6 +1126,9 @@ int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const { uint32 n_linear_rings; const char *data= m_data; + double first_x, first_y; + double prev_x, prev_y; + int was_equal_first= 0; if (trn->start_poly()) return 1; @@ -1140,11 +1150,33 @@ int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const return 1; trn->start_ring(); + get_point(&first_x, &first_y, data); + data+= POINT_DATA_SIZE; + n_points--; + prev_x= first_x; + prev_y= first_y; + if (trn->add_point(first_x, first_y)) + return 1; while (--n_points) { double x, y; get_point(&x, &y, data); data+= POINT_DATA_SIZE; + if (x == prev_x && y == prev_y) + continue; + prev_x= x; + prev_y= y; + if (was_equal_first) + { + if (trn->add_point(first_x, first_y)) + return 1; + was_equal_first= 0; + } + if (x == first_x && y == first_y) + { + was_equal_first= 1; + continue; + } if (trn->add_point(x, y)) return 1; } From c937b7588f007d24c1cf93ee0b2da9e0e244d711 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 2 Sep 2011 09:38:17 +0500 Subject: [PATCH 15/40] bugs #801560 and #802194 tests added. per-file comments: mysql-test/r/gis-precise.result bugs #801560 and #802194 test result updated. mysql-test/t/gis-precise.test bugs #801560 and #802194 test case added. --- mysql-test/r/gis-precise.result | 16 ++++++++++++++++ mysql-test/t/gis-precise.test | 14 ++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 80d44da6cbf..b4ebbfbf3a8 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -301,3 +301,19 @@ MultiPolygonFromText('MULTIPOLYGON(((9 9, 7 9, 1 1, 9 9)), ((0 0, 7 5, 9 6, 0 0)), POLYGON((0 0,0 5,1 5,2 7,2 5.5,5 7,5.5 7,7 9,9 9,7 7,7 5,9 6,7 4.66666666666667,7 1,4.25 2.83333333333333,3 2,3 0,0 0),(1 1,1 4,1.33333333333333 4,1.85714285714286 2.42857142857143,1 2,1.75 2,1 1,2 2,2 1.42857142857143,1.4 1,1 1),(1.5 1,2 1.33333333333333,2 1,1.5 1),(3 2.14285714285714,3 3,3.4 3.4,4.10344827586207 2.93103448275862,3 2.14285714285714)) +SELECT AsText( ST_INTERSECTION( +LinestringFromText('LINESTRING( 3 5, 2 5, 2 4, 3 4, 3 5 ) ') , +LinestringFromText('LINESTRING( 3 5, 2 4, 2 5, 3 5 ) ') +)); +AsText( ST_INTERSECTION( +LinestringFromText('LINESTRING( 3 5, 2 5, 2 4, 3 4, 3 5 ) ') , +LinestringFromText('LINESTRING( 3 5, 2 4, 2 5, 3 5 ) ') +)) +LINESTRING(2 4,2 5,3 5) +SELECT AsText( ST_UNION( +PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 7 5 , 2 0 , 2 2 ) ) ') , +PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 3 3 , 2 5 , 2 2 ) ) ') ) ); +AsText( ST_UNION( +PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 7 5 , 2 0 , 2 2 ) ) ') , +PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 3 3 , 2 5 , 2 2 ) ) ') ) ) +POLYGON((2 0,2 5,3 3,3 2,7 5,2 0)) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index bb223b685e4..4ad03d44823 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -187,3 +187,17 @@ SELECT AsText(ST_UNION( MultiPolygonFromText('MULTIPOLYGON(((2 2, 2 2, 1 5, 2 7, 2 2)), ((0 5, 3 5, 3 0, 0 0, 0 5), (1 1, 2 1, 2 4, 1 4, 1 1)))'))); +#bug 802376 ST_INTERSECTION returns wrong result on two overlapping linestrings in maria-5.3-gis + +SELECT AsText( ST_INTERSECTION( + LinestringFromText('LINESTRING( 3 5, 2 5, 2 4, 3 4, 3 5 ) ') , + LinestringFromText('LINESTRING( 3 5, 2 4, 2 5, 3 5 ) ') +)); + +#bug 801560 ST_UNION of adjacent polygons includes extra line in maria-5.3-gis + +SELECT AsText( ST_UNION( + PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 7 5 , 2 0 , 2 2 ) ) ') , + PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 3 3 , 2 5 , 2 2 ) ) ') ) ); + + From eefff87652cde1cb0c986fd167ed057e87230250 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 4 Sep 2011 19:11:04 +0500 Subject: [PATCH 16/40] bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. We didn't implement an empty geometry. And returning NULL instead of it is not quite correct. So here is the implementation of the empty value as GEOMETRYCOLLECTION(). per-file comments: mysql-test/r/gis-precise.result bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. test result updated. mysql-test/r/gis.result bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. test result updated. mysql-test/t/gis-precise.test bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. test case added. mysql-test/t/gis.test bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. test case added. sql/field.cc bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. store GEOMETRYCOLLECTION() properly. sql/gcalc_tools.cc bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. create the GEOMETRYCOLLECTION() for the empty result. sql/gstream.h bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. next_symbol() added. sql/spatial.cc bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis. code modified to handle 0 geometries in the GEOMETRYCOLLECTION properly. --- mysql-test/r/gis-precise.result | 3 +++ mysql-test/r/gis.result | 23 +++++++++++++++++++---- mysql-test/t/gis-precise.test | 3 +++ mysql-test/t/gis.test | 3 ++- sql/field.cc | 2 +- sql/gcalc_tools.cc | 9 +++++---- sql/gstream.h | 8 ++++++++ sql/spatial.cc | 26 ++++++++++++++------------ 8 files changed, 55 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index b4ebbfbf3a8..a3928cd0fb0 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -317,3 +317,6 @@ AsText( ST_UNION( PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 7 5 , 2 0 , 2 2 ) ) ') , PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 3 3 , 2 5 , 2 2 ) ) ') ) ) POLYGON((2 0,2 5,3 3,3 2,7 5,2 0)) +SELECT AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), GeometryFromText('LINESTRING(3 3, 4 4)'))); +AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), GeometryFromText('LINESTRING(3 3, 4 4)'))) +GEOMETRYCOLLECTION() diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 8dabc431e8f..b3993657182 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -66,7 +66,8 @@ INSERT INTO gis_multi_polygon VALUES (119, MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3))))))); INSERT INTO gis_geometrycollection VALUES (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')), -(121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))); +(121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))), +(122, GeomFromText('GeometryCollection()')); INSERT into gis_geometry SELECT * FROM gis_point; INSERT into gis_geometry SELECT * FROM gis_line; INSERT into gis_geometry SELECT * FROM gis_polygon; @@ -109,6 +110,7 @@ SELECT fid, AsText(g) FROM gis_geometrycollection; fid AsText(g) 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10)) 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9)) +122 GEOMETRYCOLLECTION() SELECT fid, AsText(g) FROM gis_geometry; fid AsText(g) 101 POINT(10 10) @@ -132,6 +134,7 @@ fid AsText(g) 119 MULTIPOLYGON(((0 3,3 3,3 0,0 3))) 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10)) 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9)) +122 GEOMETRYCOLLECTION() SELECT fid, Dimension(g) FROM gis_geometry; fid Dimension(g) 101 0 @@ -155,6 +158,7 @@ fid Dimension(g) 119 2 120 1 121 1 +122 0 SELECT fid, GeometryType(g) FROM gis_geometry; fid GeometryType(g) 101 POINT @@ -178,6 +182,7 @@ fid GeometryType(g) 119 MULTIPOLYGON 120 GEOMETRYCOLLECTION 121 GEOMETRYCOLLECTION +122 GEOMETRYCOLLECTION SELECT fid, IsEmpty(g) FROM gis_geometry; fid IsEmpty(g) 101 0 @@ -201,6 +206,7 @@ fid IsEmpty(g) 119 0 120 0 121 0 +122 0 SELECT fid, AsText(Envelope(g)) FROM gis_geometry; fid AsText(Envelope(g)) 101 POLYGON((10 10,10 10,10 10,10 10,10 10)) @@ -224,9 +230,10 @@ fid AsText(Envelope(g)) 119 POLYGON((0 0,3 0,3 3,0 3,0 0)) 120 POLYGON((0 0,10 0,10 10,0 10,0 0)) 121 POLYGON((3 6,44 6,44 9,3 9,3 6)) +122 POLYGON((1.79769313486232e+308 1.79769313486232e+308,-1.79769313486232e+308 1.79769313486232e+308,-1.79769313486232e+308 -1.79769313486232e+308,1.79769313486232e+308 -1.79769313486232e+308,1.79769313486232e+308 1.79769313486232e+308)) explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelope(g)) from gis_geometry; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 21 100.00 +1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 22 100.00 Warnings: Note 1003 select st_dimension(`test`.`gis_geometry`.`g`) AS `Dimension(g)`,st_geometrytype(`test`.`gis_geometry`.`g`) AS `GeometryType(g)`,st_isempty(`test`.`gis_geometry`.`g`) AS `IsEmpty(g)`,st_astext(st_envelope(`test`.`gis_geometry`.`g`)) AS `AsText(Envelope(g))` from `test`.`gis_geometry` SELECT fid, X(g) FROM gis_point; @@ -345,6 +352,7 @@ SELECT fid, NumGeometries(g) from gis_geometrycollection; fid NumGeometries(g) 120 2 121 2 +122 0 explain extended SELECT fid, NumGeometries(g) from gis_multi_point; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3 100.00 @@ -369,10 +377,12 @@ SELECT fid, AsText(GeometryN(g, 2)) from gis_geometrycollection; fid AsText(GeometryN(g, 2)) 120 LINESTRING(0 0,10 10) 121 LINESTRING(3 6,7 9) +122 NULL SELECT fid, AsText(GeometryN(g, 1)) from gis_geometrycollection; fid AsText(GeometryN(g, 1)) 120 POINT(0 0) 121 POINT(44 6) +122 NULL explain extended SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3 100.00 @@ -386,16 +396,21 @@ FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second first second w c o e d t i r 120 120 1 1 0 1 0 1 1 1 120 121 0 0 1 0 0 0 1 0 +120 122 0 1 0 0 1 0 0 0 121 120 0 0 1 0 0 0 1 0 121 121 1 1 0 1 0 1 1 1 +121 122 0 1 0 0 1 0 0 0 +122 120 1 0 0 0 1 0 0 0 +122 121 1 0 0 0 1 0 0 0 +122 122 1 1 0 1 1 0 0 0 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE g1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort -1 SIMPLE g2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join) +1 SIMPLE g1 ALL NULL NULL NULL NULL 3 100.00 Using temporary; Using filesort +1 SIMPLE g2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) Warnings: Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,st_within(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,st_contains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,mbroverlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,mbrequals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,mbrdisjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,st_touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,mbrintersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,st_crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid` DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry; diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 4ad03d44823..d2012ee795d 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -200,4 +200,7 @@ SELECT AsText( ST_UNION( PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 7 5 , 2 0 , 2 2 ) ) ') , PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 3 3 , 2 5 , 2 2 ) ) ') ) ); +#bug 801466 ST_INTERSECTION() returns invalid value on empty intersection in maria-5.3-gis + +SELECT AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), GeometryFromText('LINESTRING(3 3, 4 4)'))); diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index fa6a7dc4675..25fec4cca4e 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -62,7 +62,8 @@ INSERT INTO gis_multi_polygon VALUES INSERT INTO gis_geometrycollection VALUES (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')), -(121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))); +(121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))), +(122, GeomFromText('GeometryCollection()')); INSERT into gis_geometry SELECT * FROM gis_point; INSERT into gis_geometry SELECT * FROM gis_line; diff --git a/sql/field.cc b/sql/field.cc index 50f66363c1f..42324674838 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8008,7 +8008,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) goto err; // Check given WKB uint32 wkb_type; - if (length < SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE*2) + if (length < SRID_SIZE + WKB_HEADER_SIZE + 4) goto err; wkb_type= uint4korr(from + SRID_SIZE + 1); if (wkb_type < (uint32) Geometry::wkb_point || diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index ab173803323..0d5c1c52d61 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -137,6 +137,8 @@ int Gcalc_function::count_internal() cur_func+= 4; if (next_func == op_shape) return i_states[c_op & ~(op_any | op_not)] ^ mask; + if (n_ops == 0) + return mask; result= count_internal(); @@ -442,11 +444,9 @@ void Gcalc_result_receiver::reset() int Gcalc_result_receiver::get_result_typeid() { - if (!n_shapes) - return 0; - - if (collection_result) + if (!n_shapes || collection_result) return Geometry::wkb_geometrycollection; + switch (common_shapetype) { case Gcalc_function::shape_polygon: @@ -1186,6 +1186,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) poly_instance *polygons= NULL; *m_res_hook= NULL; + while (m_result) { Gcalc_function::shape_type shape= m_result->type; diff --git a/sql/gstream.h b/sql/gstream.h index 1ef90ad5bf0..a1850e9a333 100644 --- a/sql/gstream.h +++ b/sql/gstream.h @@ -57,6 +57,14 @@ public: m_cur++; return 0; } + /* Returns the next notempty character. */ + char next_symbol() + { + skip_space(); + if (m_cur >= m_limit) + return 0; /* EOL meet. */ + return *m_cur; + } void set_error_msg(const char *msg); // caller should free this pointer diff --git a/sql/spatial.cc b/sql/spatial.cc index 67ece027141..67e36ccb12b 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -2075,19 +2075,22 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb) return 1; wkb->length(wkb->length()+4); // Reserve space for points - for (;;) + if (trs->next_symbol() != ')') { - if (!(g= create_from_wkt(&buffer, trs, wkb))) - return 1; - - if (g->get_class_info()->m_type_id == wkb_geometrycollection) + for (;;) { - trs->set_error_msg("Unexpected GEOMETRYCOLLECTION"); - return 1; + if (!(g= create_from_wkt(&buffer, trs, wkb))) + return 1; + + if (g->get_class_info()->m_type_id == wkb_geometrycollection) + { + trs->set_error_msg("Unexpected GEOMETRYCOLLECTION"); + return 1; + } + n_objects++; + if (trs->skip_char(',')) // Didn't find ',' + break; } - n_objects++; - if (trs->skip_char(',')) // Didn't find ',' - break; } wkb->write_at_position(no_pos, n_objects); @@ -2208,10 +2211,9 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt, 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)) + if (n_objects && txt->append(STRING_WITH_LEN(","), 512)) return 1; } - txt->length(txt->length() - 1); *end= data; return 0; } From 6dfa30e938babc2cac59f2d5eac1f4d46a361b93 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 4 Sep 2011 23:48:17 +0500 Subject: [PATCH 17/40] bug 839341 100% CPU usage with ST_UNION in maria-5.3-gis. Line loops weren't recognized when collect results. Fixed by checking if we got the same beginning point of the line. per-file comments: mysql-test/r/gis-precise.result bug 839341 100% CPU usage with ST_UNION in maria-5.3-gis. test result updated. mysql-test/t/gis-precise.test bug 839341 100% CPU usage with ST_UNION in maria-5.3-gis. test case added. sql/gcalc_tools.cc bug 839341 100% CPU usage with ST_UNION in maria-5.3-gis. check if we get the beginning node of the linestring, then cut the loop. --- mysql-test/r/gis-precise.result | 3 +++ mysql-test/t/gis-precise.test | 2 ++ sql/gcalc_tools.cc | 9 +++++++++ 3 files changed, 14 insertions(+) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index a3928cd0fb0..a370e117fe0 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -320,3 +320,6 @@ POLYGON((2 0,2 5,3 3,3 2,7 5,2 0)) SELECT AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), GeometryFromText('LINESTRING(3 3, 4 4)'))); AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), GeometryFromText('LINESTRING(3 3, 4 4)'))) GEOMETRYCOLLECTION() +SELECT AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 5, 2 5, 2 4, 3 4, 3 5))'))); +AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 5, 2 5, 2 4, 3 4, 3 5))'))) +GEOMETRYCOLLECTION(POINT(8 1),LINESTRING(2 4,2 5,3 5,3 4,2 4)) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index d2012ee795d..c2d13cfe5cb 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -204,3 +204,5 @@ SELECT AsText( ST_UNION( SELECT AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), GeometryFromText('LINESTRING(3 3, 4 4)'))); +#bug 839341 100% CPU usage with ST_UNION in maria-5.3-gis +SELECT AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 5, 2 5, 2 4, 3 4, 3 5))'))); diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 0d5c1c52d61..e502d54a160 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -1158,6 +1158,7 @@ int Gcalc_operation_reducer::get_line_result(res_point *cur, Gcalc_result_receiver *storage) { res_point *next; + res_point *cur_orig= cur; int move_upward= 1; if (cur->glue) { @@ -1171,6 +1172,14 @@ int Gcalc_operation_reducer::get_line_result(res_point *cur, if (!next) { next= cur->glue; + if (next == cur_orig) + { + /* It's the line loop */ + cur= cur_orig; + cur->glue->glue= NULL; + move_upward= 1; + break; + } move_upward^= 1; } } From 97eae1cd63e3bb05c98a4b050ec3abaf7925c382 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 5 Sep 2011 09:13:58 +0500 Subject: [PATCH 18/40] bug 839318 Crash in Gcalc_scan_iterator::point::get_shape with ST_DISTANCE and MULTILINESTRING in maria-5.3-gis. wrong variable was used as a result of inattentive copypaste. per-file comments: mysql-test/r/gis-precise.result bug 839318 Crash in Gcalc_scan_iterator::point::get_shape with ST_DISTANCE and MULTILINESTRING in maria-5.3-gis. test result updated. mysql-test/t/gis-precise.test bug 839318 Crash in Gcalc_scan_iterator::point::get_shape with ST_DISTANCE and MULTILINESTRING in maria-5.3-gis. test case added. sql/item_geofunc.cc bug 839318 Crash in Gcalc_scan_iterator::point::get_shape with ST_DISTANCE and MULTILINESTRING in maria-5.3-gis. use 'ev' variable instead of the 'evpos'. --- mysql-test/r/gis-precise.result | 5 +++++ mysql-test/t/gis-precise.test | 5 +++++ sql/item_geofunc.cc | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index a370e117fe0..1d61db1c98d 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -323,3 +323,8 @@ GEOMETRYCOLLECTION() SELECT AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 5, 2 5, 2 4, 3 4, 3 5))'))); AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 5, 2 5, 2 4, 3 4, 3 5))'))) GEOMETRYCOLLECTION(POINT(8 1),LINESTRING(2 4,2 5,3 5,3 4,2 4)) +SELECT ST_DISTANCE(POINTFROMTEXT('POINT(7 1)'),MULTILINESTRINGFROMTEXT('MULTILINESTRING( + (4 7,9 7,6 1,3 4,1 1), (3 5, 2 5, 2 4, 3 4, 3 5))')); +ST_DISTANCE(POINTFROMTEXT('POINT(7 1)'),MULTILINESTRINGFROMTEXT('MULTILINESTRING( + (4 7,9 7,6 1,3 4,1 1), (3 5, 2 5, 2 4, 3 4, 3 5))')) +1 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index c2d13cfe5cb..62445d3aa27 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -206,3 +206,8 @@ SELECT AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), Geomet #bug 839341 100% CPU usage with ST_UNION in maria-5.3-gis SELECT AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 5, 2 5, 2 4, 3 4, 3 5))'))); + +#bug 839318 Crash in Gcalc_scan_iterator::point::get_shape with ST_DISTANCE and MULTILINESTRING in maria-5.3-gis +SELECT ST_DISTANCE(POINTFROMTEXT('POINT(7 1)'),MULTILINESTRINGFROMTEXT('MULTILINESTRING( + (4 7,9 7,6 1,3 4,1 1), (3 5, 2 5, 2 4, 3 4, 3 5))')); + diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index a8abcd26b42..ea849bb10a3 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1829,7 +1829,7 @@ double Item_func_distance::val_real() { if (ev->event != scev_intersection) cur_point= ev->pi; - func.set_on_state(evpos->get_shape()); + func.set_on_state(ev->get_shape()); if (func.count()) { /* Point of one object is inside the other - intersection found */ From a1315808b4a067fd82877ea1cfbd8867f9a8588a Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 5 Sep 2011 09:49:46 +0500 Subject: [PATCH 19/40] bug 839327 Crash in Gcalc_operation_reducer::end_couple with ST_UNION and MULTIPOLYGONs in 5.3-gis. When edges of a polygon coicide, it can form an pike, that is turned into a line after an operation. In this case a former polygon point can be an end of a single line, and that case wasn't properly handled. per-file comments: mysql-test/r/gis-precise.result bug 839327 Crash in Gcalc_operation_reducer::end_couple with ST_UNION and MULTIPOLYGONs in 5.3-gis. test result updated. mysql-test/t/gis-precise.test bug 839327 Crash in Gcalc_operation_reducer::end_couple with ST_UNION and MULTIPOLYGONs in 5.3-gis. test case added. sql/gcalc_tools.cc bug 839327 Crash in Gcalc_operation_reducer::end_couple with ST_UNION and MULTIPOLYGONs in 5.3-gis. in the scev_two_ends case check if we have single line ending on a polygon node. --- mysql-test/r/gis-precise.result | 3 +++ mysql-test/t/gis-precise.test | 4 ++++ sql/gcalc_tools.cc | 16 +++++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 1d61db1c98d..68fa4661c90 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -328,3 +328,6 @@ SELECT ST_DISTANCE(POINTFROMTEXT('POINT(7 1)'),MULTILINESTRINGFROMTEXT('MULTILIN ST_DISTANCE(POINTFROMTEXT('POINT(7 1)'),MULTILINESTRINGFROMTEXT('MULTILINESTRING( (4 7,9 7,6 1,3 4,1 1), (3 5, 2 5, 2 4, 3 4, 3 5))')) 1 +SELECT AsText(ST_UNION(POLYGONFROMTEXT('POLYGON((12 9, 3 6, 3 0, 12 9))'), POLYGONFROMTEXT('POLYGON((2 2, 7 2, 4 2, 2 0, 2 2))'))); +AsText(ST_UNION(POLYGONFROMTEXT('POLYGON((12 9, 3 6, 3 0, 12 9))'), POLYGONFROMTEXT('POLYGON((2 2, 7 2, 4 2, 2 0, 2 2))'))) +GEOMETRYCOLLECTION(POLYGON((2 0,2 2,3 2,3 6,12 9,3 0,3 1,2 0)),LINESTRING(5 2,7 2)) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 62445d3aa27..cafd9a1d99a 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -211,3 +211,7 @@ SELECT AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT(' SELECT ST_DISTANCE(POINTFROMTEXT('POINT(7 1)'),MULTILINESTRINGFROMTEXT('MULTILINESTRING( (4 7,9 7,6 1,3 4,1 1), (3 5, 2 5, 2 4, 3 4, 3 5))')); +#bug 839327 Crash in Gcalc_operation_reducer::end_couple with ST_UNION and MULTIPOLYGONs in 5.3-gis +SELECT AsText(ST_UNION(POLYGONFROMTEXT('POLYGON((12 9, 3 6, 3 0, 12 9))'), POLYGONFROMTEXT('POLYGON((2 2, 7 2, 4 2, 2 0, 2 2))'))); + + diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index e502d54a160..3ee58646ca4 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -626,9 +626,19 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) } case scev_two_ends: { - if (cur_t->enabled() && - end_couple(cur_t, cur_t->get_next(), events->pi)) - return 1; + if (cur_t->enabled() && cur_t->get_next()->enabled()) + { + /* When two threads are ended here */ + if (end_couple(cur_t, cur_t->get_next(), events->pi)) + return 1; + } + else if (cur_t->enabled() || cur_t->get_next()->enabled()) + { + /* Rare case when edges of a polygon coincide */ + if (end_line(cur_t->enabled() ? cur_t : cur_t->get_next(), + events->pi, si)) + return 1; + } *cur_t_hook= cur_t->get_next()->get_next(); free_item(cur_t->next); free_item(cur_t); From 3882c5d62c83f4768c022f38bf91180ce0fcc7a2 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 13 Sep 2011 13:59:11 +0500 Subject: [PATCH 20/40] Fix for few similar bugs: #841622 Assertion `t->rp->type == Gcalc_function::shape_line' failed in Gcalc_operation_reducer::end_line in maria-5.3-gi #841625 Assertion `m_poly_borders->next' failed in Gcalc_operation_reducer::count_slice in maria-5.3-gis #841638 Assertion `!m_prev || m_prev->x != x || m_prev->y != y' failed in Gcalc_shape_transporter::int_add_point in maria-5.3-gis #841662 Third assertion `n > 0 && n < SINUSES_CALCULATED*2+1' in get_n_sincos #841745 Assertion `!sp0->is_bottom()' failed in Gcalc_scan_iterator::find_intersections in maria-5.3-gis They mostly was caused by inprecision of double arithmetic. Fixed by changes in how to handle multiple intersections to keep their order right. Also ST_DISTANCE(GEOM, EMPTY_GEOM) was defined as NULL. per-file comments: mysql-test/r/gis-precise.result GIS bugfixes. test result updated. mysql-test/t/gis-precise.test GIS bugfixes. test cases added. sql/gcalc_slicescan.cc GIS bugfixes. If intersections are close, add order checks to cope with the double calcualtions imprecision. sql/gcalc_slicescan.h GIS bugfixes. n_row parameter added to intersection to check their order. sql/item_geofunc.cc GIS bugfixes. ST_DISTANCE(GEOM, EMPTY_GEOM) returns NULL. --- mysql-test/r/gis-precise.result | 87 +++++++++++++++++++- mysql-test/t/gis-precise.test | 65 +++++++++++++++ sql/gcalc_slicescan.cc | 141 ++++++++++++++++++++++++-------- sql/gcalc_slicescan.h | 3 +- sql/item_geofunc.cc | 8 ++ 5 files changed, 269 insertions(+), 35 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 68fa4661c90..5ebce7f603e 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -214,7 +214,7 @@ astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0)) LINESTRING(0 0,1 1) SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5); Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5) -78.68303 +78.68426 SELECT ST_INTERSECTION(NULL, NULL); ST_INTERSECTION(NULL, NULL) NULL @@ -257,7 +257,7 @@ ST_NUMGEOMETRIES((ST_UNION(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), -183 +176 SELECT Round(ST_AREA(ST_BUFFER( ST_UNION( POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6); @@ -331,3 +331,86 @@ ST_DISTANCE(POINTFROMTEXT('POINT(7 1)'),MULTILINESTRINGFROMTEXT('MULTILINESTRING SELECT AsText(ST_UNION(POLYGONFROMTEXT('POLYGON((12 9, 3 6, 3 0, 12 9))'), POLYGONFROMTEXT('POLYGON((2 2, 7 2, 4 2, 2 0, 2 2))'))); AsText(ST_UNION(POLYGONFROMTEXT('POLYGON((12 9, 3 6, 3 0, 12 9))'), POLYGONFROMTEXT('POLYGON((2 2, 7 2, 4 2, 2 0, 2 2))'))) GEOMETRYCOLLECTION(POLYGON((2 0,2 2,3 2,3 6,12 9,3 0,3 1,2 0)),LINESTRING(5 2,7 2)) +SELECT ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER(ST_UNION( +MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 2 5, 7 6, 1 8),(0 0 ,1 6 ,0 1, 8 9, 2 4, 6 1, 3 5, 4 8), (9 3, 5 4, 1 8, 4 2, 5 8, 3 0))' ) , +MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 3 1, 2 7, 4 2, 6 2, 1 5))') +), 16))); +ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER(ST_UNION( +MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 2 5, 7 6, 1 8),(0 0 ,1 6 ,0 1, 8 9, 2 4, 6 1, 3 5, 4 8), (9 3, 5 4, 1 8, 4 2, 5 8, 3 0))' ) , +MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 3 1, 2 7, 4 2, 6 2 +280 +SELECT ST_NUMGEOMETRIES(ST_DIFFERENCE ( +ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 4 , 5 0 , 2 9 , 6 2 , 0 2 ) , ( 4 3 , 5 6 , 9 4 , 0 7 , 7 2 , 2 0 , 8 2 ) , ( 5 0 , 1 5 , 3 7 , 7 7 ) , ( 2 3 , 9 5 , 2 0 , 8 1 ) , ( 0 9 , 9 3 , 2 8 , 8 1 , 9 4 ) ) ' ), +ST_UNION ( +MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 7 2 , 6 2 , 2 6 , 2 2 ) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , +ENVELOPE( +MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) +) +) +), +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 9 , 1 3 , 7 3 , 8 5 ) , ( 5 0 , 8 1 , 2 0 , 7 4 , 1 0 ) , ( 9 2 , 5 2 , 6 5 , 8 8 , 0 2 ) , ( 0 8 , 3 9 , 4 0 , 1 0 ) , ( 0 0 , 7 6 , 8 3 , 0 0 ) ) ' ) +)); +ST_NUMGEOMETRIES(ST_DIFFERENCE ( +ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 4 , 5 0 , 2 9 , 6 2 , 0 2 ) , ( 4 3 , 5 6 , 9 4 , 0 7 , 7 2 , 2 0 , 8 2 ) , ( 5 0 , 1 5 , 3 7 , 7 7 ) , ( 2 3 , 9 5 , 2 0 , 8 1 ) , ( 0 9 , 9 3 , 2 8 , 8 1 , 9 4 ) +126 +SELECT ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER ( +ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 7 3 , 1 8 , 4 0 , 7 9 ) , ( 5 4 , 9 8 , 7 4 , 3 7 ) , ( 5 8 , 5 4 , 9 2 , 5 6 ) , ( 4 0 , 3 2 , 0 1 , 3 9 ) , ( 2 0 , 3 5 , 9 5 , 0 9 ) ) ' ) , +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 4 5 , 3 0 , 3 1 , 4 7 , 4 2 ) , ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) +) , 1 +))); +ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER ( +ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 7 3 , 1 8 , 4 0 , 7 9 ) , ( 5 4 , 9 8 , 7 4 , 3 7 ) , ( 5 8 , 5 4 , 9 2 , 5 6 ) , ( 4 0 , 3 2 , 0 1 , 3 9 ) , ( 2 0 , 3 5 , 9 5 , 0 9 ) ) ' ) , +MULTILINESTRI +659 +SELECT ASTEXT(ST_DIFFERENCE ( +POLYGONFROMTEXT( ' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) , +ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) ) ' ) , +ST_SYMDIFFERENCE ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 3 8 , 0 8 , 6 6 , 6 1 , 0 5 , 6 7 , 3 7 ) , ( 5 8 , 7 7 , 9 0 , 8 7 ) , ( 1 5 , 1 8 , 2 3 , 3 9 ) , ( 1 3 , 9 7 , 5 5 , 0 8 , 6 9 ) , ( 3 6 , 6 9 , 8 7 , 0 2 , 4 6 , 9 5 ) ) ' ) , +ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 9 4 , 2 0 , 2 2 , 7 2 , 6 2 ) , ( 5 2 , 8 2 , 4 8 , 3 4 ) , ( 1 0 , 1 4 , 2 7 , 7 0 , 1 5 ) , ( 2 8 , 4 4 , 5 0 , 7 0 , 4 0 ) ) ' ) , +GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 3 7 , 7 3 , 5 8 , 4 8 ) , ( 3 2 , 5 0 , 9 3 , 4 4 ) , ( 6 0 , 4 2 , 7 8 , 1 3 ) ) ' ) +) +) +) +)); +ASTEXT(ST_DIFFERENCE ( +POLYGONFROMTEXT( ' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) , +ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) ) ' ) , +ST_SYMDIFFERENCE ( +MULTILINESTRINGFROMTEX +POLYGON((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)) +SELECT ST_NUMGEOMETRIES(ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 0 8 , 1 9 , 5 7 , 2 8 , 5 8 , 6 7 ) , ( 4 5 , 8 4 , 0 3 , 5 1 ) , ( 6 8 , 2 7 , 1 6 , 9 9 , 7 2 ) , ( 9 5 , 2 8 , 1 2 , 9 6 , 2 0 ) ) ' ) , +MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 7 7 , 2 7, 6 8, 7 1 , 7 7 ) ) ) ' ) +)); +ST_NUMGEOMETRIES(ST_UNION ( +MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 0 8 , 1 9 , 5 7 , 2 8 , 5 8 , 6 7 ) , ( 4 5 , 8 4 , 0 3 , 5 1 ) , ( 6 8 , 2 7 , 1 6 , 9 9 , 7 2 ) , ( 9 5 , 2 8 , 1 2 , 9 6 , 2 0 ) ) ' ) , +MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( +50 +SELECT ST_BUFFER ( +LINESTRINGFROMTEXT( ' LINESTRING( 5 4 , 3 8 , 2 6 , 5 5 , 7 9 ) ' ) , +ST_DISTANCE ( +MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) , +ST_DIFFERENCE ( +MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , +MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) , ( ( 0 0 , 3 8 , 9 4 , 0 0 ) ) ) ' ) +) +) +) ; +ST_BUFFER ( +LINESTRINGFROMTEXT( ' LINESTRING( 5 4 , 3 8 , 2 6 , 5 5 , 7 9 ) ' ) , +ST_DISTANCE ( +MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) , +ST_DIFFERENCE ( +MULTIPOL +NULL +SELECT ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) , ( ( 0 0 , 3 8 , 9 4 , 0 0 ) ) ) ' ) ), MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) ) ; +ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , +NULL diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index cafd9a1d99a..59a9edb92d1 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -214,4 +214,69 @@ SELECT ST_DISTANCE(POINTFROMTEXT('POINT(7 1)'),MULTILINESTRINGFROMTEXT('MULTILIN #bug 839327 Crash in Gcalc_operation_reducer::end_couple with ST_UNION and MULTIPOLYGONs in 5.3-gis SELECT AsText(ST_UNION(POLYGONFROMTEXT('POLYGON((12 9, 3 6, 3 0, 12 9))'), POLYGONFROMTEXT('POLYGON((2 2, 7 2, 4 2, 2 0, 2 2))'))); +#bug 841622 Assertion `t->rp->type == Gcalc_function::shape_line' failed in Gcalc_operation_reducer::end_line in maria-5.3-gis + +SELECT ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER(ST_UNION( + MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 2 5, 7 6, 1 8),(0 0 ,1 6 ,0 1, 8 9, 2 4, 6 1, 3 5, 4 8), (9 3, 5 4, 1 8, 4 2, 5 8, 3 0))' ) , + MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 3 1, 2 7, 4 2, 6 2, 1 5))') + ), 16))); + +#bug 841625 Assertion `m_poly_borders->next' failed in Gcalc_operation_reducer::count_slice in maria-5.3-gis + +SELECT ST_NUMGEOMETRIES(ST_DIFFERENCE ( + ST_UNION ( + MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 4 , 5 0 , 2 9 , 6 2 , 0 2 ) , ( 4 3 , 5 6 , 9 4 , 0 7 , 7 2 , 2 0 , 8 2 ) , ( 5 0 , 1 5 , 3 7 , 7 7 ) , ( 2 3 , 9 5 , 2 0 , 8 1 ) , ( 0 9 , 9 3 , 2 8 , 8 1 , 9 4 ) ) ' ), + ST_UNION ( + MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 7 2 , 6 2 , 2 6 , 2 2 ) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , + ENVELOPE( + MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) + ) + ) + ), + MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 9 , 1 3 , 7 3 , 8 5 ) , ( 5 0 , 8 1 , 2 0 , 7 4 , 1 0 ) , ( 9 2 , 5 2 , 6 5 , 8 8 , 0 2 ) , ( 0 8 , 3 9 , 4 0 , 1 0 ) , ( 0 0 , 7 6 , 8 3 , 0 0 ) ) ' ) +)); + + +#bug 841638 Assertion `!m_prev || m_prev->x != x || m_prev->y != y' failed in Gcalc_shape_transporter::int_add_point in maria-5.3-gis +SELECT ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER ( + ST_UNION ( + MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 7 3 , 1 8 , 4 0 , 7 9 ) , ( 5 4 , 9 8 , 7 4 , 3 7 ) , ( 5 8 , 5 4 , 9 2 , 5 6 ) , ( 4 0 , 3 2 , 0 1 , 3 9 ) , ( 2 0 , 3 5 , 9 5 , 0 9 ) ) ' ) , + MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 4 5 , 3 0 , 3 1 , 4 7 , 4 2 ) , ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) + ) , 1 +))); + +#bug 841745 ssertion `!sp0->is_bottom()' failed in Gcalc_scan_iterator::find_intersections in maria-5.3-gis +SELECT ASTEXT(ST_DIFFERENCE ( + POLYGONFROMTEXT( ' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) , + ST_UNION ( + MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) ) ' ) , + ST_SYMDIFFERENCE ( + MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 3 8 , 0 8 , 6 6 , 6 1 , 0 5 , 6 7 , 3 7 ) , ( 5 8 , 7 7 , 9 0 , 8 7 ) , ( 1 5 , 1 8 , 2 3 , 3 9 ) , ( 1 3 , 9 7 , 5 5 , 0 8 , 6 9 ) , ( 3 6 , 6 9 , 8 7 , 0 2 , 4 6 , 9 5 ) ) ' ) , + ST_UNION ( + MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 9 4 , 2 0 , 2 2 , 7 2 , 6 2 ) , ( 5 2 , 8 2 , 4 8 , 3 4 ) , ( 1 0 , 1 4 , 2 7 , 7 0 , 1 5 ) , ( 2 8 , 4 4 , 5 0 , 7 0 , 4 0 ) ) ' ) , + GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 3 7 , 7 3 , 5 8 , 4 8 ) , ( 3 2 , 5 0 , 9 3 , 4 4 ) , ( 6 0 , 4 2 , 7 8 , 1 3 ) ) ' ) + ) + ) + ) +)); + +#bug 841773 Assertion `t0->rp->type == t1->rp->type' failed in Gcalc_operation_reducer::end_couple in maria-5.3-gis +SELECT ST_NUMGEOMETRIES(ST_UNION ( + MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 0 8 , 1 9 , 5 7 , 2 8 , 5 8 , 6 7 ) , ( 4 5 , 8 4 , 0 3 , 5 1 ) , ( 6 8 , 2 7 , 1 6 , 9 9 , 7 2 ) , ( 9 5 , 2 8 , 1 2 , 9 6 , 2 0 ) ) ' ) , + MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 7 7 , 2 7, 6 8, 7 1 , 7 7 ) ) ) ' ) +)); + +#bug 841662 Third assertion `n > 0 && n < SINUSES_CALCULATED*2+1' in get_n_sincos +SELECT ST_BUFFER ( + LINESTRINGFROMTEXT( ' LINESTRING( 5 4 , 3 8 , 2 6 , 5 5 , 7 9 ) ' ) , + ST_DISTANCE ( + MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) , + ST_DIFFERENCE ( + MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , + MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) , ( ( 0 0 , 3 8 , 9 4 , 0 0 ) ) ) ' ) + ) + ) + ) ; +SELECT ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) , ( ( 0 0 , 3 8 , 9 4 , 0 0 ) ) ) ' ) ), MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) ) ; + diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index c5f288388f8..607f55a5d3f 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -683,7 +683,8 @@ int Gcalc_scan_iterator::normal_scan() #define INTERSECTION_ZERO 0.000000000001 -int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, +int Gcalc_scan_iterator::add_intersection(int n_row, + const point *a, const point *b, Gcalc_dyn_list::Item ***p_hook) { intersection *isc= new_intersection(); @@ -693,6 +694,7 @@ int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, m_n_intersections++; **p_hook= isc; *p_hook= &isc->next; + isc->n_row= n_row; isc->thread_a= a->thread; isc->thread_b= b->thread; @@ -703,13 +705,22 @@ int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, if (!a0->horiz_dir && !b0->horiz_dir) { - double dk= a0->dx_dy - b0->dx_dy; - double dy= (b0->x - a0->x)/dk; + double b0_x= a0->next_pi->x - a0->pi->x; + double b0_y= a0->next_pi->y - a0->pi->y; + double b1_x= b0->next_pi->x - b0->pi->x; + double b1_y= b0->next_pi->y - b0->pi->y; + double b1xb0= b1_x * b0_y - b1_y * b0_x; + double t= (a0->pi->x - b0->pi->x) * b0_y - (a0->pi->y - b0->pi->y) * b0_x; + if (fabs(b1xb0) < INTERSECTION_ZERO) + { + isc->y= current_state->y; + isc->x= a0->x; + return 0; + } - if (fabs(dk) < INTERSECTION_ZERO) - dy= 0.0; - isc->y= current_state->y + dy; - isc->x= a0->x + dy*a0->dx_dy; + t/= b1xb0; + isc->x= b0->pi->x + b1_x*t; + isc->y= b0->pi->y + b1_y*t; return 0; } isc->y= next_state->y; @@ -720,13 +731,13 @@ int Gcalc_scan_iterator::add_intersection(const point *a, const point *b, int Gcalc_scan_iterator::find_intersections() { - point *sp1= next_state->slice; Gcalc_dyn_list::Item **hook; m_n_intersections= 0; { /* Set links between slicepoints */ point *sp0= current_state->slice; + point *sp1= next_state->slice; for (; sp1; sp0= sp0->get_next(),sp1= sp1->get_next()) { DBUG_ASSERT(!sp0->is_bottom()); @@ -737,30 +748,34 @@ int Gcalc_scan_iterator::find_intersections() hook= (Gcalc_dyn_list::Item **)&m_intersections; bool intersections_found; + int n_row= 0; - point *last_possible_isc= NULL; do { point **pprev_s1= &next_state->slice; intersections_found= false; - sp1= next_state->slice->get_next(); - point *cur_possible_isc= NULL; - for (; sp1 != last_possible_isc; - pprev_s1= (point **)(&(*pprev_s1)->next), sp1= sp1->get_next()) + n_row++; + for (;;) { point *prev_s1= *pprev_s1; - if (prev_s1->x <= sp1->x) - continue; + point *s1= prev_s1->get_next(); + if (!s1) + break; + if (prev_s1->x <= s1->x) + { + pprev_s1= (point **) &prev_s1->next; + continue; + } intersections_found= true; - if (add_intersection(prev_s1, sp1, &hook)) + if (add_intersection(n_row, prev_s1, s1, &hook)) return 1; - *pprev_s1= sp1; - prev_s1->next= sp1->next; - sp1->next= prev_s1; - sp1= prev_s1; - cur_possible_isc= sp1; - } - last_possible_isc= cur_possible_isc; + *pprev_s1= s1; + prev_s1->next= s1->next; + s1->next= prev_s1; + pprev_s1= (point **) &prev_s1->next; + if (!*pprev_s1) + break; + }; } while (intersections_found); *hook= NULL; @@ -772,7 +787,13 @@ static int compare_intersections(const void *e0, const void *e1) { Gcalc_scan_iterator::intersection *i0= (Gcalc_scan_iterator::intersection *)e0; Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1; - if (i0->y != i1->y) + + if (fabs(i0->y - i1->y) > 0.00000000000001) + return i0->y > i1->y; + + if (i0->n_row != i1->n_row) + return i0->n_row > i1->n_row; + if (!coord_eq(i0->y, i1->y)) return i0->y > i1->y; return i0->x > i1->x; } @@ -810,7 +831,8 @@ int Gcalc_scan_iterator::intersection_scan() { point *sp0, *sp1; Gcalc_dyn_list::Item **hook; - intersection *next_intersection; + intersection *next_intersection= NULL; + int met_equal= 0; if (m_cur_intersection != m_intersections) { @@ -860,7 +882,6 @@ int Gcalc_scan_iterator::intersection_scan() next_state->y= m_cur_intersection->y; -found_equal_intersection: sp0= current_state->slice; hook= (Gcalc_dyn_list::Item **) &next_state->slice; sp1= next_state->slice; @@ -872,6 +893,10 @@ found_equal_intersection: if (sp0->thread == m_cur_intersection->thread_a || sp0->thread == m_cur_intersection->thread_b) { +#ifdef REACTIVATE_THIS + DBUG_ASSERT(sp0->thread != m_cur_intersection->thread_a || + sp0->get_next()->thread == m_cur_intersection->thread_b); +#endif /*REACTIVATE_THIS*/ sp1->copy_core(sp0); sp1->x= m_cur_intersection->x; sp1->event= scev_intersection; @@ -888,6 +913,7 @@ found_equal_intersection: { sp1->event= scev_intersection; mark_event_position1(sp1, hook); + met_equal= 1; } else sp1->event= scev_none; @@ -900,13 +926,64 @@ found_equal_intersection: *hook= NULL; } - next_intersection= m_cur_intersection->get_next(); - if (next_intersection && - coord_eq(next_intersection->x, m_cur_intersection->x) && - coord_eq(next_intersection->y, m_cur_intersection->y)) + if (met_equal) { - m_cur_intersection= next_intersection; - goto found_equal_intersection; + /* Remove superfluous intersections. */ + /* Double operations can produce unexact result, so it's needed. */ + for (sp0= next_state->event_position; + sp0 != *next_state->event_end_hook; + sp0= sp0->get_next()) + { + for (sp1= sp0->get_next(); + sp1 != *next_state->event_end_hook; + sp1= sp1->get_next()) + { + intersection *isc= m_cur_intersection; + while (isc->get_next()) + { + intersection *cur_isc= isc->get_next(); + if ((cur_isc->thread_a == sp0->thread && + cur_isc->thread_b == sp1->thread) || + (cur_isc->thread_a == sp1->thread && + cur_isc->thread_b == sp0->thread)) + { + /* The superfluous intersection should be close to the current. */ + DBUG_ASSERT(fabs(cur_isc->x-m_cur_intersection->x) + + fabs(cur_isc->y-m_cur_intersection->y) < + INTERSECTION_ZERO); + isc->next= isc->next->next; + free_item(cur_isc); + } + else + isc= isc->get_next(); + } + } + } + } + + for (next_intersection= m_cur_intersection->get_next(); + next_intersection && + coord_eq(next_intersection->x, m_cur_intersection->x) && + coord_eq(next_intersection->y, m_cur_intersection->y); + next_intersection= next_intersection->get_next()) + { + /* Handle equal intersections. We only need to set proper events */ + sp0= current_state->slice; + hook= (Gcalc_dyn_list::Item **) &next_state->slice; + sp1= next_state->slice; + next_state->clear_event_position(); + + for (; sp0; + hook= &sp1->next, sp1= sp1->get_next(), sp0= sp0->get_next()) + { + if (sp0->thread == next_intersection->thread_a || + sp0->thread == next_intersection->thread_b || + sp1->event == scev_intersection) + { + sp1->event= scev_intersection; + mark_event_position1(sp1, hook); + } + } } m_cur_intersection= next_intersection; diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index 9ffe39dd370..ebe2bcffe5c 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -303,6 +303,7 @@ public: class intersection : public Gcalc_dyn_list::Item { public: + int n_row; sc_thread_id thread_a; sc_thread_id thread_b; double x; @@ -371,7 +372,7 @@ private: void sort_intersections(); int handle_intersections(); int insert_top_point(); - int add_intersection(const point *a, const point *b, + int add_intersection(int n_row, const point *a, const point *b, Gcalc_dyn_list::Item ***p_hook); int find_intersections(); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index ea849bb10a3..631b63812b5 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1789,6 +1789,14 @@ double Item_func_distance::val_real() if (g2->store_shapes(&trn) || func.alloc_states()) goto mem_error; + if (obj2_si == 0 || func.get_nshapes() == obj2_si) + { + distance= 0.0; + null_value= 1; + goto exit; + } + + collector.prepare_operation(); scan_it.init(&collector); From b408b1bbbc87246df8e9728cec90ce215dc08ec2 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 13 Sep 2011 15:19:55 +0500 Subject: [PATCH 21/40] Fix for bug #848901 Assertion `fabs(cur_isc->x-m_cur_intersection->x) + fabs(cur_isc->y-m_cur_intersection->y) < 0.000000000001' failed in Gcalc_scan_iterator::intersection_scan() in maria-5.3-gis That assertion's check was too tight. Released it a bit. per-file comments: mysql-test/r/gis-precise.result Fix for bug #848901 test result updated. mysql-test/t/gis-precise.test Fix for bug #848901 test case added. sql/gcalc_slicescan.cc Fix for bug #848901 The DBUG_ASSERT check is too tight here. --- mysql-test/r/gis-precise.result | 3 +++ mysql-test/t/gis-precise.test | 3 +++ sql/gcalc_slicescan.cc | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 5ebce7f603e..2a70f7806bf 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -414,3 +414,6 @@ NULL SELECT ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) , ( ( 0 0 , 3 8 , 9 4 , 0 0 ) ) ) ' ) ), MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) ) ; ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , NULL +SELECT ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 , 7 2 , 3 4 ) ' ) , ST_BUFFER ( ST_UNION ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 6 2 , 1 3 , 2 2 , 2 2 ) ) ) ' ) , GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 1 4 , 9 9 , 3 0 , 6 6 ) , ( 3 5 , 1 0 , 5 8 , 6 1 ) , ( 8 9 , 6 1 , 5 1 , 6 2 ) , ( 2 2 , 7 5 , 5 8 , 6 9 , 3 0 ) , ( 8 0 , 8 4 , 6 7 , 5 5 ) ) ' ) ) , NUMPOINTS( EXTERIORRING( POLYGONFROMTEXT( ' POLYGON( ( 0 0 , 2 1 , 8 2 , 0 0 ) ) ' ) ) ) ) ) ) , ST_INTERSECTION ( POLYGONFROMTEXT( ' POLYGON( ( 2 3, 5 7 , 3 7 , 4 1 , 0 5, 2 3 ) ) ' ) , MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 3 , 1 4 , 6 4 , 9 1 , 3 4 , 1 8 ) , ( 9 9 , 0 3 , 1 7 , 9 9 ) ) ' ) ) ) , POLYGONFROMTEXT( ' POLYGON( ( 1 3, 7 2 , 1 5 , 3 8 , 5 0, 1 3) ) ' ) ) ) ; +ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 +26 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 59a9edb92d1..467cfbcc1bd 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -279,4 +279,7 @@ SELECT ST_BUFFER ( ) ; SELECT ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) , ( ( 0 0 , 3 8 , 9 4 , 0 0 ) ) ) ' ) ), MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) ) ; +#bug 848901 Assertion `fabs(cur_isc->x-m_cur_intersection->x) + fabs(cur_isc->y-m_cur_intersection->y) < 0.000000000001' failed in Gcalc_scan_iterator::intersection_scan() in maria-5.3-gis + +SELECT ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 , 7 2 , 3 4 ) ' ) , ST_BUFFER ( ST_UNION ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 6 2 , 1 3 , 2 2 , 2 2 ) ) ) ' ) , GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 1 4 , 9 9 , 3 0 , 6 6 ) , ( 3 5 , 1 0 , 5 8 , 6 1 ) , ( 8 9 , 6 1 , 5 1 , 6 2 ) , ( 2 2 , 7 5 , 5 8 , 6 9 , 3 0 ) , ( 8 0 , 8 4 , 6 7 , 5 5 ) ) ' ) ) , NUMPOINTS( EXTERIORRING( POLYGONFROMTEXT( ' POLYGON( ( 0 0 , 2 1 , 8 2 , 0 0 ) ) ' ) ) ) ) ) ) , ST_INTERSECTION ( POLYGONFROMTEXT( ' POLYGON( ( 2 3, 5 7 , 3 7 , 4 1 , 0 5, 2 3 ) ) ' ) , MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 3 , 1 4 , 6 4 , 9 1 , 3 4 , 1 8 ) , ( 9 9 , 0 3 , 1 7 , 9 9 ) ) ' ) ) ) , POLYGONFROMTEXT( ' POLYGON( ( 1 3, 7 2 , 1 5 , 3 8 , 5 0, 1 3) ) ' ) ) ) ; diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 607f55a5d3f..6f41a5fc371 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -950,7 +950,7 @@ int Gcalc_scan_iterator::intersection_scan() /* The superfluous intersection should be close to the current. */ DBUG_ASSERT(fabs(cur_isc->x-m_cur_intersection->x) + fabs(cur_isc->y-m_cur_intersection->y) < - INTERSECTION_ZERO); + 0.00000000001); isc->next= isc->next->next; free_item(cur_isc); } From 5a04ac7bf0ee359fb36f4ebc00f0aebc142d36b7 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 13 Sep 2011 18:26:16 +0500 Subject: [PATCH 22/40] Fix for bug 848939 Wrong result with ST_INTERSECTION between linestrings and a polygon in 5.3-gis Coordinates were mistakenly reversed for MULTIPOINT. per-file comments: mysql-test/r/gis-precise.result Fix for bug 848939 Wrong result with ST_INTERSECTION between linestrings and a polygon in 5.3-gis test result updated. mysql-test/t/gis-precise.test Fix for bug 848939 Wrong result with ST_INTERSECTION between linestrings and a polygon in 5.3-gis test case added. sql/gcalc_tools.cc Fix for bug 848939 Wrong result with ST_INTERSECTION between linestrings and a polygon in 5.3-gis coordinates set in the proper order. --- mysql-test/r/gis-precise.result | 9 ++++++--- mysql-test/t/gis-precise.test | 3 +++ sql/gcalc_tools.cc | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 2a70f7806bf..c3f77f6680f 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -127,10 +127,10 @@ astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFr POLYGON((26.4705882352941 23.8235294117647,21.9512195121951 27.4390243902439,23.855421686747 29.8192771084337,29.2899408284024 26.3609467455621,26.4705882352941 23.8235294117647)) select astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50, 0 0)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45, 50 5)'))); astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50, 0 0)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45, 50 5)'))) -MULTIPOINT(23.8235294117647 26.4705882352941,26.3609467455621 29.2899408284024,27.4390243902439 21.9512195121951,29.8192771084337 23.855421686747) +MULTIPOINT(26.4705882352941 23.8235294117647,29.2899408284024 26.3609467455621,21.9512195121951 27.4390243902439,23.855421686747 29.8192771084337) select astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45)'))); astext(ST_Intersection(GeomFromText('LINESTRING(0 0, 50 45, 40 50)'), GeomFromText('LINESTRING(50 5, 55 10, 0 45)'))) -POINT(26.3609467455621 29.2899408284024) +POINT(29.2899408284024 26.3609467455621) select astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POINT(20 20)'))); astext(ST_Intersection(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('POINT(20 20)'))) POINT(20 20) @@ -416,4 +416,7 @@ ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFR NULL SELECT ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 , 7 2 , 3 4 ) ' ) , ST_BUFFER ( ST_UNION ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 6 2 , 1 3 , 2 2 , 2 2 ) ) ) ' ) , GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 1 4 , 9 9 , 3 0 , 6 6 ) , ( 3 5 , 1 0 , 5 8 , 6 1 ) , ( 8 9 , 6 1 , 5 1 , 6 2 ) , ( 2 2 , 7 5 , 5 8 , 6 9 , 3 0 ) , ( 8 0 , 8 4 , 6 7 , 5 5 ) ) ' ) ) , NUMPOINTS( EXTERIORRING( POLYGONFROMTEXT( ' POLYGON( ( 0 0 , 2 1 , 8 2 , 0 0 ) ) ' ) ) ) ) ) ) , ST_INTERSECTION ( POLYGONFROMTEXT( ' POLYGON( ( 2 3, 5 7 , 3 7 , 4 1 , 0 5, 2 3 ) ) ' ) , MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 3 , 1 4 , 6 4 , 9 1 , 3 4 , 1 8 ) , ( 9 9 , 0 3 , 1 7 , 9 9 ) ) ' ) ) ) , POLYGONFROMTEXT( ' POLYGON( ( 1 3, 7 2 , 1 5 , 3 8 , 5 0, 1 3) ) ' ) ) ) ; ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 -26 +27 +SELECT ASTEXT(ST_INTERSECTION( GEOMETRYFROMTEXT('GEOMETRYCOLLECTION(LINESTRING(7 7,5.33333333333333 7),LINESTRING(5.33333333333333 7,0 7,5 8,5.33333333333333 7),LINESTRING(5.33333333333333 7,7 2,7 7),POLYGON((0 5,3 5,3 2,1 2,1 1,3 1,3 0,0 0,0 3,2 3,2 4,0 4,0 5)))'), geomETRYFROMTEXT(' MULTILINESTRING( ( 5 1 , 3 7 , 6 1 , 7 0 ) , ( 1 6 , 8 5 , 7 5 , 5 6 ) )') )); +ASTEXT(ST_INTERSECTION( GEOMETRYFROMTEXT('GEOMETRYCOLLECTION(LINESTRING(7 7,5.33333333333333 7),LINESTRING(5.33333333333333 7,0 7,5 8,5.33333333333333 7),LINESTRING(5.33333333333333 7,7 2,7 7),POLYGON((0 5,3 5,3 2,1 2,1 1,3 1,3 0,0 0,0 3,2 3,2 4,0 4,0 5)) +MULTIPOINT(7 5,7 5.14285714285714,5.9 5.3,5.8 5.6,3 7) diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 467cfbcc1bd..8e630766004 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -283,3 +283,6 @@ SELECT ST_DISTANCE ( ST_DIFFERENCE ( MULTI SELECT ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 , 7 2 , 3 4 ) ' ) , ST_BUFFER ( ST_UNION ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 6 2 , 1 3 , 2 2 , 2 2 ) ) ) ' ) , GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 1 4 , 9 9 , 3 0 , 6 6 ) , ( 3 5 , 1 0 , 5 8 , 6 1 ) , ( 8 9 , 6 1 , 5 1 , 6 2 ) , ( 2 2 , 7 5 , 5 8 , 6 9 , 3 0 ) , ( 8 0 , 8 4 , 6 7 , 5 5 ) ) ' ) ) , NUMPOINTS( EXTERIORRING( POLYGONFROMTEXT( ' POLYGON( ( 0 0 , 2 1 , 8 2 , 0 0 ) ) ' ) ) ) ) ) ) , ST_INTERSECTION ( POLYGONFROMTEXT( ' POLYGON( ( 2 3, 5 7 , 3 7 , 4 1 , 0 5, 2 3 ) ) ' ) , MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 3 , 1 4 , 6 4 , 9 1 , 3 4 , 1 8 ) , ( 9 9 , 0 3 , 1 7 , 9 9 ) ) ' ) ) ) , POLYGONFROMTEXT( ' POLYGON( ( 1 3, 7 2 , 1 5 , 3 8 , 5 0, 1 3) ) ' ) ) ) ; +#bug 848939 Wrong result with ST_INTERSECTION between linestrings and a polygon in 5.3-gis +SELECT ASTEXT(ST_INTERSECTION( GEOMETRYFROMTEXT('GEOMETRYCOLLECTION(LINESTRING(7 7,5.33333333333333 7),LINESTRING(5.33333333333333 7,0 7,5 8,5.33333333333333 7),LINESTRING(5.33333333333333 7,7 2,7 7),POLYGON((0 5,3 5,3 2,1 2,1 1,3 1,3 0,0 0,0 3,2 3,2 4,0 4,0 5)))'), geomETRYFROMTEXT(' MULTILINESTRING( ( 5 1 , 3 7 , 6 1 , 7 0 ) , ( 1 6 , 8 5 , 7 5 , 5 6 ) )') )); + diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 3ee58646ca4..baff6278444 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -853,8 +853,8 @@ int Gcalc_operation_reducer::add_single_point(const Gcalc_heap::Info *p, else { rp->intersection_point= true; - rp->x= si->get_y(); - rp->y= si->get_events()->x; + rp->y= si->get_y(); + rp->x= si->get_events()->x; } return 0; } From 0249413a6ae4a5900b51f434b361b9efa6133ad1 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 21 Sep 2011 00:04:41 +0500 Subject: [PATCH 23/40] several bugs fixed here. 849789 Second assertion `m_poly_borders->next' failed in Gcalc_operation_reducer::count_slice in maria-5.3-gis 849791 Fourth assertion `n > 0 && n < SINUSES_CALCULATED*2+1' in get_n_sincos 849789 Second assertion `m_poly_borders->next' failed in Gcalc_operation_reducer::count_slice in maria-5.3-gis 848901 Assertion `fabs(cur_isc->x-m_cur_intersection->x) + fabs(cur_isc->y-m_cur_intersection->y) < 0.000000000001' failed in Gcalc_scan_iterator::intersection_scan() in maria-5.3-gis per-file comments: mysql-test/r/gis-precise.result test result updated. mysql-test/r/gis.result test result updated. sql/gcalc_slicescan.cc bugfixes. sql/gcalc_slicescan.h bugfixes. sql/gcalc_tools.cc bugfixes. sql/gcalc_tools.h bugfixes. sql/item_geofunc.cc bugfixes. sql/spatial.cc bugfixes. --- mysql-test/r/gis-precise.result | 12 +- mysql-test/r/gis.result | 4 +- sql/gcalc_slicescan.cc | 1328 +++++++++++++++++++++++++++---- sql/gcalc_slicescan.h | 179 ++++- sql/gcalc_tools.cc | 293 ++++--- sql/gcalc_tools.h | 95 +-- sql/item_geofunc.cc | 3 +- sql/spatial.cc | 2 + 8 files changed, 1579 insertions(+), 337 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index c3f77f6680f..5adecfb5a35 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -189,7 +189,7 @@ st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')) -1 +0 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')) 1 @@ -257,7 +257,7 @@ ST_NUMGEOMETRIES((ST_UNION(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), -176 +185 SELECT Round(ST_AREA(ST_BUFFER( ST_UNION( POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6); @@ -338,7 +338,7 @@ MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 3 1, 2 7, 4 2, 6 2, 1 5))') ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 2 5, 7 6, 1 8),(0 0 ,1 6 ,0 1, 8 9, 2 4, 6 1, 3 5, 4 8), (9 3, 5 4, 1 8, 4 2, 5 8, 3 0))' ) , MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 3 1, 2 7, 4 2, 6 2 -280 +275 SELECT ST_NUMGEOMETRIES(ST_DIFFERENCE ( ST_UNION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 4 , 5 0 , 2 9 , 6 2 , 0 2 ) , ( 4 3 , 5 6 , 9 4 , 0 7 , 7 2 , 2 0 , 8 2 ) , ( 5 0 , 1 5 , 3 7 , 7 7 ) , ( 2 3 , 9 5 , 2 0 , 8 1 ) , ( 0 9 , 9 3 , 2 8 , 8 1 , 9 4 ) ) ' ), @@ -354,7 +354,7 @@ MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 9 , 1 3 , 7 3 , 8 5 ) , ( 5 0 , ST_NUMGEOMETRIES(ST_DIFFERENCE ( ST_UNION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 4 , 5 0 , 2 9 , 6 2 , 0 2 ) , ( 4 3 , 5 6 , 9 4 , 0 7 , 7 2 , 2 0 , 8 2 ) , ( 5 0 , 1 5 , 3 7 , 7 7 ) , ( 2 3 , 9 5 , 2 0 , 8 1 ) , ( 0 9 , 9 3 , 2 8 , 8 1 , 9 4 ) -126 +123 SELECT ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER ( ST_UNION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 7 3 , 1 8 , 4 0 , 7 9 ) , ( 5 4 , 9 8 , 7 4 , 3 7 ) , ( 5 8 , 5 4 , 9 2 , 5 6 ) , ( 4 0 , 3 2 , 0 1 , 3 9 ) , ( 2 0 , 3 5 , 9 5 , 0 9 ) ) ' ) , @@ -365,7 +365,7 @@ ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER ( ST_UNION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 7 3 , 1 8 , 4 0 , 7 9 ) , ( 5 4 , 9 8 , 7 4 , 3 7 ) , ( 5 8 , 5 4 , 9 2 , 5 6 ) , ( 4 0 , 3 2 , 0 1 , 3 9 ) , ( 2 0 , 3 5 , 9 5 , 0 9 ) ) ' ) , MULTILINESTRI -659 +653 SELECT ASTEXT(ST_DIFFERENCE ( POLYGONFROMTEXT( ' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) , ST_UNION ( @@ -416,7 +416,7 @@ ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFR NULL SELECT ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 , 7 2 , 3 4 ) ' ) , ST_BUFFER ( ST_UNION ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 6 2 , 1 3 , 2 2 , 2 2 ) ) ) ' ) , GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 1 4 , 9 9 , 3 0 , 6 6 ) , ( 3 5 , 1 0 , 5 8 , 6 1 ) , ( 8 9 , 6 1 , 5 1 , 6 2 ) , ( 2 2 , 7 5 , 5 8 , 6 9 , 3 0 ) , ( 8 0 , 8 4 , 6 7 , 5 5 ) ) ' ) ) , NUMPOINTS( EXTERIORRING( POLYGONFROMTEXT( ' POLYGON( ( 0 0 , 2 1 , 8 2 , 0 0 ) ) ' ) ) ) ) ) ) , ST_INTERSECTION ( POLYGONFROMTEXT( ' POLYGON( ( 2 3, 5 7 , 3 7 , 4 1 , 0 5, 2 3 ) ) ' ) , MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 3 , 1 4 , 6 4 , 9 1 , 3 4 , 1 8 ) , ( 9 9 , 0 3 , 1 7 , 9 9 ) ) ' ) ) ) , POLYGONFROMTEXT( ' POLYGON( ( 1 3, 7 2 , 1 5 , 3 8 , 5 0, 1 3) ) ' ) ) ) ; ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 -27 +25 SELECT ASTEXT(ST_INTERSECTION( GEOMETRYFROMTEXT('GEOMETRYCOLLECTION(LINESTRING(7 7,5.33333333333333 7),LINESTRING(5.33333333333333 7,0 7,5 8,5.33333333333333 7),LINESTRING(5.33333333333333 7,7 2,7 7),POLYGON((0 5,3 5,3 2,1 2,1 1,3 1,3 0,0 0,0 3,2 3,2 4,0 4,0 5)))'), geomETRYFROMTEXT(' MULTILINESTRING( ( 5 1 , 3 7 , 6 1 , 7 0 ) , ( 1 6 , 8 5 , 7 5 , 5 6 ) )') )); ASTEXT(ST_INTERSECTION( GEOMETRYFROMTEXT('GEOMETRYCOLLECTION(LINESTRING(7 7,5.33333333333333 7),LINESTRING(5.33333333333333 7,0 7,5 8,5.33333333333333 7),LINESTRING(5.33333333333333 7,7 2,7 7),POLYGON((0 5,3 5,3 2,1 2,1 1,3 1,3 0,0 0,0 3,2 3,2 4,0 4,0 5)) MULTIPOINT(7 5,7 5.14285714285714,5.9 5.3,5.8 5.6,3 7) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index b3993657182..190795855dd 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -850,7 +850,7 @@ mbroverlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrtouches FROM t1 a1 JOIN t1 a2 ON MBRTouches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrtouches -big,center,down,down2,left,left2,right,right2,small,up,up2 +down2,left2,right2,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrwithin FROM t1 a1 JOIN t1 a2 ON MBRWithin( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrwithin big,center @@ -871,7 +871,7 @@ overlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS touches FROM t1 a1 JOIN t1 a2 ON Touches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; touches -big,center,down,down2,left,left2,right,right2,small,up,up2 +down2,left2,right2,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS within FROM t1 a1 JOIN t1 a2 ON Within( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; within big,center diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 6f41a5fc371..07120d2e87e 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -116,6 +116,450 @@ void Gcalc_dyn_list::reset() } +/* Internal coordinate operations implementations */ + +void Gcalc_internal_coord::set_zero() +{ + int n_res= 0; + do + { + digits[n_res++]= 0; + } while (n_res < n_digits); + sign= 0; +} + + +int Gcalc_internal_coord::is_zero() const +{ + int n_res= 0; + do + { + if (digits[n_res++] != 0) + return 0; + } while (n_res < n_digits); + return 1; +} + + +#ifdef GCALC_CHECK_WITH_FLOAT +long double Gcalc_internal_coord::get_double() const +{ + int n= 0; + long double res= 0.0; + do + { + res*= (long double) DIG_BASE; + res+= digits[n]; + } while(++n < n_digits); + + n= 0; + do + { + if (n & 1) + res/= (long double) C_SCALE; + } while(++n < n_digits); + + if (sign) + res*= -1.0; + return res; +} +#endif /*GCALC_CHECK_WITH_FLOAT*/ + + +static void do_add(Gcalc_internal_coord *result, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b) +{ + DBUG_ASSERT(a->n_digits == b->n_digits); + DBUG_ASSERT(a->n_digits == result->n_digits); + int n_digit= a->n_digits-1; + coord_digit_t carry= 0; + + do + { + if ((result->digits[n_digit]= + a->digits[n_digit] + b->digits[n_digit] + carry) >= DIG_BASE) + { + carry= 1; + result->digits[n_digit]-= DIG_BASE; + } + else + carry= 0; + } while (n_digit--); + DBUG_ASSERT(carry == 0); + result->sign= a->sign; +} + + +static void do_sub(Gcalc_internal_coord *result, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b) +{ + DBUG_ASSERT(a->n_digits == b->n_digits); + DBUG_ASSERT(a->n_digits == result->n_digits); + int n_digit= a->n_digits-1; + coord_digit_t carry= 0; + + do + { + if ((result->digits[n_digit]= + a->digits[n_digit] - b->digits[n_digit] - carry) < 0) + { + carry= 1; + result->digits[n_digit]+= DIG_BASE; + } + else + carry= 0; + } while (n_digit--); + DBUG_ASSERT(carry == 0); + if (a->sign && result->is_zero()) + result->sign= 0; + else + result->sign= a->sign; +} + + +static int do_cmp(const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b) +{ + DBUG_ASSERT(a->n_digits == b->n_digits); + int n_digit= 0; + + do + { + coord_digit_t d= a->digits[n_digit] - b->digits[n_digit]; + if (d > 0) + return 1; + if (d < 0) + return -1; + n_digit++; + } while (n_digit < a->n_digits); + + return 0; +} + + +#ifdef GCALC_CHECK_WITH_FLOAT +static int de_check(long double a, long double b) +{ + long double d= a - b; + if (d < (long double) 1e-6 && d > (long double) -1e-6) + return 1; + printf("xxx\n"); + return 0; +} + +static int de_check1(long double a, long double b) +{ + long double d= a - b; + if (d < (long double) 1e-6 && d > (long double) -1e-6) + return 1; + return 0; +} +static int de_weak(long double a, long double b) +{ + long double d= a - b; + if (d < (long double) 1 && d > (long double) -1) + return 1; + return 0; +} +#endif /*GCALC_CHECK_WITH_FLOAT*/ + + +void gcalc_mul_coord(Gcalc_internal_coord *result, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b) +{ + DBUG_ASSERT(result->n_digits == a->n_digits + b->n_digits); + int n_a, n_b, n_res; + coord_digit_t carry= 0; + + result->set_zero(); + if (a->is_zero() || b->is_zero()) + return; + + n_a= a->n_digits - 1; + do + { + n_b= b->n_digits - 1; + do + { + coord2 mul= ((coord2) a->digits[n_a]) * b->digits[n_b] + carry + + result->digits[n_a + n_b + 1]; + result->digits[n_a + n_b + 1]= mul % DIG_BASE; + carry= mul / DIG_BASE; + } while (n_b--); + if (carry) + { + for (n_res= n_a; (result->digits[n_res]+= carry) >= DIG_BASE; n_res--) + { + result->digits[n_res]-= DIG_BASE; + carry= 1; + } + carry= 0; + } + } while (n_a--); + result->sign= a->sign != b->sign; +#ifdef GCALC_CHECK_WITH_FLOAT + DBUG_ASSERT(de_check(a->get_double() * b->get_double(), + result->get_double())); +#endif /*GCALC_CHECK_WITH_FLOAT*/ +} + + +void gcalc_add_coord(Gcalc_internal_coord *result, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b) +{ + if (a->sign == b->sign) + do_add(result, a, b); + else + { + int cmp_res= do_cmp(a, b); + if (cmp_res == 0) + result->set_zero(); + else if (cmp_res > 0) + do_sub(result, a, b); + else + do_sub(result, b, a); + } +#ifdef GCALC_CHECK_WITH_FLOAT + DBUG_ASSERT(de_check(a->get_double() + b->get_double(), + result->get_double())); +#endif /*GCALC_CHECK_WITH_FLOAT*/ +} + + +void gcalc_sub_coord(Gcalc_internal_coord *result, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b) +{ + if (a->sign != b->sign) + do_add(result, a, b); + else + { + int cmp_res= do_cmp(a, b); + if (cmp_res == 0) + result->set_zero(); + else if (cmp_res > 0) + do_sub(result, a, b); + else + { + do_sub(result, b, a); + result->sign= 1 - result->sign; + } + } +#ifdef GCALC_CHECK_WITH_FLOAT + DBUG_ASSERT(de_check(a->get_double() - b->get_double(), + result->get_double())); +#endif /*GCALC_CHECK_WITH_FLOAT*/ +} + + +int gcalc_cmp_coord(const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b) +{ + int result; + if (a->sign != b->sign) + return a->sign ? -1 : 1; + result= a->sign ? do_cmp(b, a) : do_cmp(a, b); +#ifdef GCALC_CHECK_WITH_FLOAT + if (result == 0) + DBUG_ASSERT(de_check(a->get_double(), b->get_double())); + else if (result == 1) + DBUG_ASSERT(de_check1(a->get_double(), b->get_double()) || + a->get_double() > b->get_double()); + else + DBUG_ASSERT(de_check1(a->get_double(), b->get_double()) || + a->get_double() < b->get_double()); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result; +} + + +int Gcalc_coord1::set_double(double d) +{ + double ds= d * C_SCALE; + init(); + if ((sign= ds < 0)) + ds= -ds; + c[0]= (coord_digit_t) (ds / (double) DIG_BASE); + c[1]= (coord_digit_t) (ds - ((double) c[0]) * DIG_BASE); +#ifdef GCALC_CHECK_WITH_FLOAT + DBUG_ASSERT(de_check(d, get_double())); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return 0; +} + + +void Gcalc_coord1::copy(const Gcalc_coord1 *from) +{ + c[0]= from->c[0]; + c[1]= from->c[1]; + sign= from->sign; +} + +/* Internal coordinates implementation end */ + + +Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y, + gcalc_shape_info shape) +{ + Info *result= (Info *)new_item(); + if (!result) + return NULL; + *m_hook= result; + m_hook= &result->next; + m_n_points++; + result->x= x; + result->y= y; + result->shape= shape; + result->ix.set_double(x); + result->iy.set_double(y); + return result; +} + + +Gcalc_heap::Intersection_info *Gcalc_heap::new_intersection( + const Info *p1, const Info *p2, + const Info *p3, const Info *p4) +{ + Intersection_info *isc= (Intersection_info *)new_item(); + if (!isc) + return 0; + isc->p1= p1; + isc->p2= p2; + isc->p3= p3; + isc->p4= p4; + *m_intersection_hook= isc; + m_intersection_hook= &isc->next; + return isc; +} + + +class Gcalc_coord3 : public Gcalc_internal_coord +{ + coord_digit_t c[COORD_BASE*3]; + public: + void init() + { + n_digits= COORD_BASE*3; + digits= c; + } +}; + + +static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, + Gcalc_coord1 *b1x, + Gcalc_coord1 *b1y, + const Gcalc_heap::Info *p1, + const Gcalc_heap::Info *p2, + const Gcalc_heap::Info *p3, + const Gcalc_heap::Info *p4) +{ + Gcalc_coord1 a2_a1x, a2_a1y; + Gcalc_coord1 b2x, b2y; + Gcalc_coord2 x1y2, x2y1; + + a2_a1x.init(); + a2_a1y.init(); + x1y2.init(); + x2y1.init(); + t_a->init(); + t_b->init(); + b1y->init(); + b1x->init(); + b2x.init(); + b2y.init(); + + gcalc_sub_coord(&a2_a1x, &p3->ix, &p1->ix); + gcalc_sub_coord(&a2_a1y, &p3->iy, &p1->iy); + gcalc_sub_coord(b1x, &p2->ix, &p1->ix); + gcalc_sub_coord(b1y, &p2->iy, &p1->iy); + gcalc_sub_coord(&b2x, &p4->ix, &p3->ix); + gcalc_sub_coord(&b2y, &p4->iy, &p3->iy); + + gcalc_mul_coord(&x1y2, b1x, &b2y); + gcalc_mul_coord(&x2y1, &b2x, b1y); + gcalc_sub_coord(t_b, &x1y2, &x2y1); + + + gcalc_mul_coord(&x1y2, &a2_a1x, &b2y); + gcalc_mul_coord(&x2y1, &a2_a1y, &b2x); + gcalc_sub_coord(t_a, &x1y2, &x2y1); +} + + +inline void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, + Gcalc_coord1 *b1x, + Gcalc_coord1 *b1y, + const Gcalc_heap::Intersection_info *isc) +{ + calc_t(t_a, t_b, b1x, b1y, isc->p1, isc->p2, isc->p3, isc->p4); +} + + +void Gcalc_heap::Intersection_info::calc_xy(double *x, double *y) const +{ + double b0_x= p2->x - p1->x; + double b0_y= p2->y - p1->y; + double b1_x= p4->x - p3->x; + double b1_y= p4->y - p3->y; + double b0xb1= b0_x * b1_y - b0_y * b1_x; + double t= (p3->x - p1->x) * b1_y - (p3->y - p1->y) * b1_x; + + t/= b0xb1; + + *x= p1->x + b0_x * t; + *y= p1->y + b0_y * t; +} + + +#ifdef GCALC_CHECK_WITH_FLOAT +void Gcalc_heap::Intersection_info::calc_xy_ld(long double *x, + long double *y) const +{ + long double b0_x= p2->x - p1->x; + long double b0_y= p2->y - p1->y; + long double b1_x= p4->x - p3->x; + long double b1_y= p4->y - p3->y; + long double b0xb1= b0_x * b1_y - b0_y * b1_x; + long double t= (p3->x - p1->x) * b1_y - (p3->y - p1->y) * b1_x; + long double cx, cy; + + t/= b0xb1; + + cx= (long double) p1->x + b0_x * t; + cy= (long double) p1->y + b0_y * t; + + Gcalc_coord2 t_a, t_b; + Gcalc_coord1 yb, xb; + Gcalc_coord3 m1, m2, sum; + + calc_t(&t_a, &t_b, &xb, &yb, this); + if (t_b.is_zero()) + { + *x= p1->x; + *y= p1->y; + return; + } + + m1.init(); + m2.init(); + sum.init(); + gcalc_mul_coord(&m1, &p1->ix, &t_b); + gcalc_mul_coord(&m2, &xb, &t_a); + gcalc_add_coord(&sum, &m1, &m2); + *x= sum.get_double() / t_b.get_double(); + + gcalc_mul_coord(&m1, &p1->iy, &t_b); + gcalc_mul_coord(&m2, &yb, &t_a); + gcalc_add_coord(&sum, &m1, &m2); + *y= sum.get_double() / t_b.get_double(); +} +#endif /*GCALC_CHECK_WITH_FLOAT*/ + + static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node) { if (!node) @@ -127,13 +571,21 @@ static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node } +static int cmp_point_info(const Gcalc_heap::Info *i0, + const Gcalc_heap::Info *i1) +{ + int cmp_y= gcalc_cmp_coord(&i0->iy, &i1->iy); + if (cmp_y) + return cmp_y; + return gcalc_cmp_coord(&i0->ix, &i1->ix); +} + + static int compare_point_info(const void *e0, const void *e1) { const Gcalc_heap::Info *i0= (const Gcalc_heap::Info *)e0; const Gcalc_heap::Info *i1= (const Gcalc_heap::Info *)e1; - if (!coord_eq(i0->y, i1->y)) - return i0->y > i1->y; - return i0->x > i1->x; + return cmp_point_info(i0, i1) > 0; } @@ -155,6 +607,7 @@ void Gcalc_heap::prepare_operation() void Gcalc_heap::reset() { +#ifdef TMP_BLOCK if (!m_hook) { m_hook= &m_first; @@ -164,10 +617,18 @@ void Gcalc_heap::reset() *m_hook= m_free; m_free= m_first; +#endif /*TMP_BLOCK*/ + if (m_n_points) + { + free_list(m_first); + free_list(m_first_intersection, m_intersection_hook); + m_intersection_hook= (Gcalc_dyn_list::Item **) &m_first_intersection; + m_n_points= 0; + } m_hook= &m_first; - m_n_points= 0; } + int Gcalc_shape_transporter::int_single_point(gcalc_shape_info Info, double x, double y) { @@ -229,6 +690,7 @@ void Gcalc_shape_transporter::int_complete() } +#ifdef TMP_BLOCK inline int GET_DX_DY(double *dxdy, const Gcalc_heap::Info *p0, const Gcalc_heap::Info *p1) { @@ -238,6 +700,13 @@ inline int GET_DX_DY(double *dxdy, (*dxdy/= dy)>DBL_MAX || (*dxdy)<-DBL_MAX; } +#endif /*TMP_BLOCK*/ +inline void calc_dx_dy(Gcalc_scan_iterator::point *p) +{ + gcalc_sub_coord(&p->dx, &p->next_pi->ix, &p->pi->ix); + gcalc_sub_coord(&p->dy, &p->next_pi->iy, &p->pi->iy); +} + Gcalc_scan_iterator::Gcalc_scan_iterator(size_t blk_size) : Gcalc_dyn_list(blk_size, @@ -268,14 +737,20 @@ void Gcalc_scan_iterator::init(Gcalc_heap *points) if (!(m_cur_pi= points->get_first())) return; + m_heap= points; m_cur_thread= 0; m_intersections= NULL; + m_cur_intersection= NULL; m_next_is_top_point= true; m_events= NULL; current_state= &state0; next_state= &state1; saved_state= &state_s; +#ifdef TMP_BLOCK next_state->y= m_cur_pi->y; +#endif /*TMP_BLOCK*/ + next_state->intersection_scan= 0; + next_state->pi= m_cur_pi; } void Gcalc_scan_iterator::reset() @@ -286,21 +761,36 @@ void Gcalc_scan_iterator::reset() } -void Gcalc_scan_iterator::point::copy_core(point *from) +void Gcalc_scan_iterator::point::copy_core(const point *from) { +#ifdef TMP_BLOCK dx_dy= from->dx_dy; horiz_dir= from->horiz_dir; +#endif /*TMP_BLOCK*/ pi= from->pi; next_pi= from->next_pi; thread= from->thread; + dx.copy(&from->dx); + dy.copy(&from->dy); #ifdef TO_REMOVE from->next_link= this; #endif /*TO_REMOVE*/ } -int Gcalc_scan_iterator::point::compare_dx_dy(int horiz_dir_a, double dx_dy_a, - int horiz_dir_b, double dx_dy_b) +void Gcalc_scan_iterator::point::copy_all(const point *from) +{ + pi= from->pi; + next_pi= from->next_pi; + thread= from->thread; + dx.copy(&from->dx); + dy.copy(&from->dy); + intersection_link= from->intersection_link; + event= from->event; +} +#ifdef TMP_BLOCK +int Gcalc_scan_iterator::point::cmp_dx_dy(int horiz_dir_a, double dx_dy_a, + int horiz_dir_b, double dx_dy_b) { if (!horiz_dir_a && !horiz_dir_b) { @@ -323,7 +813,169 @@ int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const return p->is_bottom() ? 0 : -1; if (p->is_bottom()) return 1; - return compare_dx_dy(horiz_dir, dx_dy, p->horiz_dir, p->dx_dy); + return cmp_dx_dy(horiz_dir, dx_dy, p->horiz_dir, p->dx_dy); +} +#endif /*TMP_BLOCK*/ +int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_coord1 *dx_a, + const Gcalc_coord1 *dy_a, + const Gcalc_coord1 *dx_b, + const Gcalc_coord1 *dy_b) +{ + Gcalc_coord2 dx_a_dy_b; + Gcalc_coord2 dy_a_dx_b; + dx_a_dy_b.init(); + dy_a_dx_b.init(); + gcalc_mul_coord(&dx_a_dy_b, dx_a, dy_b); + gcalc_mul_coord(&dy_a_dx_b, dy_a, dx_b); + + return gcalc_cmp_coord(&dx_a_dy_b, &dy_a_dx_b); +} + + +int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_heap::Info *p1, + const Gcalc_heap::Info *p2, + const Gcalc_heap::Info *p3, + const Gcalc_heap::Info *p4) +{ + Gcalc_coord1 dx_a, dy_a, dx_b, dy_b; + dx_a.init(); + dx_b.init(); + dy_a.init(); + dy_b.init(); + gcalc_sub_coord(&dx_a, &p2->ix, &p1->ix); + gcalc_sub_coord(&dy_a, &p2->iy, &p1->iy); + gcalc_sub_coord(&dx_b, &p4->ix, &p3->ix); + gcalc_sub_coord(&dy_b, &p4->iy, &p3->iy); + return cmp_dx_dy(&dx_a, &dy_a, &dx_b, &dy_b); +} + + +int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const +{ + if (is_bottom()) + return p->is_bottom() ? 0 : -1; + if (p->is_bottom()) + return 1; + return cmp_dx_dy(&dx, &dy, &p->dx, &p->dy); +} + + +#ifdef GCALC_CHECK_WITH_FLOAT +void Gcalc_scan_iterator::point::calc_x(long double *x, long double y, + long double ix) const +{ + if (fabsl(dy.get_double()) < (long double) 1e-15) + { + *x= ix; + } + else + *x= (long double) pi->x + dx.get_double()/dy.get_double() * (y - pi->y); +} +#endif /*GCALC_CHECK_WITH_FLOAT*/ + + +static int cmp_sp_pi(const Gcalc_scan_iterator::point *sp, + const Gcalc_heap::Info *pi) +{ + Gcalc_coord1 dx_pi, dy_pi; + Gcalc_coord2 dx_sp_dy_pi, dy_sp_dx_pi; + + if (!sp->next_pi) + return cmp_point_info(sp->pi, pi); + + dx_pi.init(); + dy_pi.init(); + dx_sp_dy_pi.init(); + dy_sp_dx_pi.init(); + + + gcalc_sub_coord(&dx_pi, &pi->ix, &sp->pi->ix); + gcalc_sub_coord(&dy_pi, &pi->iy, &sp->pi->iy); + gcalc_mul_coord(&dx_sp_dy_pi, &sp->dx, &dy_pi); + gcalc_mul_coord(&dy_sp_dx_pi, &sp->dy, &dx_pi); + + int result= gcalc_cmp_coord(&dx_sp_dy_pi, &dy_sp_dx_pi); +#ifdef GCALC_CHECK_WITH_FLOAT + long double sp_x; + sp->calc_x(&sp_x, pi->y, pi->x); + if (result == 0) + DBUG_ASSERT(de_check1(sp->dy.get_double(), 0.0) || + de_check(sp_x, pi->x)); + if (result < 0) + DBUG_ASSERT(de_check1(sp->dy.get_double(), 0.0) || + de_check1(sp_x, pi->x) || + sp_x < pi->x); + if (result > 0) + DBUG_ASSERT(de_check1(sp->dy.get_double(), 0.0) || + de_check1(sp_x, pi->x) || + sp_x > pi->x); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result; +} + + +static void calc_cmp_sp_sp_exp(Gcalc_coord3 *result, + const Gcalc_scan_iterator::point *a, + const Gcalc_scan_iterator::point *b, + const Gcalc_coord1 *ly) +{ + Gcalc_coord2 x_dy, dx_ly, sum; + + x_dy.init(); + dx_ly.init(); + sum.init(); + result->init(); + + gcalc_mul_coord(&x_dy, &a->pi->ix, &a->dy); + gcalc_mul_coord(&dx_ly, &a->dx, ly); + gcalc_add_coord(&sum, &x_dy, &dx_ly); + gcalc_mul_coord(result, &sum, &b->dy); +} + + +static int cmp_sp_sp_cnt(const Gcalc_scan_iterator::point *a, + const Gcalc_scan_iterator::point *b, + const Gcalc_coord1 *y) +{ + Gcalc_coord1 lya, lyb; + Gcalc_coord3 a_exp, b_exp; + + lya.init(); + lyb.init(); + gcalc_sub_coord(&lya, y, &a->pi->iy); + gcalc_sub_coord(&lyb, y, &b->pi->iy); + + calc_cmp_sp_sp_exp(&a_exp, a, b, &lya); + calc_cmp_sp_sp_exp(&b_exp, b, a, &lyb); + + int result= gcalc_cmp_coord(&a_exp, &b_exp); +#ifdef GCALC_CHECK_WITH_FLOAT + long double a_x, b_x; + a->calc_x(&a_x, y->get_double(), 0); + b->calc_x(&b_x, y->get_double(), 0); + if (result == 0) + DBUG_ASSERT(de_check(a_x, b_x)); + if (result < 0) + DBUG_ASSERT(de_check1(a_x, b_x) || a_x < b_x); + if (result > 0) + DBUG_ASSERT(de_check1(a_x, b_x) || a_x > b_x); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result; +} + + +static int cmp_sp_sp(const Gcalc_scan_iterator::point *a, + const Gcalc_scan_iterator::point *b, + const Gcalc_heap::Info *pi) +{ + if (a->event == scev_none && b->event == scev_none) + return cmp_sp_sp_cnt(a, b, &pi->iy); + if (a->event == scev_none) + return cmp_sp_pi(a, pi); + if (b->event == scev_none) + return -1 * cmp_sp_pi(b, pi); + + return 0; } @@ -366,7 +1018,7 @@ int Gcalc_scan_iterator::arrange_event() continue; if (!(new_sp= new_slice_point())) return 1; - *new_sp= *sp; + new_sp->copy_all(sp); *ae_hook= new_sp; ae_hook= &new_sp->next; #ifdef TO_REMOVE @@ -420,10 +1072,12 @@ int Gcalc_scan_iterator::insert_top_point() sp0->pi= m_cur_pi; sp0->next_pi= m_cur_pi->left; sp0->thread= m_cur_thread++; +#ifdef TMP_BLOCK sp0->x= coord_to_float(m_cur_pi->x); +#endif /*TMP_BLOCK*/ if (m_cur_pi->left) { - sp0->horiz_dir= GET_DX_DY(&sp0->dx_dy, m_cur_pi, m_cur_pi->left); + calc_dx_dy(sp0); sp0->event= scev_thread; /*Now just to increase the size of m_slice0 to be same*/ @@ -436,15 +1090,13 @@ int Gcalc_scan_iterator::insert_top_point() if (!(sp1= new_slice_point())) return 1; sp1->event= sp0->event= scev_two_threads; -#ifdef TO_REMOVE - sp1->event_pair= sp0; - sp0->event_pair= sp1; -#endif /*TO_REMOVE*/ sp1->pi= m_cur_pi; sp1->next_pi= m_cur_pi->right; sp1->thread= m_cur_thread++; +#ifdef TMP_BLOCK sp1->x= sp0->x; - sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->right); +#endif /*TMP_BLOCK*/ + calc_dx_dy(sp1); /* We have two threads so should decide which one will be first */ if (sp0->cmp_dx_dy(sp1)>0) { @@ -463,17 +1115,20 @@ int Gcalc_scan_iterator::insert_top_point() else { sp0->event= scev_single_point; +#ifdef TMP_BLOCK sp0->horiz_dir= 0; sp0->dx_dy= 0.0; +#endif /*TMP_BLOCK*/ } /* We need to find the place to insert. */ - for (; sp && (sp->x < sp0->x); prev_hook= &sp->next, sp=sp->get_next()) + for (; sp && cmp_sp_pi(sp, m_cur_pi) < 0; + prev_hook= &sp->next, sp=sp->get_next()) {} next_state->event_position_hook= prev_hook; - if (sp && coord_eq(sp->x, sp0->x)) + if (sp && cmp_sp_pi(sp, m_cur_pi) == 0) { next_state->event_position= sp; do @@ -482,7 +1137,7 @@ int Gcalc_scan_iterator::insert_top_point() sp->event= scev_intersection; prev_hook= &sp->next; sp= sp->get_next(); - } while (sp && coord_eq(sp->x, sp0->x)); + } while (sp && cmp_sp_pi(sp, m_cur_pi) == 0); } else next_state->event_position= sp0; @@ -503,44 +1158,88 @@ int Gcalc_scan_iterator::insert_top_point() } +#ifndef NO_TESTING +const char *pev(int ev) +{ + switch (ev) + { + case scev_none: + return "n"; + case scev_thread: + return "t"; + case scev_two_threads: + return "tt"; + case scev_end: + return "e"; + case scev_two_ends: + return "ee"; + case scev_intersection: + return "i"; + case scev_point: + return "p"; + case scev_single_point: + return "sp"; + }; + return "fck"; +} +extern int ca_counter; +#endif /*NO_TESTING*/ int Gcalc_scan_iterator::normal_scan() { point *sp; Gcalc_dyn_list::Item **sp_hook; Gcalc_heap::Info *next_pi; - point *first_bottom_point= NULL; + point *first_bottom_point; if (m_next_is_top_point && insert_top_point()) return 1; for (next_pi= m_cur_pi->get_next(); - next_pi && - coord_eq(m_cur_pi->x, next_pi->x) && - coord_eq(m_cur_pi->y, next_pi->y); + next_pi && cmp_point_info(m_cur_pi, next_pi) == 0; next_pi= next_pi->get_next()) { - DBUG_ASSERT(coord_eq(next_state->event_position->x, next_pi->x)); next_state->clear_event_position(); m_next_is_top_point= true; + first_bottom_point= NULL; for (sp= next_state->slice, sp_hook= (Gcalc_dyn_list::Item **) &next_state->slice; sp; sp_hook= &sp->next, sp= sp->get_next()) { +#ifndef NO_TESTING + // if (ca_counter == 21) + printf("%s%d\t", pev(sp->event), sp->thread); +#endif /*NO_TESTING*/ if (sp->next_pi == next_pi) /* End of the segment */ { +#ifdef TMP_BLOCK sp->x= coord_to_float(next_pi->x); sp->pi= next_pi; +#endif /*TMP_BLOCK*/ + if (cmp_point_info(sp->pi, next_pi)) + sp->pi= next_pi; sp->next_pi= next_pi->left; m_next_is_top_point= false; if (next_pi->is_bottom()) { - if (first_bottom_point) + if (sp->event == scev_thread) + sp->event= scev_single_point; + else if (sp->event == scev_two_threads) + { + if (sp->get_next() && sp->get_next()->pi == sp->pi) + sp->get_next()->event= scev_thread; + else if (sp != next_state->slice) + { + point *fnd_sp; + for (fnd_sp= next_state->slice; fnd_sp->get_next() != sp; + fnd_sp= fnd_sp->get_next()); + DBUG_ASSERT(fnd_sp->pi == sp->pi); + fnd_sp->event= scev_thread; + } + sp->event= scev_single_point; + } + else if (first_bottom_point) { first_bottom_point->event= sp->event= scev_two_ends; -#ifdef TO_REMOVE - first_bottom_point->event_pair= sp; - sp->event_pair= first_bottom_point; -#endif /*TO_REMOVE*/ } else { @@ -550,21 +1249,52 @@ int Gcalc_scan_iterator::normal_scan() } else { - sp->event= scev_point; - sp->horiz_dir= GET_DX_DY(&sp->dx_dy, next_pi, next_pi->left); + if ((sp->event & (scev_point | scev_thread | scev_two_threads)) == 0) + sp->event= scev_point; + calc_dx_dy(sp); } mark_event_position1(sp, sp_hook); } - else if (coord_eq(sp->x, next_pi->x)) + else if (sp->event || (cmp_sp_pi(sp, next_pi) == 0)) { if (!sp->event) sp->event= scev_intersection; mark_event_position1(sp, sp_hook); } } +#ifndef NO_TESTING + //if (ca_counter == 21) + printf("\n"); +#endif /*NO_TESTING*/ m_cur_pi= next_pi; - if (m_next_is_top_point && insert_top_point()) - return 1; + if (m_next_is_top_point) + { + if (insert_top_point()) + return 1; + /* Set proper values to the event position */ + /* TODO: can be done faster */ + next_state->clear_event_position(); + if (next_state->slice->event) + mark_event_position1(next_state->slice, + (Gcalc_dyn_list::Item **) &next_state->slice); +#ifndef NO_TESTING + //if (ca_counter == 21) + printf("*%s%d\t", pev(next_state->slice->event), next_state->slice->thread); +#endif /*NO_TESTING*/ + for (sp= next_state->slice; sp->get_next(); sp= sp->get_next()) + { +#ifndef NO_TESTING + //if (ca_counter == 21) + printf("%s%d\t", pev(sp->get_next()->event), sp->get_next()->thread); +#endif /*NO_TESTING*/ + if (sp->get_next()->event) + mark_event_position1(sp->get_next(), &sp->next); + } +#ifndef NO_TESTING + //if (ca_counter == 21) + printf("\n"); +#endif /*NO_TESTING*/ + } } /* Swap current <-> next */ @@ -580,6 +1310,19 @@ int Gcalc_scan_iterator::normal_scan() point *sp0= current_state->slice; point *sp1= next_state->slice; point *prev_sp1= NULL; +#ifndef NO_TESTING + //if (ca_counter == 21) + { + point *sp= current_state->slice; + printf("After arrange\n"); + for (; sp; sp= sp->get_next()) + printf("%s%d\t", pev(sp->event), sp->thread); + printf("\nEvent\n"); + for (sp= m_events; sp; sp= sp->get_next()) + printf("%s%d\t", pev(sp->event), sp->thread); + printf("\n"); + } +#endif /*NO_TESTING*/ if (!(m_cur_pi= next_pi)) { @@ -592,8 +1335,12 @@ int Gcalc_scan_iterator::normal_scan() return 0; } + next_state->intersection_scan= 0; + next_state->pi= m_cur_pi; Gcalc_heap::Info *cur_pi= m_cur_pi; +#ifdef TMP_BLOCK next_state->y= coord_to_float(cur_pi->y); +#endif /*TMP_BLOCK*/ first_bottom_point= NULL; @@ -603,9 +1350,12 @@ int Gcalc_scan_iterator::normal_scan() for (; sp0; sp0= sp0->get_next()) { + DBUG_ASSERT(!sp0->is_bottom()); if (sp0->next_pi == cur_pi) /* End of the segment */ { +#ifdef TMP_BLOCK sp1->x= coord_to_float(cur_pi->x); +#endif /*TMP_BLOCK*/ sp1->pi= cur_pi; sp1->thread= sp0->thread; sp1->next_pi= cur_pi->left; @@ -625,16 +1375,12 @@ int Gcalc_scan_iterator::normal_scan() else { first_bottom_point->event= sp1->event= scev_two_ends; -#ifdef TO_REMOVE - sp1->event_pair= first_bottom_point; - first_bottom_point->event_pair= sp1; -#endif /*TO_REMOVE*/ } } else { sp1->event= scev_point; - sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->left); + calc_dx_dy(sp1); } mark_event_position1(sp1, prev_sp1 ? &prev_sp1->next : @@ -644,10 +1390,12 @@ int Gcalc_scan_iterator::normal_scan() { /* Cut current string with the height of the new point*/ sp1->copy_core(sp0); +#ifdef TMP_BLOCK sp1->x= sp1->horiz_dir ? coord_to_float(cur_pi->x) : (coord_to_float(sp1->pi->x) + (next_state->y-coord_to_float(sp1->pi->y)) * sp1->dx_dy); - if (coord_eq(sp1->x, cur_pi->x)) +#endif /*TMP_BLOCK*/ + if (cmp_sp_pi(sp1, cur_pi) == 0) { mark_event_position1(sp1, prev_sp1 ? &prev_sp1->next : @@ -659,7 +1407,7 @@ int Gcalc_scan_iterator::normal_scan() } intersections_found= intersections_found || - (prev_sp1 && prev_sp1->x > sp1->x); + (prev_sp1 && cmp_sp_sp(prev_sp1, sp1, cur_pi) > 0); prev_sp1= sp1; sp1= sp1->get_next(); @@ -674,6 +1422,16 @@ int Gcalc_scan_iterator::normal_scan() free_list(sp1); } +#ifndef NO_TESTING + //if (ca_counter == 21) + { + point *sp= next_state->slice; + printf("After slice\n"); + for (; sp; sp= sp->get_next()) + printf("%s%d\t", pev(sp->event), sp->thread); + printf("\n"); + } +#endif /*NO_TESTING*/ if (intersections_found) return handle_intersections(); @@ -681,16 +1439,20 @@ int Gcalc_scan_iterator::normal_scan() } -#define INTERSECTION_ZERO 0.000000000001 - +#ifndef NO_TESTING +int isc_counter= 0; +#endif /*NO_TESTING*/ int Gcalc_scan_iterator::add_intersection(int n_row, const point *a, const point *b, Gcalc_dyn_list::Item ***p_hook) { + const point *a0= a->intersection_link; + const point *b0= b->intersection_link; intersection *isc= new_intersection(); if (!isc) return 1; + m_n_intersections++; **p_hook= isc; *p_hook= &isc->next; @@ -698,34 +1460,17 @@ int Gcalc_scan_iterator::add_intersection(int n_row, isc->thread_a= a->thread; isc->thread_b= b->thread; - /* intersection_normal */ - const point *a0= a->intersection_link; - const point *b0= b->intersection_link; - DBUG_ASSERT(!a0->horiz_dir || !b0->horiz_dir); - - if (!a0->horiz_dir && !b0->horiz_dir) + isc->ii= m_heap->new_intersection(a0->pi, a0->next_pi, + b0->pi, b0->next_pi); +#ifndef NO_TESTING + //if (isc_counter == 40) { - double b0_x= a0->next_pi->x - a0->pi->x; - double b0_y= a0->next_pi->y - a0->pi->y; - double b1_x= b0->next_pi->x - b0->pi->x; - double b1_y= b0->next_pi->y - b0->pi->y; - double b1xb0= b1_x * b0_y - b1_y * b0_x; - double t= (a0->pi->x - b0->pi->x) * b0_y - (a0->pi->y - b0->pi->y) * b0_x; - if (fabs(b1xb0) < INTERSECTION_ZERO) - { - isc->y= current_state->y; - isc->x= a0->x; - return 0; - } - - t/= b1xb0; - isc->x= b0->pi->x + b1_x*t; - isc->y= b0->pi->y + b1_y*t; - return 0; + long double ix, iy; + isc->ii->calc_xy_ld(&ix, &iy); + printf("%d\t%d\t%.20LG\t%.20LG\t%d\n", isc->thread_a, isc->thread_b, ix, iy, isc->n_row); } - isc->y= next_state->y; - isc->x= a0->horiz_dir ? b->x : a->x; - return 0; +#endif /*NO_TESTING*/ + return isc->ii == NULL; } @@ -733,6 +1478,10 @@ int Gcalc_scan_iterator::find_intersections() { Gcalc_dyn_list::Item **hook; +#ifndef NO_TESTING + ++isc_counter; + printf("Looking for intersections\n"); +#endif /*NO_TESTING*/ m_n_intersections= 0; { /* Set links between slicepoints */ @@ -743,6 +1492,15 @@ int Gcalc_scan_iterator::find_intersections() DBUG_ASSERT(!sp0->is_bottom()); DBUG_ASSERT(sp0->thread == sp1->thread); sp1->intersection_link= sp0; +#ifndef NO_TESTING + //if (isc_counter == 40) + { + long double spx, spx1; + sp0->calc_x(&spx, current_state->pi->y, current_state->pi->x); + sp1->calc_x(&spx1, m_cur_pi->y, m_cur_pi->x); + printf("%d\t%.20LG\t%.20LG\n", sp0->thread, spx, spx1); + } +#endif /*NO_TESTING*/ } } @@ -761,7 +1519,7 @@ int Gcalc_scan_iterator::find_intersections() point *s1= prev_s1->get_next(); if (!s1) break; - if (prev_s1->x <= s1->x) + if (cmp_sp_sp(prev_s1, s1, m_cur_pi) <= 0) { pprev_s1= (point **) &prev_s1->next; continue; @@ -783,19 +1541,250 @@ int Gcalc_scan_iterator::find_intersections() } -static int compare_intersections(const void *e0, const void *e1) +class Gcalc_coord4 : public Gcalc_internal_coord +{ + coord_digit_t c[COORD_BASE*4]; + public: + void init() + { + n_digits= COORD_BASE*4; + digits= c; + } +}; + +class Gcalc_coord5 : public Gcalc_internal_coord +{ + coord_digit_t c[COORD_BASE*5]; + public: + void init() + { + n_digits= COORD_BASE*5; + digits= c; + } +}; + + +static void calc_isc_exp(Gcalc_coord5 *exp, + const Gcalc_coord2 *bb2, + const Gcalc_coord1 *ya1, + const Gcalc_coord2 *bb1, + const Gcalc_coord1 *yb1, + const Gcalc_coord2 *a21_b1) +{ + Gcalc_coord3 p1, p2, sum; + p1.init(); + p2.init(); + sum.init(); + exp->init(); + + gcalc_mul_coord(&p1, ya1, bb1); + gcalc_mul_coord(&p2, yb1, a21_b1); + gcalc_add_coord(&sum, &p1, &p2); + gcalc_mul_coord(exp, bb2, &sum); +} + + +#ifdef TMP_BLOCK +static void calc_aa1_b(Gcalc_coord2 *res, + const Gcalc_heap::Info *a0, + const Gcalc_heap::Info *a1, + const Gcalc_coord1 *xb, + const Gcalc_coord1 *yb) +{ + Gcalc_coord1 aa1_x, aa1_y; + Gcalc_coord2 p1, p2; + res->init(); + aa1_x.init(); + aa1_y.init(); + p1.init(); + p2.init(); + + gcalc_sub_coord(&aa1_x, &a1->ix, &a0->ix); + gcalc_sub_coord(&aa1_y, &a1->iy, &a0->iy); + gcalc_mul_coord(&p1, &aa1_x, yb); + gcalc_mul_coord(&p2, &aa1_y, xb); + gcalc_sub_coord(res, &p1, &p2); +} + + +static int cmp_intersections_y(const Gcalc_heap::Intersection_info *i1, + const Gcalc_heap::Intersection_info *i2) +{ + Gcalc_coord2 t_a1, t_b1; + Gcalc_coord2 t_a2, t_b2; + Gcalc_coord1 yb1, yb2; + Gcalc_coord1 xb1, xb2; + Gcalc_coord5 exp_a, exp_b; + + calc_t(&t_a1, &t_b1, &xb1, &yb1, i1); + calc_t(&t_a2, &t_b2, &xb2, &yb2, i2); + + calc_isc_exp(&exp_a, &t_b2, &i1->p1->iy, &t_b1, &yb1, &t_a1); + calc_isc_exp(&exp_b, &t_b1, &i2->p1->iy, &t_b2, &yb2, &t_a2); + + int result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + long double x1, y1, x2,y2; + i1->calc_xy_ld(&x1, &y1); + i2->calc_xy_ld(&x2, &y2); + + if (result == 0) + DBUG_ASSERT(de_check(y1, y2)); + if (result < 0) + DBUG_ASSERT(de_check1(y1, y2) || y1 < y2); + if (result > 0) + DBUG_ASSERT(de_check1(y1, y2) || y1 > y2); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result; +} + + +static int compare_intersections(const void *e1, const void *e2) { - Gcalc_scan_iterator::intersection *i0= (Gcalc_scan_iterator::intersection *)e0; Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1; + Gcalc_scan_iterator::intersection *i2= (Gcalc_scan_iterator::intersection *)e2; + int result= cmp_intersections_y(i1->ii, i2->ii); + if (result != 0) + return result > 0; + return (i1->n_row > i2->n_row); +} - if (fabs(i0->y - i1->y) > 0.00000000000001) - return i0->y > i1->y; +#endif /*TMP_BLOCK*/ - if (i0->n_row != i1->n_row) - return i0->n_row > i1->n_row; - if (!coord_eq(i0->y, i1->y)) - return i0->y > i1->y; - return i0->x > i1->x; +#ifndef NO_TESTING +extern int ca_counter; +#endif /*NO_TESTING*/ +static int cmp_intersections(const Gcalc_heap::Intersection_info *i1, + const Gcalc_heap::Intersection_info *i2) +{ + Gcalc_coord2 t_a1, t_b1; + Gcalc_coord2 t_a2, t_b2; + Gcalc_coord1 yb1, yb2; + Gcalc_coord1 xb1, xb2; + Gcalc_coord5 exp_a, exp_b; + int result; + + calc_t(&t_a1, &t_b1, &xb1, &yb1, i1); + calc_t(&t_a2, &t_b2, &xb2, &yb2, i2); + + calc_isc_exp(&exp_a, &t_b2, &i1->p1->iy, &t_b1, &yb1, &t_a1); + calc_isc_exp(&exp_b, &t_b1, &i2->p1->iy, &t_b2, &yb2, &t_a2); + + result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + long double x1, y1, x2, y2; + i1->calc_xy_ld(&x1, &y1); + i2->calc_xy_ld(&x2, &y2); + + if (result == 0) + DBUG_ASSERT(de_weak(y1, y2)); +#ifndef NO_TESTING + if (ca_counter == 7) + printf("77"); +#endif /*NO_TESTING*/ + if (result < 0) + DBUG_ASSERT(de_weak(y1, y2) || y1 < y2); + if (result > 0) + DBUG_ASSERT(de_weak(y1, y2) || y1 > y2); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + + if (result != 0) + return result; + + + calc_isc_exp(&exp_a, &t_b2, &i1->p1->ix, &t_b1, &xb1, &t_a1); + calc_isc_exp(&exp_b, &t_b1, &i2->p1->ix, &t_b2, &xb2, &t_a2); + result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + if (result == 0) + DBUG_ASSERT(de_weak(x1, x2)); + if (result < 0) + DBUG_ASSERT(de_weak(x1, x2) || x1 < x2); + if (result > 0) + DBUG_ASSERT(de_weak(x1, x2) || x1 > x2); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result; +} + +static int compare_intersections(const void *e1, const void *e2) +{ + Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1; + Gcalc_scan_iterator::intersection *i2= (Gcalc_scan_iterator::intersection *)e2; + int result= cmp_intersections(i1->ii, i2->ii); + if (result != 0) + return result > 0; + return (i1->n_row > i2->n_row); +} + +inline int intersections_eq(const Gcalc_heap::Intersection_info *i1, + const Gcalc_heap::Intersection_info *i2) +{ + return cmp_intersections(i1, i2) == 0; +} + + +#ifdef TMP_BLOCK +static void calc_isc_sp_exp(Gcalc_coord4 *exp, + const Gcalc_coord2 *bb, + const Gcalc_coord1 *x1, + const Gcalc_coord1 *y1, + const Gcalc_coord1 *x2, + const Gcalc_coord1 *y2) +{ + Gcalc_coord2 p1, p2, sum; + p1.init(); + p2.init(); + sum.init(); + exp->init(); + + gcalc_mul_coord(&p1, x1, y1); + gcalc_mul_coord(&p2, x2, y2); + gcalc_add_coord(&sum, &p1, &p2); + gcalc_mul_coord(exp, bb, &sum); +} +#endif /*TMP_BLOCK*/ + + +static int sp_isc_eq(const Gcalc_scan_iterator::point *sp, + const Gcalc_heap::Intersection_info *isc) +{ + + Gcalc_coord4 exp_a, exp_b; + Gcalc_coord1 xb1, yb1; + Gcalc_coord2 t_a, t_b; + Gcalc_coord2 t_sp_a, t_sp_b; +#ifdef TMP_BLOCK + xa1a0.init(); + ya1a0.init(); + + gcalc_sub_coord(&xa1a0, &isc->p1->ix, &sp->pi->ix); + gcalc_sub_coord(&ya1a0, &isc->p1->iy, &sp->pi->iy); + calc_isc_sp_exp(&exp_a, &t_b, &sp->pi->ix, &ya1a0, &sp->pi->iy, &xa1a0); + calc_isc_sp_exp(&exp_b, &t_a, &sp->pi->iy, &isc->p1->ix, + &sp->pi->ix, &isc->p1->iy); + return gcalc_cmp_coord(&exp_a, &exp_b); +#endif /*TMP_BLOCK*/ + exp_a.init(); + exp_b.init(); + calc_t(&t_a, &t_b, &xb1, &yb1, isc); + calc_t(&t_sp_a, &t_sp_b, &xb1, &yb1, isc->p1, isc->p2, sp->pi, sp->next_pi); + + gcalc_mul_coord(&exp_a, &t_a, &t_sp_b); + gcalc_mul_coord(&exp_b, &t_b, &t_sp_a); + int result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + long double int_x, int_y, sp_x; + isc->calc_xy_ld(&int_x, &int_y); + sp->calc_x(&sp_x, int_y, int_x); + if (result == 0) + DBUG_ASSERT(de_check1(sp->dy.get_double(), 0.0) || + de_check(sp_x, int_x)); +#ifdef TMP_BLOCK + else + DBUG_ASSERT(!de_check1(sp_x, int_x)); +#endif /*TMP_BLOCK*/ +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result == 0; } @@ -823,6 +1812,18 @@ int Gcalc_scan_iterator::handle_intersections() /* We need the next slice to be just equal */ next_state->slice= new_slice(saved_state->slice); m_cur_intersection= m_intersections; +#ifndef NO_TESTING + //if (isc_counter == 40) + { + printf("Sorted\n"); + for (intersection *isc= m_intersections; isc; isc= isc->get_next()) + { + long double ix, iy; + isc->ii->calc_xy_ld(&ix, &iy); + printf("%d\t%d\t%.20LG\t%.20LG\t%d\n", isc->thread_a, isc->thread_b, ix, iy, isc->n_row); + } + } +#endif /*NO_TESTING*/ return intersection_scan(); } @@ -832,7 +1833,6 @@ int Gcalc_scan_iterator::intersection_scan() point *sp0, *sp1; Gcalc_dyn_list::Item **hook; intersection *next_intersection= NULL; - int met_equal= 0; if (m_cur_intersection != m_intersections) { @@ -846,20 +1846,12 @@ int Gcalc_scan_iterator::intersection_scan() if (arrange_event()) return 1; +#ifdef TMP_BLOCK if (!m_cur_intersection) { saved_state->event_position_hook= (Gcalc_dyn_list::Item **) &saved_state->slice; -#ifdef TO_REMOVE - for (sp0= current_state->slice, sp1= saved_state->slice; - sp0; - sp0= sp0->get_next(), sp1= sp1->get_next()) - { - sp0->next_link= sp1; - if (sp1->get_next() == saved_state->event_position) - saved_state->event_position_hook= &sp1->next; - } -#endif /*TO_REMOVE*/ + for (sp1= saved_state->slice; sp1; sp1= sp1->get_next()) { if (sp1->get_next() == saved_state->event_position) @@ -878,14 +1870,63 @@ int Gcalc_scan_iterator::intersection_scan() m_intersections= NULL; return 0; } - } +#endif /*TMP_BLOCK*/ + if (!m_cur_intersection) + { + /* Swap saved <-> next */ + { + slice_state *tmp= next_state; + next_state= saved_state; + saved_state= tmp; + } + Gcalc_dyn_list::Item **n_hook= + (Gcalc_dyn_list::Item **) &next_state->slice; - next_state->y= m_cur_intersection->y; + next_state->clear_event_position(); + sp0= current_state->slice; + sp1= next_state->slice; + + for (; sp0; + sp0= sp0->get_next(), n_hook= &sp1->next, sp1= sp1->get_next()) + { + if (sp0->thread != sp1->thread) + { + point *fnd_s= sp1->get_next(); + Gcalc_dyn_list::Item **fnd_hook= &sp1->next; + for (; fnd_s && fnd_s->thread != sp0->thread; + fnd_hook= &fnd_s->next, fnd_s= fnd_s->get_next()); + DBUG_ASSERT(fnd_s && fnd_s == *fnd_hook); + /* Now swap items of the next_state->slice */ + *n_hook= fnd_s; + *fnd_hook= fnd_s->next; + fnd_s->next= sp1; + sp1= fnd_s; + } + if (sp1->event) + mark_event_position1(sp1, n_hook); + } +#ifndef DBUG_OFF + sp0= current_state->slice; + sp1= next_state->slice; + for (; sp0; sp0= sp0->get_next(), sp1= sp1->get_next()) + DBUG_ASSERT(sp0->thread == sp1->thread); + DBUG_ASSERT(!sp1); +#endif /*DBUG_OFF*/ + free_list(saved_state->slice); + saved_state->slice= NULL; + + free_list(m_intersections); + m_intersections= NULL; + return 0; + } + } sp0= current_state->slice; hook= (Gcalc_dyn_list::Item **) &next_state->slice; sp1= next_state->slice; next_state->clear_event_position(); + next_state->intersection_scan= 1; + next_state->isc= m_cur_intersection->ii; for (; sp0; hook= &sp1->next, sp1= sp1->get_next(), sp0= sp0->get_next()) @@ -893,27 +1934,20 @@ int Gcalc_scan_iterator::intersection_scan() if (sp0->thread == m_cur_intersection->thread_a || sp0->thread == m_cur_intersection->thread_b) { -#ifdef REACTIVATE_THIS DBUG_ASSERT(sp0->thread != m_cur_intersection->thread_a || - sp0->get_next()->thread == m_cur_intersection->thread_b); -#endif /*REACTIVATE_THIS*/ + sp0->get_next()->thread == m_cur_intersection->thread_b || + sp_isc_eq(sp0->get_next(), m_cur_intersection->ii)); sp1->copy_core(sp0); - sp1->x= m_cur_intersection->x; sp1->event= scev_intersection; mark_event_position1(sp1, hook); } else { sp1->copy_core(sp0); - sp1->x= sp1->horiz_dir ? - m_cur_intersection->x : - coord_to_float(sp1->pi->x) + - (next_state->y-coord_to_float(sp1->pi->y)) * sp1->dx_dy; - if (coord_eq(sp1->x, m_cur_intersection->x)) + if (sp_isc_eq(sp1, m_cur_intersection->ii)) { sp1->event= scev_intersection; mark_event_position1(sp1, hook); - met_equal= 1; } else sp1->event= scev_none; @@ -926,45 +1960,10 @@ int Gcalc_scan_iterator::intersection_scan() *hook= NULL; } - if (met_equal) - { - /* Remove superfluous intersections. */ - /* Double operations can produce unexact result, so it's needed. */ - for (sp0= next_state->event_position; - sp0 != *next_state->event_end_hook; - sp0= sp0->get_next()) - { - for (sp1= sp0->get_next(); - sp1 != *next_state->event_end_hook; - sp1= sp1->get_next()) - { - intersection *isc= m_cur_intersection; - while (isc->get_next()) - { - intersection *cur_isc= isc->get_next(); - if ((cur_isc->thread_a == sp0->thread && - cur_isc->thread_b == sp1->thread) || - (cur_isc->thread_a == sp1->thread && - cur_isc->thread_b == sp0->thread)) - { - /* The superfluous intersection should be close to the current. */ - DBUG_ASSERT(fabs(cur_isc->x-m_cur_intersection->x) + - fabs(cur_isc->y-m_cur_intersection->y) < - 0.00000000001); - isc->next= isc->next->next; - free_item(cur_isc); - } - else - isc= isc->get_next(); - } - } - } - } - + /* Now check equal intersections */ for (next_intersection= m_cur_intersection->get_next(); next_intersection && - coord_eq(next_intersection->x, m_cur_intersection->x) && - coord_eq(next_intersection->y, m_cur_intersection->y); + intersections_eq(next_intersection->ii, m_cur_intersection->ii); next_intersection= next_intersection->get_next()) { /* Handle equal intersections. We only need to set proper events */ @@ -990,5 +1989,58 @@ int Gcalc_scan_iterator::intersection_scan() return 0; } + +double Gcalc_scan_iterator::get_y() const +{ + if (current_state->intersection_scan) + { + double x, y; + current_state->isc->calc_xy(&x, &y); + return y; + } + else + return current_state->pi->y; +} + + +double Gcalc_scan_iterator::get_event_x() const +{ + if (current_state->intersection_scan) + { + double x, y; + current_state->isc->calc_xy(&x, &y); + return x; + } + else + return current_state->pi->x; +} + +double Gcalc_scan_iterator::get_h() const +{ + double cur_y= get_y(); + double next_y; + if (next_state->intersection_scan) + { + double x; + next_state->isc->calc_xy(&x, &next_y); + } + else + next_y= next_state->pi->y; + return next_y - cur_y; +} + + +double Gcalc_scan_iterator::get_sp_x(const point *sp) const +{ + double dy; + if (sp->event == scev_end | scev_two_ends | scev_point) + return sp->pi->x; + dy= sp->next_pi->y - sp->pi->y; + if (fabs(dy) < 1e-12) + return sp->pi->x; + return (sp->next_pi->x - sp->pi->x) * dy; +} + + #endif /* HAVE_SPATIAL */ diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index ebe2bcffe5c..d1c81ca4648 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -59,8 +59,11 @@ public: } inline void free_list(Item *list, Item **hook) { - *hook= m_free; - m_free= list; + if (*hook != list) + { + *hook= m_free; + m_free= list; + } } void free_list(Item *list) @@ -91,6 +94,79 @@ protected: } }; +/* Internal Gcalc coordinates to provide the precise calculations */ + +#define DIG_BASE 1000000000 +typedef int32 coord_digit_t; +typedef long long coord2; + +#define C_SCALE 1e13 +#define COORD_BASE 2 +#ifndef DBUG_OFF +//#define GCALC_CHECK_WITH_FLOAT +#define NO_TESTING +#else +#define NO_TESTING +#endif /*DBUG_OFF*/ + +class Gcalc_internal_coord +{ +public: + coord_digit_t *digits; + int sign; + int n_digits; + void set_zero(); + int is_zero() const; +#ifdef GCALC_CHECK_WITH_FLOAT + long double get_double() const; +#endif /*GCALC_CHECK_WITH_FLOAT*/ +}; + + +class Gcalc_coord1 : public Gcalc_internal_coord +{ + coord_digit_t c[COORD_BASE]; +public: + void init() + { + n_digits= COORD_BASE; + digits= c; + } + int set_double(double d); + void copy(const Gcalc_coord1 *from); +}; + + +class Gcalc_coord2 : public Gcalc_internal_coord +{ + coord_digit_t c[COORD_BASE*2]; +public: + void init() + { + n_digits= COORD_BASE*2; + digits= c; + } +}; + + +void gcalc_mul_coord(Gcalc_internal_coord *result, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b); + +void gcalc_add_coord(Gcalc_internal_coord *result, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b); + +void gcalc_sub_coord(Gcalc_internal_coord *result, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b); + +int gcalc_cmp_coord(const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b); + +/* Internal coordinates declarations end. */ + + typedef uint gcalc_shape_info; /* @@ -114,27 +190,34 @@ public: Info *left; Info *right; double x,y; + Gcalc_coord1 ix, iy; inline bool is_bottom() const { return !left; } inline Info *get_next() { return (Info *)next; } inline const Info *get_next() const { return (const Info *)next; } }; + class Intersection_info : public Gcalc_dyn_list::Item + { + public: + /* Line p1-p2 supposed to intersect line p3-p4 */ + const Info *p1; + const Info *p2; + const Info *p3; + const Info *p4; + void calc_xy(double *x, double *y) const; +#ifdef GCALC_CHECK_WITH_FLOAT + void calc_xy_ld(long double *x, long double *y) const; +#endif /*GCALC_CHECK_WITH_FLOAT*/ + }; Gcalc_heap(size_t blk_size=8192) : - Gcalc_dyn_list(blk_size, sizeof(Info)), m_hook(&m_first), m_n_points(0) {} - Info *new_point_info(double x, double y, gcalc_shape_info shape) - { - Info *result= (Info *)new_item(); - if (!result) - return NULL; - *m_hook= result; - m_hook= &result->next; - m_n_points++; - result->x= x; - result->y= y; - result->shape= shape; - return result; - } + Gcalc_dyn_list(blk_size, sizeof(Info)), + m_hook(&m_first), m_n_points(0), + m_intersection_hook((Gcalc_dyn_list::Item **) &m_first_intersection) + {} + Info *new_point_info(double x, double y, gcalc_shape_info shape); + Intersection_info *new_intersection(const Info *p1, const Info *p2, + const Info *p3, const Info *p4); void prepare_operation(); inline bool ready() const { return m_hook == NULL; } Info *get_first() { return (Info *)m_first; } @@ -145,6 +228,8 @@ private: Gcalc_dyn_list::Item *m_first; Gcalc_dyn_list::Item **m_hook; int m_n_points; + Intersection_info *m_first_intersection; + Gcalc_dyn_list::Item **m_intersection_hook; }; @@ -263,9 +348,13 @@ public: class point : public Gcalc_dyn_list::Item { public: +#ifdef TMP_BLOCK double x; double dx_dy; int horiz_dir; +#endif /*TMP_BLOCK*/ + Gcalc_coord1 dx; + Gcalc_coord1 dy; Gcalc_heap::Info *pi; Gcalc_heap::Info *next_pi; sc_thread_id thread; @@ -273,22 +362,32 @@ public: const point *intersection_link; Gcalc_scan_events event; #ifdef TO_REMOVE - const point *event_pair; point *next_link; #endif /*TO_REMOVE*/ inline const point *c_get_next() const { return (const point *)next; } - inline bool is_bottom() const { return pi->is_bottom(); } + inline bool is_bottom() const { return !next_pi; } gcalc_shape_info get_shape() const { return pi->shape; } inline point *get_next() { return (point *)next; } inline const point *get_next() const { return (const point *)next; } /* copies all but 'next' 'x' and 'precursor' */ - void copy_core(point *from); + void copy_core(const point *from); + void copy_all(const point *from); /* Compare the dx_dy parameters regarding the horiz_dir */ /* returns -1 if less, 0 if equal, 1 if bigger */ - static int compare_dx_dy(int horiz_dir_a, double dx_dy_a, - int horiz_dir_b, double dx_dy_b); +#ifdef TMP_BLOCK + static int cmp_dx_dy(int horiz_dir_a, double dx_dy_a, + int horiz_dir_b, double dx_dy_b); +#endif /*TMP_BLOCK*/ + static int cmp_dx_dy(const Gcalc_coord1 *dx_a, + const Gcalc_coord1 *dy_a, + const Gcalc_coord1 *dx_b, + const Gcalc_coord1 *dy_b); + static int cmp_dx_dy(const Gcalc_heap::Info *p1, + const Gcalc_heap::Info *p2, + const Gcalc_heap::Info *p3, + const Gcalc_heap::Info *p4); int cmp_dx_dy(const point *p) const; int simple_event() const { @@ -298,6 +397,9 @@ public: #ifndef DBUG_OFF void dbug_print(); #endif /*DBUG_OFF*/ +#ifdef GCALC_CHECK_WITH_FLOAT + void calc_x(long double *x, long double y, long double ix) const; +#endif /*GCALC_CHECK_WITH_FLOAT*/ }; class intersection : public Gcalc_dyn_list::Item @@ -306,8 +408,11 @@ public: int n_row; sc_thread_id thread_a; sc_thread_id thread_b; +#ifdef TMP_BLOCK double x; double y; +#endif /*TMP_BLOCK*/ + const Gcalc_heap::Intersection_info *ii; inline intersection *get_next() { return (intersection *)next; } }; @@ -318,7 +423,15 @@ public: point *event_position; Gcalc_dyn_list::Item **event_position_hook; Gcalc_dyn_list::Item **event_end_hook; + int intersection_scan; + union + { + const Gcalc_heap::Info *pi; + const Gcalc_heap::Intersection_info *isc; + }; +#ifdef TMP_BLOCK double y; +#endif /*TMP_BLOCK*/ slice_state() : slice(NULL) {} void clear_event_position() { @@ -350,10 +463,24 @@ public: { return (point *) *current_state->event_end_hook; } inline const point *get_b_slice() const { return current_state->slice; } inline const point *get_t_slice() const { return next_state->slice; } - inline double get_h() const { return current_state->y - next_state->y; } - inline double get_y() const { return current_state->y; } + double get_h() const; + double get_y() const; + double get_event_x() const; + double get_sp_x(const point *sp) const; + int intersection_step() const { return current_state->intersection_scan; } + const Gcalc_heap::Info *get_cur_pi() const + { + DBUG_ASSERT(!intersection_step()); + return current_state->pi; + } + const Gcalc_heap::Intersection_info *get_cur_ii() const + { + DBUG_ASSERT(intersection_step()); + return current_state->isc; + } private: + Gcalc_heap *m_heap; Gcalc_heap::Info *m_cur_pi; slice_state state0, state1, state_s; slice_state *current_state; @@ -382,7 +509,10 @@ private: } point *new_slice_point() { - return (point *)new_item(); + point *new_point= (point *)new_item(); + new_point->dx.init(); + new_point->dy.init(); + return new_point; } point *new_slice(point *example); int arrange_event(); @@ -450,7 +580,6 @@ public: inline const Gcalc_scan_iterator::point *point() const { return sp; } inline const Gcalc_heap::Info *get_pi() const { return sp->pi; } inline gcalc_shape_info get_shape() const { return sp->get_shape(); } - inline double get_x() const { return sp->x; } inline void restart(const Gcalc_scan_iterator *scan_i) { sp= scan_i->get_b_slice(); } }; diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index baff6278444..90c39f08d0b 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -347,6 +347,10 @@ int Gcalc_result_receiver::add_point(double x, double y) buffer.q_append(prev_y); prev_x= x; prev_y= y; +#ifndef NO_TESTING + if (n_points == 53) + printf("xxx\n"); +#endif /*NO_TESTING*/ return 0; } @@ -488,6 +492,9 @@ int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_positio Gcalc_operation_reducer::Gcalc_operation_reducer(size_t blk_size) : Gcalc_dyn_list(blk_size, sizeof(res_point)), +#ifndef DBUG_OFF + n_res_points(0), +#endif /*DBUG_OFF*/ m_res_hook((Gcalc_dyn_list::Item **)&m_result), m_first_active_thread(NULL) {} @@ -514,9 +521,73 @@ Gcalc_operation_reducer(Gcalc_function *fn, modes mode, size_t blk_size) : } -inline int Gcalc_operation_reducer::continue_range(active_thread *t, - const Gcalc_heap::Info *p, - int horiz_dir, double dx_dy) +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(); +} + +#ifndef NO_TESTING +void call_checkpoint(int d) +{ + printf("%d\n", d); +} +#endif /*NO_TESTING*/ + +Gcalc_operation_reducer::res_point * + Gcalc_operation_reducer::add_res_point(Gcalc_function::shape_type type) +{ + res_point *result= (res_point *)new_item(); + *m_res_hook= result; + result->prev_hook= m_res_hook; + m_res_hook= &result->next; + result->type= type; +#ifndef DBUG_OFF + result->point_n= n_res_points++; +#endif /*DBUG_OFF*/ +#ifndef NO_TESTING + if (result->point_n == 74) + call_checkpoint(74); +#endif /*NO_TESTING*/ + return result; +} + +int Gcalc_operation_reducer::add_line(int incoming, active_thread *t, + const Gcalc_scan_iterator::point *p) +{ + line *l= new_line(); + if (!l) + return 1; + l->incoming= incoming; + l->t= t; + l->p= p; + *m_lines_hook= l; + m_lines_hook= &l->next; + return 0; +} + + +int Gcalc_operation_reducer::add_poly_border(int incoming, + active_thread *t, int prev_state, const Gcalc_scan_iterator::point *p) +{ + poly_border *b= new_poly_border(); + if (!b) + return 1; + b->incoming= incoming; + b->t= t; + b->prev_state= prev_state; + b->p= p; + *m_poly_borders_hook= b; + m_poly_borders_hook= &b->next; + return 0; +} + + +int Gcalc_operation_reducer::continue_range(active_thread *t, + const Gcalc_heap::Info *p, + const Gcalc_heap::Info *p_next) { res_point *rp= add_res_point(t->rp->type); if (!rp) @@ -527,15 +598,14 @@ inline int Gcalc_operation_reducer::continue_range(active_thread *t, rp->intersection_point= false; rp->pi= p; t->rp= rp; - t->horiz_dir= horiz_dir; - t->dx_dy= dx_dy; + t->p1= p; + t->p2= p_next; return 0; } inline int Gcalc_operation_reducer::continue_i_range(active_thread *t, - double x, double y, - int horiz_dir, double dx_dy) + const Gcalc_heap::Intersection_info *ii) { res_point *rp= add_res_point(t->rp->type); if (!rp) @@ -544,11 +614,8 @@ inline int Gcalc_operation_reducer::continue_i_range(active_thread *t, rp->down= t->rp; t->rp->up= rp; rp->intersection_point= true; - rp->x= x; - rp->y= y; + rp->ii= ii; t->rp= rp; - t->horiz_dir= horiz_dir; - t->dx_dy= dx_dy; return 0; } @@ -573,6 +640,9 @@ int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1, } +#ifndef NO_TESTING +int ca_counter= 0; +#endif /*NO_TESTING*/ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { Gcalc_point_iterator pi(si); @@ -587,8 +657,16 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) active_thread *bottom_threads= NULL; active_thread *eq_thread, *point_thread;; +#ifndef NO_TESTING + if (ca_counter == 11522) + call_checkpoint(89); +#endif /*NO_TESTING*/ m_fn->clear_state(); /* Walk to the event, remembering what is needed. */ +#ifndef NO_TESTING + if (si->get_event_position() == pi.point()) + printf("yyy\n"); +#endif /*NO_TESTING*/ for (; pi.point() != si->get_event_position(); ++pi, cur_t_hook= (active_thread **) &(*cur_t_hook)->next) { @@ -612,13 +690,13 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) case scev_point: { if (cur_t->enabled() && - continue_range(cur_t, events->pi, events->horiz_dir, events->dx_dy)) + continue_range(cur_t, events->pi, events->next_pi)) return 1; break; } case scev_end: { - if (cur_t->enabled() && end_line(cur_t, events->pi, si)) + if (cur_t->enabled() && end_line(cur_t, si)) return 1; *cur_t_hook= cur_t->get_next(); free_item(cur_t); @@ -635,8 +713,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) else if (cur_t->enabled() || cur_t->get_next()->enabled()) { /* Rare case when edges of a polygon coincide */ - if (end_line(cur_t->enabled() ? cur_t : cur_t->get_next(), - events->pi, si)) + if (end_line(cur_t->enabled() ? cur_t : cur_t->get_next(), si)) return 1; } *cur_t_hook= cur_t->get_next()->get_next(); @@ -647,6 +724,9 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) default: DBUG_ASSERT(0); } +#ifndef NO_TESTING + goto testing; +#endif /*NO_TESTING*/ return 0; } @@ -773,7 +853,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) for (events= si->get_events(); events; events= events->get_next()) m_fn->set_on_state(events->get_shape()); - return m_fn->count() ? add_single_point(event_point, si) : 0; + return m_fn->count() ? add_single_point(si) : 0; } if (m_poly_borders) @@ -783,6 +863,10 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { poly_border *pb1, *pb2; pb1= m_poly_borders; +#ifndef NO_TESTING + if (!m_poly_borders->next) + call_checkpoint(3); +#endif /*NO_TESTING*/ DBUG_ASSERT(m_poly_borders->next); pb2= get_pair_border(pb1); @@ -790,8 +874,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) m_poly_borders= pb1->get_next(); if (connect_threads(pb1->incoming, pb2->incoming, pb1->t, pb2->t, pb1->p, pb2->p, - prev_range, event_point, si, - Gcalc_function::shape_polygon)) + prev_range, si, Gcalc_function::shape_polygon)) return 1; free_item(pb1); @@ -809,8 +892,8 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { if (connect_threads(m_lines->incoming, m_lines->get_next()->incoming, m_lines->t, m_lines->get_next()->t, - m_lines->p, m_lines->get_next()->p, NULL, - event_point, si, Gcalc_function::shape_line)) + m_lines->p, m_lines->get_next()->p, + NULL, si, Gcalc_function::shape_line)) return 1; } else @@ -819,11 +902,11 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { if (cur_line->incoming) { - if (end_line(cur_line->t, event_point, si)) + if (end_line(cur_line->t, si)) return 1; } else - start_line(cur_line->t, cur_line->p, event_point, si); + start_line(cur_line->t, cur_line->p, si); } } free_list(m_lines); @@ -834,28 +917,56 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) if (bottom_threads) free_list(bottom_threads); +#ifndef NO_TESTING +testing: + { + Gcalc_point_iterator x_pi(si); + active_thread **x_cur_t_hook= &m_first_active_thread; + int x_prev_state= 0; + m_fn->save_states(); + m_fn->clear_state(); + if (ca_counter == /*11552*/90) + call_checkpoint(10); + for (; x_pi.point(); ++x_pi) + { + active_thread *cur_t= *x_cur_t_hook; + if (cur_t->enabled() && + cur_t->rp->type == Gcalc_function::shape_polygon) + x_prev_state^= 1; + int ppb= m_fn->count(); + if (m_fn->get_shape_kind(x_pi.get_shape()) == Gcalc_function::shape_polygon) + m_fn->invert_state(x_pi.get_shape()); + int ppa= m_fn->count(); + if (ppa != x_prev_state) + { + if (x_pi.point()->cmp_dx_dy(x_pi.point()->get_next()) != 0) + call_checkpoint(21); + } + if (cur_t->enabled()) + { + if (m_fn->get_shape_kind(x_pi.get_shape()) == Gcalc_function::shape_polygon) + if (ppa == ppb) + call_checkpoint(22); + else + if (ppa != 0 && ppb != 0) + call_checkpoint(23); + } + x_cur_t_hook= (active_thread **) &(*x_cur_t_hook)->next; + } + m_fn->restore_states(); + } +#endif /*NO_TESTING*/ return 0; } -int Gcalc_operation_reducer::add_single_point(const Gcalc_heap::Info *p, - const Gcalc_scan_iterator *si) +int Gcalc_operation_reducer::add_single_point(const Gcalc_scan_iterator *si) { res_point *rp= add_res_point(Gcalc_function::shape_point); if (!rp) return 1; rp->glue= rp->up= rp->down= NULL; - if (p) - { - rp->intersection_point= false; - rp->pi= p; - } - else - { - rp->intersection_point= true; - rp->y= si->get_y(); - rp->x= si->get_events()->x; - } + rp->set(si); return 0; } @@ -912,7 +1023,7 @@ int Gcalc_operation_reducer::connect_threads( int incoming_a, int incoming_b, active_thread *ta, active_thread *tb, const Gcalc_scan_iterator::point *pa, const Gcalc_scan_iterator::point *pb, - active_thread *prev_range, const Gcalc_heap::Info *ev_p, + active_thread *prev_range, const Gcalc_scan_iterator *si, Gcalc_function::shape_type s_t) { if (incoming_a && incoming_b) @@ -929,18 +1040,8 @@ int Gcalc_operation_reducer::connect_threads( rpa->up= rpb->up= NULL; ta->rp->up= rpa; tb->rp->up= rpb; - if (ev_p) - { - rpa->intersection_point= rpb->intersection_point= false; - rpa->pi= rpb->pi= ev_p; - } - else - { - rpa->intersection_point= rpb->intersection_point= true; - rpa->x= rpb->x= si->get_events()->x; - rpa->y= rpb->y= si->get_y(); - } - + rpa->set(si); + rpb->set(si); ta->rp= tb->rp= NULL; return 0; } @@ -953,35 +1054,30 @@ int Gcalc_operation_reducer::connect_threads( return 1; rp0->glue= rp1; rp1->glue= rp0; - if (ev_p) - { - rp0->intersection_point= rp1->intersection_point= false; - rp0->pi= rp1->pi= ev_p; - } - else - { - rp0->intersection_point= rp1->intersection_point= true; - rp0->x= rp1->x= si->get_events()->x; - rp0->y= rp1->y= si->get_y(); - } + rp0->set(si); + rp1->set(si); rp0->down= rp1->down= NULL; ta->rp= rp0; tb->rp= rp1; - ta->horiz_dir= pa->horiz_dir; - ta->dx_dy= pa->dx_dy; + ta->p1= pa->pi; + ta->p2= pa->next_pi; - tb->horiz_dir= pb->horiz_dir; - tb->dx_dy= pb->dx_dy; + tb->p1= pb->pi; + tb->p2= pb->next_pi; if (prev_range) { rp0->outer_poly= prev_range->thread_start; tb->thread_start= prev_range->thread_start; + /* Chack if needed */ + ta->thread_start= prev_range->thread_start; } else { rp0->outer_poly= 0; ta->thread_start= rp0; + /* Chack if needed */ + tb->thread_start= rp0; } return 0; } @@ -991,20 +1087,18 @@ int Gcalc_operation_reducer::connect_threads( tb->rp= ta->rp; tb->thread_start= ta->thread_start; if (Gcalc_scan_iterator::point:: - compare_dx_dy(ta->horiz_dir, ta->dx_dy, - pb->horiz_dir, pb->dx_dy) != 0) + cmp_dx_dy(ta->p1, ta->p2, pb->pi, pb->next_pi) != 0) { - if (ev_p ? continue_range(tb, ev_p, pb->horiz_dir, pb->dx_dy): - continue_i_range(tb, - si->get_events()->x, si->get_y(), - pb->horiz_dir, pb->dx_dy)) + if (si->intersection_step() ? + continue_i_range(tb, si->get_cur_ii()) : + continue_range(tb, si->get_cur_pi(), pb->next_pi)) +#ifdef TMP_BLOCK + continue_range(tb, si->get_cur_pi()) +#endif /*TMP_BLOCK*/ return 1; } - else - { - tb->horiz_dir= pb->horiz_dir; - tb->dx_dy= pb->dx_dy; - } + tb->p1= pb->pi; + tb->p2= pb->next_pi; return 0; } @@ -1012,33 +1106,21 @@ int Gcalc_operation_reducer::connect_threads( int Gcalc_operation_reducer::start_line(active_thread *t, const Gcalc_scan_iterator::point *p, - const Gcalc_heap::Info *ev_p, const Gcalc_scan_iterator *si) { res_point *rp= add_res_point(Gcalc_function::shape_line); if (!rp) return 1; rp->glue= rp->down= NULL; - if (ev_p) - { - rp->intersection_point= false; - rp->pi= ev_p; - } - else - { - rp->intersection_point= true; - rp->x= si->get_events()->x; - rp->y= si->get_y(); - } + rp->set(si); t->rp= rp; - t->horiz_dir= p->horiz_dir; - t->dx_dy= p->dx_dy; + t->p1= p->pi; + t->p2= p->next_pi; return 0; } int Gcalc_operation_reducer::end_line(active_thread *t, - const Gcalc_heap::Info *ev_p, const Gcalc_scan_iterator *si) { DBUG_ASSERT(t->rp->type == Gcalc_function::shape_line); @@ -1047,17 +1129,7 @@ int Gcalc_operation_reducer::end_line(active_thread *t, return 1; rp->glue= rp->up= NULL; rp->down= t->rp; - if (ev_p) - { - rp->intersection_point= false; - rp->pi= ev_p; - } - else - { - rp->intersection_point= true; - rp->x= si->get_events()->x; - rp->y= si->get_y(); - } + rp->set(si); t->rp->up= rp; t->rp= NULL; @@ -1071,6 +1143,11 @@ int Gcalc_operation_reducer::count_all(Gcalc_heap *hp) si.init(hp); while (si.more_points()) { +#ifndef NO_TESTING + printf("Point %d\n", ++ca_counter); + if (ca_counter == 12) + call_checkpoint(10); +#endif /*NO_TESTING*/ if (si.step()) return 1; if (count_slice(&si)) @@ -1094,8 +1171,9 @@ inline int Gcalc_operation_reducer::get_single_result(res_point *res, { if (res->intersection_point) { - if (storage->single_point(float_to_coord(res->x), - float_to_coord(res->y))) + double x, y; + res->ii->calc_xy(&x, &y); + if (storage->single_point(x,y)) return 1; } else @@ -1105,6 +1183,9 @@ inline int Gcalc_operation_reducer::get_single_result(res_point *res, return 0; } +#ifndef NO_TESTING +int pc_counter= 0; +#endif /*NO_TESTING*/ int Gcalc_operation_reducer::get_result_thread(res_point *cur, Gcalc_result_receiver *storage, @@ -1116,12 +1197,16 @@ int Gcalc_operation_reducer::get_result_thread(res_point *cur, double x, y; while (cur) { +#ifndef NO_TESTING + ++pc_counter; + if (pc_counter == 79) + call_checkpoint(79); +#endif /*NO_TESTING*/ if (!glue_step) { if (cur->intersection_point) { - x= float_to_coord(cur->x); - y= float_to_coord(cur->y); + cur->ii->calc_xy(&x, &y); } else { diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index da7be1d9fa7..39704dfeb56 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -206,26 +206,37 @@ public: int get_result(Gcalc_result_receiver *storage); void reset(); +#ifndef DBUG_OFF + int n_res_points; +#endif /*DBUG_OFF*/ class res_point : public Gcalc_dyn_list::Item { public: - bool intersection_point; - double x,y; + int intersection_point; + union + { + const Gcalc_heap::Info *pi; + const Gcalc_heap::Intersection_info *ii; + res_point *first_poly_node; + }; +#ifdef TMP_BLOCK + union + { +#endif /*TMP_BLOCK*/ + res_point *outer_poly; + uint32 poly_position; +#ifdef TMP_BLOCK + }; +#endif /*TMP_BLOCK*/ res_point *up; res_point *down; res_point *glue; Gcalc_function::shape_type type; - union - { - const Gcalc_heap::Info *pi; - res_point *first_poly_node; - }; - union - { - res_point *outer_poly; - uint32 poly_position; - }; Gcalc_dyn_list::Item **prev_hook; +#ifndef DBUG_OFF + int point_n; +#endif /*DBUG_OFF*/ + void set(const Gcalc_scan_iterator *si); res_point *get_next() { return (res_point *)next; } }; @@ -233,9 +244,9 @@ public: { public: res_point *rp; - int horiz_dir; - double dx_dy; res_point *thread_start; + + const Gcalc_heap::Info *p1, *p2; res_point *enabled() { return rp; } active_thread *get_next() { return (active_thread *)next; } }; @@ -273,33 +284,9 @@ public: line *new_line() { return (line *) new_item(); } poly_border *new_poly_border() { return (poly_border *) new_item(); } int add_line(int incoming, active_thread *t, - const Gcalc_scan_iterator::point *p) - { - line *l= new_line(); - if (!l) - return 1; - l->incoming= incoming; - l->t= t; - l->p= p; - *m_lines_hook= l; - m_lines_hook= &l->next; - return 0; - } - + const Gcalc_scan_iterator::point *p); int add_poly_border(int incoming, active_thread *t, int prev_state, - const Gcalc_scan_iterator::point *p) - { - poly_border *b= new_poly_border(); - if (!b) - return 1; - b->incoming= incoming; - b->t= t; - b->prev_state= prev_state; - b->p= p; - *m_poly_borders_hook= b; - m_poly_borders_hook= &b->next; - return 0; - } + const Gcalc_scan_iterator::point *p); protected: Gcalc_function *m_fn; @@ -310,43 +297,29 @@ protected: res_point *result_heap; active_thread *m_first_active_thread; - res_point *add_res_point(Gcalc_function::shape_type type) - { - res_point *result= (res_point *)new_item(); - *m_res_hook= result; - result->prev_hook= m_res_hook; - m_res_hook= &result->next; - result->type= type; - return result; - } - + res_point *add_res_point(Gcalc_function::shape_type type); active_thread *new_active_thread() { return (active_thread *)new_item(); } poly_instance *new_poly() { return (poly_instance *) new_item(); } private: int start_line(active_thread *t, const Gcalc_scan_iterator::point *p, - const Gcalc_heap::Info *ev_p, const Gcalc_scan_iterator *si); - int end_line(active_thread *t, const Gcalc_heap::Info *ev_p, - const Gcalc_scan_iterator *si); + const Gcalc_scan_iterator *si); + int end_line(active_thread *t, const Gcalc_scan_iterator *si); int connect_threads(int incoming_a, int incoming_b, active_thread *ta, active_thread *tb, const Gcalc_scan_iterator::point *pa, const Gcalc_scan_iterator::point *pb, active_thread *prev_range, - const Gcalc_heap::Info *ev_p, const Gcalc_scan_iterator *si, Gcalc_function::shape_type s_t); - int add_single_point(const Gcalc_heap::Info *p, - const Gcalc_scan_iterator *si); + int add_single_point(const Gcalc_scan_iterator *si); poly_border *get_pair_border(poly_border *b1); int continue_range(active_thread *t, const Gcalc_heap::Info *p, - int horiz_dir, double dx_dy); - int continue_i_range(active_thread *t, double x, double y, - int horiz_dir, double dx_dy); + const Gcalc_heap::Info *p_next); + int continue_i_range(active_thread *t, + const Gcalc_heap::Intersection_info *ii); int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p); - int add_single_point(const Gcalc_heap::Info *p); - int get_single_result(res_point *res, Gcalc_result_receiver *storage); int get_result_thread(res_point *cur, Gcalc_result_receiver *storage, int move_upward, res_point *first_poly_node); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 631b63812b5..2c3facb49c8 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -867,7 +867,8 @@ int Item_func_spatial_rel::func_touches() if (cur_func) { area= scan_it.get_h() * - ((ti.rb()->x - ti.lb()->x) + (ti.rt()->x - ti.lt()->x)); + ((scan_it.get_sp_x(ti.rb()) - scan_it.get_sp_x(ti.lb())) + + (scan_it.get_sp_x(ti.rt()) - scan_it.get_sp_x(ti.lt()))); if (area > GIS_ZERO) { result= 0; diff --git a/sql/spatial.cc b/sql/spatial.cc index 67e36ccb12b..0e535d11056 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -2230,6 +2230,8 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const return 1; n_objects= uint4korr(data); data+= 4; + if (n_objects == 0) + return 1; while (n_objects--) { From 25b5019c34e717aff95bf405e7d5eb15c2bedf75 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 21 Sep 2011 09:29:37 +0500 Subject: [PATCH 24/40] bugs fixed 855253 Compiler error: gcalc_slicescan.cc:2036: error: suggest parentheses around comparison in operand of .|. in maria-5.3-gis 850775 ST_AREA does not work on GEOMETRYCOLLECTIONs in maria-5.3-gis per-file comments: mysql-test/r/gis.result test result updated. mysql-test/t/gis.test test case added for 850775. sql/gcalc_slicescan.cc compiler error fixed. sql/spatial.cc ST_AREA implementation for GEOMETRY_COLLECTION, POINT and LINESTRING. sql/spatial.h area() declarations added. --- mysql-test/r/gis.result | 15 ++++++----- mysql-test/t/gis.test | 5 ++++ sql/gcalc_slicescan.cc | 2 +- sql/spatial.cc | 60 +++++++++++++++++++++++++++++++++++++++++ sql/spatial.h | 3 +++ 5 files changed, 78 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 190795855dd..5a8571bb17e 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -230,7 +230,7 @@ fid AsText(Envelope(g)) 119 POLYGON((0 0,3 0,3 3,0 3,0 0)) 120 POLYGON((0 0,10 0,10 10,0 10,0 0)) 121 POLYGON((3 6,44 6,44 9,3 9,3 6)) -122 POLYGON((1.79769313486232e+308 1.79769313486232e+308,-1.79769313486232e+308 1.79769313486232e+308,-1.79769313486232e+308 -1.79769313486232e+308,1.79769313486232e+308 -1.79769313486232e+308,1.79769313486232e+308 1.79769313486232e+308)) +122 NULL explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelope(g)) from gis_geometry; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 22 100.00 @@ -396,13 +396,13 @@ FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second first second w c o e d t i r 120 120 1 1 0 1 0 1 1 1 120 121 0 0 1 0 0 0 1 0 -120 122 0 1 0 0 1 0 0 0 +120 122 0 1 NULL NULL NULL 0 NULL 0 121 120 0 0 1 0 0 0 1 0 121 121 1 1 0 1 0 1 1 1 -121 122 0 1 0 0 1 0 0 0 -122 120 1 0 0 0 1 0 0 0 -122 121 1 0 0 0 1 0 0 0 -122 122 1 1 0 1 1 0 0 0 +121 122 0 1 NULL NULL NULL 0 NULL 0 +122 120 1 0 NULL NULL NULL 0 NULL 0 +122 121 1 0 NULL NULL NULL 0 NULL 0 +122 122 1 1 NULL NULL NULL 0 NULL 0 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -1077,6 +1077,9 @@ SPATIAL INDEX i1 (col1, col2) ERROR HY000: Incorrect arguments to SPATIAL INDEX DROP TABLE t1; DROP TABLE t2; +select ST_AREA(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 31 10, 77 80), POLYGON((0 0,4 7,1 1,0 0)), POINT(20 20))')); +ST_AREA(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 31 10, 77 80), POLYGON((0 0,4 7,1 1,0 0)), POINT(20 20))')) +1.5 DROP DATABASE IF EXISTS gis_ogs; CREATE DATABASE gis_ogs; USE gis_ogs; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 25fec4cca4e..359d0e8520a 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -804,6 +804,11 @@ CREATE TABLE t3 ( DROP TABLE t1; DROP TABLE t2; +#bug 850775 ST_AREA does not work on GEOMETRYCOLLECTIONs in maria-5.3-gis +select ST_AREA(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 31 10, 77 80), POLYGON((0 0,4 7,1 1,0 0)), POINT(20 20))')); + + + # Conformance tests # # C.3.3 Geometry types and functions diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 07120d2e87e..8a9fcc60ad0 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -2033,7 +2033,7 @@ double Gcalc_scan_iterator::get_h() const double Gcalc_scan_iterator::get_sp_x(const point *sp) const { double dy; - if (sp->event == scev_end | scev_two_ends | scev_point) + if (sp->event & (scev_end | scev_two_ends | scev_point)) return sp->pi->x; dy= sp->next_pi->y - sp->pi->y; if (fabs(dy) < 1e-12) diff --git a/sql/spatial.cc b/sql/spatial.cc index 0e535d11056..4d5e5db10c0 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -489,6 +489,14 @@ bool Gis_point::get_mbr(MBR *mbr, const char **end) const } +int Gis_point::area(double *ar, const char **end) const +{ + *ar= 0; + *end= m_data+ POINT_DATA_SIZE; + return 0; +} + + int Gis_point::store_shapes(Gcalc_shape_transporter *trn) const { double x, y; @@ -634,6 +642,20 @@ int Gis_line_string::geom_length(double *len) const } +int Gis_line_string::area(double *ar, const char **end) const +{ + uint32 n_points; + *ar= 0.0; + + /* read number of points */ + if (no_data(m_data, 4)) + return 1; + n_points= uint4korr(m_data); + *end= m_data + 4 + POINT_DATA_SIZE * n_points; + return 0; +} + + int Gis_line_string::is_closed(int *closed) const { uint32 n_points; @@ -2253,6 +2275,44 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const } +int Gis_geometry_collection::area(double *ar, const char **end_of_data) const +{ + uint32 n_objects; + const char *data= m_data; + Geometry_buffer buffer; + Geometry *geom; + double result; + + if (no_data(data, 4)) + return 1; + n_objects= uint4korr(data); + data+= 4; + if (n_objects == 0) + return 1; + + result= 0.0; + while (n_objects--) + { + uint32 wkb_type; + + if (no_data(data, WKB_HEADER_SIZE)) + 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->area(ar, &data)) + return 1; + result+= *ar; + } + *end_of_data= data; + *ar= result; + return 0; +} + + int Gis_geometry_collection::num_geometries(uint32 *num) const { if (no_data(m_data, 4)) diff --git a/sql/spatial.h b/sql/spatial.h index e8f230f9127..eaf048b7a3d 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -375,6 +375,7 @@ public: return 0; } + int area(double *ar, const char **end) const; bool dimension(uint32 *dim, const char **end) const { *dim= 0; @@ -399,6 +400,7 @@ public: bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int geom_length(double *len) const; + int area(double *ar, const char **end) const; int is_closed(int *closed) const; int num_points(uint32 *n_points) const; int start_point(String *point) const; @@ -540,6 +542,7 @@ public: uint init_from_opresult(String *bin, const char *opres, uint res_len); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; + int area(double *ar, const char **end) const; int num_geometries(uint32 *num) const; int geometry_n(uint32 num, String *result) const; bool dimension(uint32 *dim, const char **end) const; From 6b64baf3b9c8a6c33dd47be62c0b73ab12157760 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 21 Sep 2011 12:50:03 +0500 Subject: [PATCH 25/40] fix for bug 848926 GIS functions return "GEOMETRYCOLLECTION()" instead of "GEOMETRYCOLLECTION EMPTY" per-file comments: mysql-test/r/gis.result fix for bug 848926 GIS functions return "GEOMETRYCOLLECTION()" instead of "GEOMETRYCOLLECTION EMPTY" test result updated. mysql-test/t/gis.test fix for bug 848926 GIS functions return "GEOMETRYCOLLECTION()" instead of "GEOMETRYCOLLECTION EMPTY" test case added. sql/gstream.cc fix for bug 848926 GIS functions return "GEOMETRYCOLLECTION()" instead of "GEOMETRYCOLLECTION EMPTY" lookup_next_word() implemented. sql/gstream.h fix for bug 848926 GIS functions return "GEOMETRYCOLLECTION()" instead of "GEOMETRYCOLLECTION EMPTY" lookup_next_word() added. sql/spatial.cc fix for bug 848926 GIS functions return "GEOMETRYCOLLECTION()" instead of "GEOMETRYCOLLECTION EMPTY" name changed for the empty geometry. sql/spatial.h fix for bug 848926 GIS functions return "GEOMETRYCOLLECTION()" instead of "GEOMETRYCOLLECTION EMPTY" declarations modified. --- mysql-test/r/gis.result | 33 ++++++++++++++----- mysql-test/t/gis.test | 3 +- sql/gstream.cc | 23 +++++++++++++ sql/gstream.h | 1 + sql/spatial.cc | 72 +++++++++++++++++++++++++++++++++-------- sql/spatial.h | 13 +------- 6 files changed, 110 insertions(+), 35 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 5a8571bb17e..0755f106fba 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -67,7 +67,8 @@ INSERT INTO gis_multi_polygon VALUES INSERT INTO gis_geometrycollection VALUES (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')), (121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))), -(122, GeomFromText('GeometryCollection()')); +(122, GeomFromText('GeometryCollection()')), +(123, GeomFromText('GeometryCollection EMPTY')); INSERT into gis_geometry SELECT * FROM gis_point; INSERT into gis_geometry SELECT * FROM gis_line; INSERT into gis_geometry SELECT * FROM gis_polygon; @@ -110,7 +111,8 @@ SELECT fid, AsText(g) FROM gis_geometrycollection; fid AsText(g) 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10)) 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9)) -122 GEOMETRYCOLLECTION() +122 GEOMETRYCOLLECTION EMPTY +123 GEOMETRYCOLLECTION EMPTY SELECT fid, AsText(g) FROM gis_geometry; fid AsText(g) 101 POINT(10 10) @@ -134,7 +136,8 @@ fid AsText(g) 119 MULTIPOLYGON(((0 3,3 3,3 0,0 3))) 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10)) 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9)) -122 GEOMETRYCOLLECTION() +122 GEOMETRYCOLLECTION EMPTY +123 GEOMETRYCOLLECTION EMPTY SELECT fid, Dimension(g) FROM gis_geometry; fid Dimension(g) 101 0 @@ -159,6 +162,7 @@ fid Dimension(g) 120 1 121 1 122 0 +123 0 SELECT fid, GeometryType(g) FROM gis_geometry; fid GeometryType(g) 101 POINT @@ -183,6 +187,7 @@ fid GeometryType(g) 120 GEOMETRYCOLLECTION 121 GEOMETRYCOLLECTION 122 GEOMETRYCOLLECTION +123 GEOMETRYCOLLECTION SELECT fid, IsEmpty(g) FROM gis_geometry; fid IsEmpty(g) 101 0 @@ -207,6 +212,7 @@ fid IsEmpty(g) 120 0 121 0 122 0 +123 0 SELECT fid, AsText(Envelope(g)) FROM gis_geometry; fid AsText(Envelope(g)) 101 POLYGON((10 10,10 10,10 10,10 10,10 10)) @@ -231,9 +237,10 @@ fid AsText(Envelope(g)) 120 POLYGON((0 0,10 0,10 10,0 10,0 0)) 121 POLYGON((3 6,44 6,44 9,3 9,3 6)) 122 NULL +123 NULL explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelope(g)) from gis_geometry; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 22 100.00 +1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 23 100.00 Warnings: Note 1003 select st_dimension(`test`.`gis_geometry`.`g`) AS `Dimension(g)`,st_geometrytype(`test`.`gis_geometry`.`g`) AS `GeometryType(g)`,st_isempty(`test`.`gis_geometry`.`g`) AS `IsEmpty(g)`,st_astext(st_envelope(`test`.`gis_geometry`.`g`)) AS `AsText(Envelope(g))` from `test`.`gis_geometry` SELECT fid, X(g) FROM gis_point; @@ -353,6 +360,7 @@ fid NumGeometries(g) 120 2 121 2 122 0 +123 0 explain extended SELECT fid, NumGeometries(g) from gis_multi_point; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3 100.00 @@ -378,11 +386,13 @@ fid AsText(GeometryN(g, 2)) 120 LINESTRING(0 0,10 10) 121 LINESTRING(3 6,7 9) 122 NULL +123 NULL SELECT fid, AsText(GeometryN(g, 1)) from gis_geometrycollection; fid AsText(GeometryN(g, 1)) 120 POINT(0 0) 121 POINT(44 6) 122 NULL +123 NULL explain extended SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3 100.00 @@ -397,20 +407,27 @@ first second w c o e d t i r 120 120 1 1 0 1 0 1 1 1 120 121 0 0 1 0 0 0 1 0 120 122 0 1 NULL NULL NULL 0 NULL 0 +120 123 0 1 NULL NULL NULL 0 NULL 0 121 120 0 0 1 0 0 0 1 0 121 121 1 1 0 1 0 1 1 1 121 122 0 1 NULL NULL NULL 0 NULL 0 +121 123 0 1 NULL NULL NULL 0 NULL 0 122 120 1 0 NULL NULL NULL 0 NULL 0 122 121 1 0 NULL NULL NULL 0 NULL 0 122 122 1 1 NULL NULL NULL 0 NULL 0 +122 123 1 1 NULL NULL NULL 0 NULL 0 +123 120 1 0 NULL NULL NULL 0 NULL 0 +123 121 1 0 NULL NULL NULL 0 NULL 0 +123 122 1 1 NULL NULL NULL 0 NULL 0 +123 123 1 1 NULL NULL NULL 0 NULL 0 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE g1 ALL NULL NULL NULL NULL 3 100.00 Using temporary; Using filesort -1 SIMPLE g2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join) +1 SIMPLE g1 ALL NULL NULL NULL NULL 4 100.00 Using temporary; Using filesort +1 SIMPLE g2 ALL NULL NULL NULL NULL 4 100.00 Using join buffer (flat, BNL join) Warnings: Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,st_within(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,st_contains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,mbroverlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,mbrequals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,mbrdisjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,st_touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,mbrintersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,st_crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid` DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry; @@ -850,7 +867,7 @@ mbroverlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrtouches FROM t1 a1 JOIN t1 a2 ON MBRTouches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrtouches -down2,left2,right2,up2 +big,down2,left,left2,right,right2,small,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrwithin FROM t1 a1 JOIN t1 a2 ON MBRWithin( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrwithin big,center @@ -871,7 +888,7 @@ overlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS touches FROM t1 a1 JOIN t1 a2 ON Touches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; touches -down2,left2,right2,up2 +big,down2,left,left2,right,right2,small,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS within FROM t1 a1 JOIN t1 a2 ON Within( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; within big,center diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 359d0e8520a..2eee4bab767 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -63,7 +63,8 @@ INSERT INTO gis_multi_polygon VALUES INSERT INTO gis_geometrycollection VALUES (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')), (121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))), -(122, GeomFromText('GeometryCollection()')); +(122, GeomFromText('GeometryCollection()')), +(123, GeomFromText('GeometryCollection EMPTY')); INSERT into gis_geometry SELECT * FROM gis_point; INSERT into gis_geometry SELECT * FROM gis_line; diff --git a/sql/gstream.cc b/sql/gstream.cc index e2bb41b8541..3eaa46af3bf 100644 --- a/sql/gstream.cc +++ b/sql/gstream.cc @@ -39,6 +39,29 @@ enum Gis_read_stream::enum_tok_types Gis_read_stream::get_next_toc_type() } +bool Gis_read_stream::lookup_next_word(LEX_STRING *res) +{ + const char *cur= m_cur; + + skip_space(); + res->str= (char*) cur; + /* The following will also test for \0 */ + if ((cur >= m_limit) || !my_isvar_start(&my_charset_bin, *cur)) + return 1; + + /* + We can't combine the following increment with my_isvar() because + my_isvar() is a macro that would cause side effects + */ + cur++; + while ((cur < m_limit) && my_isvar(&my_charset_bin, *cur)) + cur++; + + res->length= (uint32) (cur - res->str); + return 0; +} + + bool Gis_read_stream::get_next_word(LEX_STRING *res) { skip_space(); diff --git a/sql/gstream.h b/sql/gstream.h index a1850e9a333..d3a40f4e7e0 100644 --- a/sql/gstream.h +++ b/sql/gstream.h @@ -39,6 +39,7 @@ public: } enum enum_tok_types get_next_toc_type(); + bool lookup_next_word(LEX_STRING *res); bool get_next_word(LEX_STRING *); bool get_next_number(double *); bool check_next_symbol(char); diff --git a/sql/spatial.cc b/sql/spatial.cc index 4d5e5db10c0..95ec4834e96 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -178,6 +178,7 @@ Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer, { LEX_STRING name; Class_info *ci; + char next_sym; if (trs->get_next_word(&name)) { @@ -190,9 +191,13 @@ Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer, Geometry *result= (*ci->m_create_func)(buffer->data); wkt->q_append((char) wkb_ndr); wkt->q_append((uint32) result->get_class_info()->m_type_id); - if (trs->check_next_symbol('(') || + if (!(next_sym= trs->next_symbol())) + return NULL; + if (!(next_sym= trs->next_symbol())) + return NULL; + if ((next_sym == '(' && trs->check_next_symbol('(')) || result->init_from_wkt(trs, wkt) || - trs->check_next_symbol(')')) + (next_sym == '(' && trs->check_next_symbol(')'))) return NULL; if (init_stream) { @@ -203,6 +208,22 @@ Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer, } +int Geometry::as_wkt(String *wkt, const char **end) +{ + uint32 len= (uint) get_class_info()->m_name.length; + if (wkt->reserve(len + 2, 512)) + return 1; + wkt->qs_append(get_class_info()->m_name.str, len); + if (get_class_info() != &geometrycollection_class) + wkt->qs_append('('); + if (get_data_as_wkt(wkt, end)) + return 1; + if (get_class_info() != &geometrycollection_class) + wkt->qs_append(')'); + return 0; +} + + static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo) { double res; @@ -2092,26 +2113,40 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb) uint32 no_pos= wkb->length(); Geometry_buffer buffer; Geometry *g; + char next_sym; if (wkb->reserve(4, 512)) return 1; wkb->length(wkb->length()+4); // Reserve space for points - if (trs->next_symbol() != ')') - { - for (;;) - { - if (!(g= create_from_wkt(&buffer, trs, wkb))) - return 1; + if (!(next_sym= trs->next_symbol())) + return 1; - if (g->get_class_info()->m_type_id == wkb_geometrycollection) + if (next_sym != ')') + { + LEX_STRING next_word; + if (trs->lookup_next_word(&next_word)) + return 1; + + if (next_word.length != 5 || + (my_strnncoll(&my_charset_latin1, + (const uchar*) "empty", 5, + (const uchar*) next_word.str, 5) != 0)) + { + for (;;) { - trs->set_error_msg("Unexpected GEOMETRYCOLLECTION"); - return 1; + if (!(g= create_from_wkt(&buffer, trs, wkb))) + return 1; + + if (g->get_class_info()->m_type_id == wkb_geometrycollection) + { + trs->set_error_msg("Unexpected GEOMETRYCOLLECTION"); + return 1; + } + n_objects++; + if (trs->skip_char(',')) // Didn't find ',' + break; } - n_objects++; - if (trs->skip_char(',')) // Didn't find ',' - break; } } @@ -2219,6 +2254,13 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt, n_objects= uint4korr(data); data+= 4; + if (n_objects == 0) + { + txt->append(STRING_WITH_LEN(" EMPTY"), 512); + goto exit; + } + + txt->qs_append('('); while (n_objects--) { uint32 wkb_type; @@ -2236,6 +2278,8 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt, if (n_objects && txt->append(STRING_WITH_LEN(","), 512)) return 1; } + txt->qs_append(')'); +exit: *end= data; return 0; } diff --git a/sql/spatial.h b/sql/spatial.h index eaf048b7a3d..cec80b3dacf 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -286,18 +286,7 @@ public: const char *wkb, uint32 len, String *res); static int create_from_opresult(Geometry_buffer *g_buf, String *res, Gcalc_result_receiver &rr); - int as_wkt(String *wkt, const char **end) - { - uint32 len= (uint) get_class_info()->m_name.length; - if (wkt->reserve(len + 2, 512)) - return 1; - wkt->qs_append(get_class_info()->m_name.str, len); - wkt->qs_append('('); - if (get_data_as_wkt(wkt, end)) - return 1; - wkt->qs_append(')'); - return 0; - } + int as_wkt(String *wkt, const char **end); inline void set_data_ptr(const char *data, uint32 data_len) { From d0f2e1e55176c7f674832444ea174c2445058ef7 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 21 Sep 2011 13:26:21 +0500 Subject: [PATCH 26/40] bug 855336 ST_LENGTH does not work on GEOMETRYCOLLECTIONs fixed. per-file comments: mysql-test/r/gis.result bug 855336 ST_LENGTH does not work on GEOMETRYCOLLECTIONs fixed. test result updated. mysql-test/t/gis.test bug 855336 ST_LENGTH does not work on GEOMETRYCOLLECTIONs fixed. test case added. sql/item_geofunc.cc bug 855336 ST_LENGTH does not work on GEOMETRYCOLLECTIONs fixed. geom_length() call fixed. sql/spatial.cc bug 855336 ST_LENGTH does not work on GEOMETRYCOLLECTIONs fixed. Geometry_collection::geom_length implemented. sql/spatial.h bug 855336 ST_LENGTH does not work on GEOMETRYCOLLECTIONs fixed. Geometry_collection::geom_length declaration added. --- mysql-test/r/gis.result | 3 +++ mysql-test/t/gis.test | 2 ++ sql/item_geofunc.cc | 3 ++- sql/spatial.cc | 59 +++++++++++++++++++++++++++++++++++++---- sql/spatial.h | 8 +++--- 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 0755f106fba..7f54e088cf8 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1097,6 +1097,9 @@ DROP TABLE t2; select ST_AREA(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 31 10, 77 80), POLYGON((0 0,4 7,1 1,0 0)), POINT(20 20))')); ST_AREA(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 31 10, 77 80), POLYGON((0 0,4 7,1 1,0 0)), POINT(20 20))')) 1.5 +select ST_LENGTH(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 100 30, 20 30), POINT(3 3), LINESTRING(20 20, 30 20))')); +ST_LENGTH(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 100 30, 20 30), POINT(3 3), LINESTRING(20 20, 30 20))')) +160 DROP DATABASE IF EXISTS gis_ogs; CREATE DATABASE gis_ogs; USE gis_ogs; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 2eee4bab767..e8fa0e6b994 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -808,6 +808,8 @@ DROP TABLE t2; #bug 850775 ST_AREA does not work on GEOMETRYCOLLECTIONs in maria-5.3-gis select ST_AREA(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 31 10, 77 80), POLYGON((0 0,4 7,1 1,0 0)), POINT(20 20))')); +#bug 855336 ST_LENGTH does not work on GEOMETRYCOLLECTIONs +select ST_LENGTH(ST_GEOMCOLLFROMTEXT(' GEOMETRYCOLLECTION(LINESTRING(100 100, 100 30, 20 30), POINT(3 3), LINESTRING(20 20, 30 20))')); # Conformance tests diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 2c3facb49c8..e490643f88b 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1719,12 +1719,13 @@ double Item_func_glength::val_real() String *swkb= args[0]->val_str(&value); Geometry_buffer buffer; Geometry *geom; + const char *end; null_value= (!swkb || !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) || - geom->geom_length(&res)); + geom->geom_length(&res, &end)); return res; } diff --git a/sql/spatial.cc b/sql/spatial.cc index 95ec4834e96..15dc42441a8 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -518,6 +518,14 @@ int Gis_point::area(double *ar, const char **end) const } +int Gis_point::geom_length(double *len, const char **end) const +{ + *len= 0; + *end= m_data+ POINT_DATA_SIZE; + return 0; +} + + int Gis_point::store_shapes(Gcalc_shape_transporter *trn) const { double x, y; @@ -634,7 +642,7 @@ bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const } -int Gis_line_string::geom_length(double *len) const +int Gis_line_string::geom_length(double *len, const char **end) const { uint32 n_points; double prev_x, prev_y; @@ -659,6 +667,7 @@ int Gis_line_string::geom_length(double *len) const prev_x= x; prev_y= y; } + *end= data; return 0; } @@ -1628,10 +1637,11 @@ int Gis_multi_line_string::geometry_n(uint32 num, String *result) const } -int Gis_multi_line_string::geom_length(double *len) const +int Gis_multi_line_string::geom_length(double *len, const char **end) const { uint32 n_line_strings; const char *data= m_data; + const char *line_end; if (no_data(data, 4)) return 1; @@ -1645,7 +1655,7 @@ int Gis_multi_line_string::geom_length(double *len) const Gis_line_string ls; data+= WKB_HEADER_SIZE; ls.set_data_ptr(data, (uint32) (m_data_end - data)); - if (ls.geom_length(&ls_len)) + if (ls.geom_length(&ls_len, &line_end)) return 1; *len+= ls_len; /* @@ -1654,6 +1664,7 @@ int Gis_multi_line_string::geom_length(double *len) const */ data+= ls.get_data_size(); } + *end= data; return 0; } @@ -2319,7 +2330,7 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const } -int Gis_geometry_collection::area(double *ar, const char **end_of_data) const +int Gis_geometry_collection::area(double *ar, const char **end) const { uint32 n_objects; const char *data= m_data; @@ -2351,12 +2362,50 @@ int Gis_geometry_collection::area(double *ar, const char **end_of_data) const return 1; result+= *ar; } - *end_of_data= data; + *end= data; *ar= result; return 0; } +int Gis_geometry_collection::geom_length(double *len, const char **end) const +{ + uint32 n_objects; + const char *data= m_data; + Geometry_buffer buffer; + Geometry *geom; + double result; + + if (no_data(data, 4)) + return 1; + n_objects= uint4korr(data); + data+= 4; + if (n_objects == 0) + return 1; + + result= 0.0; + while (n_objects--) + { + uint32 wkb_type; + + if (no_data(data, WKB_HEADER_SIZE)) + 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->geom_length(len, &data)) + return 1; + result+= *len; + } + *end= data; + *len= result; + return 0; +} + + int Gis_geometry_collection::num_geometries(uint32 *num) const { if (no_data(m_data, 4)) diff --git a/sql/spatial.h b/sql/spatial.h index cec80b3dacf..d55fc639acc 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -259,7 +259,7 @@ public: virtual bool dimension(uint32 *dim, const char **end) const=0; virtual int get_x(double *x) const { return -1; } virtual int get_y(double *y) const { return -1; } - virtual int geom_length(double *len) const { return -1; } + virtual int geom_length(double *len, const char **end) const { return -1; } virtual int area(double *ar, const char **end) const { return -1;} virtual int is_closed(int *closed) const { return -1; } virtual int num_interior_ring(uint32 *n_int_rings) const { return -1; } @@ -364,6 +364,7 @@ public: return 0; } + int geom_length(double *len, const char **end) const; int area(double *ar, const char **end) const; bool dimension(uint32 *dim, const char **end) const { @@ -388,7 +389,7 @@ public: uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res); bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; - int geom_length(double *len) const; + int geom_length(double *len, const char **end) const; int area(double *ar, const char **end) const; int is_closed(int *closed) const; int num_points(uint32 *n_points) const; @@ -477,7 +478,7 @@ public: bool get_mbr(MBR *mbr, const char **end) const; int num_geometries(uint32 *num) const; int geometry_n(uint32 num, String *result) const; - int geom_length(double *len) const; + int geom_length(double *len, const char **end) const; int is_closed(int *closed) const; bool dimension(uint32 *dim, const char **end) const { @@ -532,6 +533,7 @@ public: bool get_data_as_wkt(String *txt, const char **end) const; bool get_mbr(MBR *mbr, const char **end) const; int area(double *ar, const char **end) const; + int geom_length(double *len, const char **end) const; int num_geometries(uint32 *num) const; int geometry_n(uint32 num, String *result) const; bool dimension(uint32 *dim, const char **end) const; From 5123f59ed2b363ac25fdef374af607f93ec9d762 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 22 Sep 2011 18:53:36 +0500 Subject: [PATCH 27/40] fixed bugs 855485 ST_CROSSES returns different result than PostGIS for overlapping polygons 855487 ST_WITHIN returns wrong result for partially overlapping polygons 855492 ST_WITHIN returns TRUE on point on the edge of a polygon 855497 ST_ENVELOPE of GEOMETRYCOLLECTION EMPTY returns NULL and not GEOMETRYCOLLECTION EMPTY 855503 ST_EQUALS reports TRUE between a POLYGON and a MULTILINESTRING 855505 ST_TOUCHES reports TRUE for intersecting polygon and linestring Changed the way weird functions like Crosses or Touches treated. Added BORDER handling to the Gcalc_function. per-file comments: mysql-test/r/gis-precise.result GIS bugs fixed. test result updated. mysql-test/t/gis-precise.test GIS bugs fixed. test cases added. sql/gcalc_slicescan.h GIS bugs fixed. sql/gcalc_tools.cc GIS bugs fixed. sql/gcalc_tools.h GIS bugs fixed. sql/item_create.cc GIS bugs fixed. sql/item_geofunc.cc GIS bugs fixed. sql/item_geofunc.h GIS bugs fixed. sql/spatial.cc GIS bugs fixed. --- mysql-test/r/gis-precise.result | 94 ++++++++++---- mysql-test/t/gis-precise.test | 36 ++++-- sql/gcalc_slicescan.h | 1 + sql/gcalc_tools.cc | 211 ++++++++++++++++++++++++------- sql/gcalc_tools.h | 60 +++++---- sql/item_create.cc | 6 +- sql/item_geofunc.cc | 213 ++++++++++---------------------- sql/item_geofunc.h | 3 - sql/spatial.cc | 6 + 9 files changed, 372 insertions(+), 258 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 5adecfb5a35..ef621d11e54 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -7,7 +7,7 @@ select 0, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFro 0 0 select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POINT(10 10)')); 1 ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POINT(10 10)')) -1 1 +1 0 select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); 1 ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')) 1 1 @@ -25,48 +25,90 @@ insert into t1 values (GeomFromText('POINT(8 2)')), (GeomFromText('POINT(8 4)')), (GeomFromText('POINT(8 6)')), (GeomFromText('POINT(8 8)')); select astext(g) from t1 where ST_Within(g, GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))')); astext(g) +POINT(2 2) +POINT(2 4) +POINT(2 6) +POINT(2 8) POINT(4 2) POINT(4 4) POINT(4 6) +POINT(4 8) POINT(6 2) POINT(6 4) POINT(6 6) +POINT(6 8) +POINT(8 2) +POINT(8 4) +POINT(8 6) +POINT(8 8) select 'Contains'; Contains Contains select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); astext(g) +POINT(2 2) +POINT(2 4) +POINT(2 6) +POINT(2 8) +POINT(4 2) POINT(4 4) +POINT(4 6) +POINT(4 8) POINT(6 2) POINT(6 4) POINT(6 6) +POINT(6 8) +POINT(8 2) +POINT(8 4) +POINT(8 6) +POINT(8 8) select 'Intersects'; Intersects Intersects select astext(g) from t1 where ST_Intersects(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); astext(g) -POINT(4 4) -POINT(6 2) -POINT(6 4) -POINT(6 6) select 'Contains'; Contains Contains select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); astext(g) +POINT(2 2) +POINT(2 4) +POINT(2 6) +POINT(2 8) +POINT(4 2) POINT(4 4) +POINT(4 6) +POINT(4 8) POINT(6 2) POINT(6 4) POINT(6 6) +POINT(6 8) +POINT(8 2) +POINT(8 4) +POINT(8 6) +POINT(8 8) select 'Contains2'; Contains2 Contains2 select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1), (5.01 3.01, 6 5, 9 5, 8 3, 5.01 3.01))'), g); astext(g) +POINT(2 2) +POINT(2 4) +POINT(2 6) +POINT(2 8) +POINT(4 2) POINT(4 4) +POINT(4 6) +POINT(4 8) POINT(6 2) +POINT(6 4) POINT(6 6) +POINT(6 8) +POINT(8 2) POINT(8 4) +POINT(8 6) +POINT(8 8) DROP TABLE t1; select 0, ST_Within(GeomFromText('LINESTRING(15 15, 50 50, 60 60)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); 0 ST_Within(GeomFromText('LINESTRING(15 15, 50 50, 60 60)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')) @@ -94,7 +136,7 @@ ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('P 1 select ST_contains(GeomFromText('MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)), ((6 6, 6 11, 11 11, 11 6, 6 6)))'), GeomFromText('POINT(5 10)')); ST_contains(GeomFromText('MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)), ((6 6, 6 11, 11 11, 11 6, 6 6)))'), GeomFromText('POINT(5 10)')) -0 +1 select ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 15, 15 15, 15 10, 10 10))')); ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 15, 15 15, 15 10, 10 10))')) 1 @@ -177,10 +219,10 @@ st_touches(geomfromtext('point(0 0)'), geomfromtext('point(1 1)')) 0 select st_touches(geomfromtext('point(1 1)'), geomfromtext('point(1 1)')); st_touches(geomfromtext('point(1 1)'), geomfromtext('point(1 1)')) -1 +0 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)')) -1 +0 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)')) 0 @@ -189,7 +231,7 @@ st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))')) -0 +1 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))')) 1 @@ -319,7 +361,7 @@ PolygonFromText(' POLYGON( ( 2 2 , 3 2 , 3 3 , 2 5 , 2 2 ) ) ') ) ) POLYGON((2 0,2 5,3 3,3 2,7 5,2 0)) SELECT AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), GeometryFromText('LINESTRING(3 3, 4 4)'))); AsText(ST_INTERSECTION(LinestringFromText('LINESTRING(1 1, 2 2)'), GeometryFromText('LINESTRING(3 3, 4 4)'))) -GEOMETRYCOLLECTION() +GEOMETRYCOLLECTION EMPTY SELECT AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 5, 2 5, 2 4, 3 4, 3 5))'))); AsText(ST_UNION(GEOMETRYFROMTEXT('POINT(8 1)') ,MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 5, 2 5, 2 4, 3 4, 3 5))'))) GEOMETRYCOLLECTION(POINT(8 1),LINESTRING(2 4,2 5,3 5,3 4,2 4)) @@ -355,17 +397,6 @@ ST_NUMGEOMETRIES(ST_DIFFERENCE ( ST_UNION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 4 , 5 0 , 2 9 , 6 2 , 0 2 ) , ( 4 3 , 5 6 , 9 4 , 0 7 , 7 2 , 2 0 , 8 2 ) , ( 5 0 , 1 5 , 3 7 , 7 7 ) , ( 2 3 , 9 5 , 2 0 , 8 1 ) , ( 0 9 , 9 3 , 2 8 , 8 1 , 9 4 ) 123 -SELECT ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER ( -ST_UNION ( -MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 7 3 , 1 8 , 4 0 , 7 9 ) , ( 5 4 , 9 8 , 7 4 , 3 7 ) , ( 5 8 , 5 4 , 9 2 , 5 6 ) , ( 4 0 , 3 2 , 0 1 , 3 9 ) , ( 2 0 , 3 5 , 9 5 , 0 9 ) ) ' ) , -MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 4 5 , 3 0 , 3 1 , 4 7 , 4 2 ) , ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) -) , 1 -))); -ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER ( -ST_UNION ( -MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 7 3 , 1 8 , 4 0 , 7 9 ) , ( 5 4 , 9 8 , 7 4 , 3 7 ) , ( 5 8 , 5 4 , 9 2 , 5 6 ) , ( 4 0 , 3 2 , 0 1 , 3 9 ) , ( 2 0 , 3 5 , 9 5 , 0 9 ) ) ' ) , -MULTILINESTRI -653 SELECT ASTEXT(ST_DIFFERENCE ( POLYGONFROMTEXT( ' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) , ST_UNION ( @@ -414,9 +445,24 @@ NULL SELECT ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) , ( ( 0 0 , 3 8 , 9 4 , 0 0 ) ) ) ' ) ), MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) ) ; ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , NULL -SELECT ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 , 7 2 , 3 4 ) ' ) , ST_BUFFER ( ST_UNION ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 6 2 , 1 3 , 2 2 , 2 2 ) ) ) ' ) , GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 1 4 , 9 9 , 3 0 , 6 6 ) , ( 3 5 , 1 0 , 5 8 , 6 1 ) , ( 8 9 , 6 1 , 5 1 , 6 2 ) , ( 2 2 , 7 5 , 5 8 , 6 9 , 3 0 ) , ( 8 0 , 8 4 , 6 7 , 5 5 ) ) ' ) ) , NUMPOINTS( EXTERIORRING( POLYGONFROMTEXT( ' POLYGON( ( 0 0 , 2 1 , 8 2 , 0 0 ) ) ' ) ) ) ) ) ) , ST_INTERSECTION ( POLYGONFROMTEXT( ' POLYGON( ( 2 3, 5 7 , 3 7 , 4 1 , 0 5, 2 3 ) ) ' ) , MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 3 , 1 4 , 6 4 , 9 1 , 3 4 , 1 8 ) , ( 9 9 , 0 3 , 1 7 , 9 9 ) ) ' ) ) ) , POLYGONFROMTEXT( ' POLYGON( ( 1 3, 7 2 , 1 5 , 3 8 , 5 0, 1 3) ) ' ) ) ) ; -ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 -25 SELECT ASTEXT(ST_INTERSECTION( GEOMETRYFROMTEXT('GEOMETRYCOLLECTION(LINESTRING(7 7,5.33333333333333 7),LINESTRING(5.33333333333333 7,0 7,5 8,5.33333333333333 7),LINESTRING(5.33333333333333 7,7 2,7 7),POLYGON((0 5,3 5,3 2,1 2,1 1,3 1,3 0,0 0,0 3,2 3,2 4,0 4,0 5)))'), geomETRYFROMTEXT(' MULTILINESTRING( ( 5 1 , 3 7 , 6 1 , 7 0 ) , ( 1 6 , 8 5 , 7 5 , 5 6 ) )') )); ASTEXT(ST_INTERSECTION( GEOMETRYFROMTEXT('GEOMETRYCOLLECTION(LINESTRING(7 7,5.33333333333333 7),LINESTRING(5.33333333333333 7,0 7,5 8,5.33333333333333 7),LINESTRING(5.33333333333333 7,7 2,7 7),POLYGON((0 5,3 5,3 2,1 2,1 1,3 1,3 0,0 0,0 3,2 3,2 4,0 4,0 5)) MULTIPOINT(7 5,7 5.14285714285714,5.9 5.3,5.8 5.6,3 7) +SELECT ST_CROSSES( GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 4, 2 5, 3 5) ) ') , POLYGONFROMTEXT(' POLYGON((2 4,3 4,3 5,2 5,2 4)) ')); +ST_CROSSES( GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 4, 2 5, 3 5) ) ') , POLYGONFROMTEXT(' POLYGON((2 4,3 4,3 5,2 5,2 4)) ')) +0 +SELECT ST_WITHIN( POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 2 0 , 1 0, 2 4 , 0 4, 0 5) ) ') , POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 1 4 , 1 3 , 3 3 , 3 0 , 0 0 , 0 5), ( 1 1 , 2 1 , 2 2 , 1 2 , 1 1 ) ) ') ); +ST_WITHIN( POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 2 0 , 1 0, 2 4 , 0 4, 0 5) ) ') , POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 1 4 , 1 3 , 3 3 , 3 0 , 0 0 , 0 5), ( 1 1 , 2 1 , 2 2 , 1 2 , 1 1 ) ) ') ) +0 +SELECT ST_WITHIN( POINTFROMTEXT(' POINT(1 2 ) ') , MULTIPOLYGONFROMTEXT(' MULTIPOLYGON( ( (0 5, 3 5, 3 0, 0 0, 0 5), ( 1 1 , 2 1 , 2 4, 1 4, 1 1 ) ) ) ')); +ST_WITHIN( POINTFROMTEXT(' POINT(1 2 ) ') , MULTIPOLYGONFROMTEXT(' MULTIPOLYGON( ( (0 5, 3 5, 3 0, 0 0, 0 5), ( 1 1 , 2 1 , 2 4, 1 4, 1 1 ) ) ) ')) +1 +select ST_ASTEXT(envelope(ST_GEOMCOLLFROMTEXT('GEOMETRYCOLLECTION EMPTY'))); +ST_ASTEXT(envelope(ST_GEOMCOLLFROMTEXT('GEOMETRYCOLLECTION EMPTY'))) +NULL +SELECT ST_EQUALS( GEOMETRYFROMTEXT(' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') , GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') ); +ST_EQUALS( GEOMETRYFROMTEXT(' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') , GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') ) +0 +SELECT ST_TOUCHES( GEOMETRYFROMTEXT(' LINESTRING( 1 1 , 1 4 , 5 0 , 8 3 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ') ); +ST_TOUCHES( GEOMETRYFROMTEXT(' LINESTRING( 1 1 , 1 4 , 5 0 , 8 3 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ') ) +0 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 8e630766004..bf5c48d11f6 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -237,14 +237,6 @@ SELECT ST_NUMGEOMETRIES(ST_DIFFERENCE ( )); -#bug 841638 Assertion `!m_prev || m_prev->x != x || m_prev->y != y' failed in Gcalc_shape_transporter::int_add_point in maria-5.3-gis -SELECT ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER ( - ST_UNION ( - MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 7 3 , 1 8 , 4 0 , 7 9 ) , ( 5 4 , 9 8 , 7 4 , 3 7 ) , ( 5 8 , 5 4 , 9 2 , 5 6 ) , ( 4 0 , 3 2 , 0 1 , 3 9 ) , ( 2 0 , 3 5 , 9 5 , 0 9 ) ) ' ) , - MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 4 5 , 3 0 , 3 1 , 4 7 , 4 2 ) , ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) - ) , 1 -))); - #bug 841745 ssertion `!sp0->is_bottom()' failed in Gcalc_scan_iterator::find_intersections in maria-5.3-gis SELECT ASTEXT(ST_DIFFERENCE ( POLYGONFROMTEXT( ' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) , @@ -279,10 +271,30 @@ SELECT ST_BUFFER ( ) ; SELECT ST_DISTANCE ( ST_DIFFERENCE ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) ' ) , MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) , ( ( 0 0 , 3 8 , 9 4 , 0 0 ) ) ) ' ) ), MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( (3 5, 2 4, 2 5, 3 5) ) , ( (3 5, 2 5, 2 4, 3 4, 3 5) ) , ( ( 0 0 , 8 3 , 9 5 , 0 0 ) ) ) ' ) ) ; -#bug 848901 Assertion `fabs(cur_isc->x-m_cur_intersection->x) + fabs(cur_isc->y-m_cur_intersection->y) < 0.000000000001' failed in Gcalc_scan_iterator::intersection_scan() in maria-5.3-gis - -SELECT ST_NUMGEOMETRIES( ST_SYMDIFFERENCE ( ST_SYMDIFFERENCE ( ST_INTERSECTION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 6 4 , 3 7 , 9 4 , 3 8 ) , ( 2 2 , 2 9 , 1 2 , 9 8 ) ) ' ) , ST_SYMDIFFERENCE ( MULTIPOINTFROMTEXT( ' MULTIPOINT( 6 1 , 3 8 , 3 3 , 0 6 , 7 2 , 3 4 ) ' ) , ST_BUFFER ( ST_UNION ( MULTIPOLYGONFROMTEXT( ' MULTIPOLYGON( ( ( 2 2 , 6 2 , 1 3 , 2 2 , 2 2 ) ) ) ' ) , GEOMETRYFROMTEXT( ' MULTILINESTRING( ( 1 4 , 9 9 , 3 0 , 6 6 ) , ( 3 5 , 1 0 , 5 8 , 6 1 ) , ( 8 9 , 6 1 , 5 1 , 6 2 ) , ( 2 2 , 7 5 , 5 8 , 6 9 , 3 0 ) , ( 8 0 , 8 4 , 6 7 , 5 5 ) ) ' ) ) , NUMPOINTS( EXTERIORRING( POLYGONFROMTEXT( ' POLYGON( ( 0 0 , 2 1 , 8 2 , 0 0 ) ) ' ) ) ) ) ) ) , ST_INTERSECTION ( POLYGONFROMTEXT( ' POLYGON( ( 2 3, 5 7 , 3 7 , 4 1 , 0 5, 2 3 ) ) ' ) , MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 3 , 1 4 , 6 4 , 9 1 , 3 4 , 1 8 ) , ( 9 9 , 0 3 , 1 7 , 9 9 ) ) ' ) ) ) , POLYGONFROMTEXT( ' POLYGON( ( 1 3, 7 2 , 1 5 , 3 8 , 5 0, 1 3) ) ' ) ) ) ; - #bug 848939 Wrong result with ST_INTERSECTION between linestrings and a polygon in 5.3-gis SELECT ASTEXT(ST_INTERSECTION( GEOMETRYFROMTEXT('GEOMETRYCOLLECTION(LINESTRING(7 7,5.33333333333333 7),LINESTRING(5.33333333333333 7,0 7,5 8,5.33333333333333 7),LINESTRING(5.33333333333333 7,7 2,7 7),POLYGON((0 5,3 5,3 2,1 2,1 1,3 1,3 0,0 0,0 3,2 3,2 4,0 4,0 5)))'), geomETRYFROMTEXT(' MULTILINESTRING( ( 5 1 , 3 7 , 6 1 , 7 0 ) , ( 1 6 , 8 5 , 7 5 , 5 6 ) )') )); +#bug 855485 ST_CROSSES returns different result than PostGIS for overlapping polygons + +SELECT ST_CROSSES( GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 4, 2 5, 3 5) ) ') , POLYGONFROMTEXT(' POLYGON((2 4,3 4,3 5,2 5,2 4)) ')); + +#bug 855487 ST_WITHIN returns wrong result for partially overlapping polygons + +SELECT ST_WITHIN( POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 2 0 , 1 0, 2 4 , 0 4, 0 5) ) ') , POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 1 4 , 1 3 , 3 3 , 3 0 , 0 0 , 0 5), ( 1 1 , 2 1 , 2 2 , 1 2 , 1 1 ) ) ') ); + +#bug 855492 ST_WITHIN returns TRUE on point on the edge of a polygon + +SELECT ST_WITHIN( POINTFROMTEXT(' POINT(1 2 ) ') , MULTIPOLYGONFROMTEXT(' MULTIPOLYGON( ( (0 5, 3 5, 3 0, 0 0, 0 5), ( 1 1 , 2 1 , 2 4, 1 4, 1 1 ) ) ) ')); + +#bug 855497 ST_ENVELOPE of GEOMETRYCOLLECTION EMPTY returns NULL and not GEOMETRYCOLLECTION EMPTY + +select ST_ASTEXT(envelope(ST_GEOMCOLLFROMTEXT('GEOMETRYCOLLECTION EMPTY'))); + +#bug 855503 ST_EQUALS reports TRUE between a POLYGON and a MULTILINESTRING + +SELECT ST_EQUALS( GEOMETRYFROMTEXT(' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') , GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') ); + +#bug 855505 ST_TOUCHES reports TRUE for intersecting polygon and linestring + +SELECT ST_TOUCHES( GEOMETRYFROMTEXT(' LINESTRING( 1 1 , 1 4 , 5 0 , 8 3 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ') ); + diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index d1c81ca4648..fe7959c4172 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -307,6 +307,7 @@ public: virtual int complete_ring()=0; virtual int add_point(double x, double y)=0; virtual int start_collection(int n_objects) { return 0; } + virtual int empty_shape() { return 0; } int start_simple_poly() { return start_poly() || start_ring(); diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 90c39f08d0b..6a2fdbccacb 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -43,7 +43,7 @@ gcalc_shape_info Gcalc_function::add_new_shape(uint32 shape_id, in prefix style. */ -void Gcalc_function::add_operation(op_type operation, uint32 n_operands) +void Gcalc_function::add_operation(uint operation, uint32 n_operands) { uint32 op_code= (uint32 ) operation + n_operands; function_buffer.q_append(op_code); @@ -84,6 +84,15 @@ int Gcalc_function::single_shape_op(shape_type shape_kind, gcalc_shape_info *si) } +int Gcalc_function::repeat_expression(uint32 exp_pos) +{ + if (reserve_op_buffer(1)) + return 1; + add_operation(op_repeat, exp_pos); + return 0; +} + + /* Specify how many arguments we're going to have. */ @@ -109,42 +118,61 @@ int Gcalc_function::alloc_states() if (function_buffer.reserve((n_shapes+1) * 2 * sizeof(int))) return 1; i_states= (int *) (function_buffer.ptr() + ALIGN_SIZE(function_buffer.length())); - saved_i_states= i_states + (n_shapes + 1); + b_states= i_states + (n_shapes + 1); return 0; } -void Gcalc_function::save_states() +int Gcalc_function::count_internal(const char *cur_func, uint set_type, + const char **end) { - memcpy(saved_i_states, i_states, (n_shapes+1) * sizeof(int)); -} - - -void Gcalc_function::restore_states() -{ - memcpy(i_states, saved_i_states, (n_shapes+1) * sizeof(int)); -} - - -int Gcalc_function::count_internal() -{ - int c_op= uint4korr(cur_func); + uint c_op= uint4korr(cur_func); op_type next_func= (op_type) (c_op & op_any); int mask= (c_op & op_not) ? 1:0; - int n_ops= c_op & ~op_any; + uint n_ops= c_op & ~(op_any | op_not | v_mask); + uint n_shape= c_op & ~(op_any | op_not | v_mask); /* same as n_ops */ + value v_state= (value) (c_op & v_mask); int result; + const char *sav_cur_func= cur_func; cur_func+= 4; if (next_func == op_shape) - return i_states[c_op & ~(op_any | op_not)] ^ mask; + { + if (set_type == 0) + result= i_states[n_shape] | b_states[n_shape]; + else if (set_type == op_border) + result= b_states[n_shape]; + else if (set_type == op_internals) + result= i_states[n_shape] && !b_states[n_shape]; + goto exit; + } + + if (next_func == op_false) + { + result= 0; + goto exit; + } + + if (next_func == op_border || next_func == op_internals) + { + result= count_internal(cur_func, next_func, &cur_func); + goto exit; + } + + if (next_func == op_repeat) + { + result= count_internal(function_buffer.ptr() + n_ops, set_type, 0); + goto exit; + } + if (n_ops == 0) return mask; - result= count_internal(); + result= count_internal(cur_func, set_type, &cur_func); while (--n_ops) { - int next_res= count_internal(); + int next_res= count_internal(cur_func, set_type, &cur_func); switch (next_func) { case op_union: @@ -159,15 +187,59 @@ int Gcalc_function::count_internal() case op_difference: result= result & !next_res; break; - case op_backdifference: - result= !result & next_res; - break; default: DBUG_ASSERT(FALSE); }; } - return result ^ mask; +exit: + result^= mask; + if (v_state != v_empty) + { + switch (v_state) + { + case v_find_t: + if (result) + { + c_op= (c_op & ~v_mask) | v_t_found; + int4store(sav_cur_func, c_op); + }; + break; + case v_find_f: + if (!result) + { + c_op= (c_op & ~v_mask) | v_f_found; + int4store(sav_cur_func, c_op); + }; + break; + case v_t_found: + result= 1; + break; + case v_f_found: + result= 0; + break; + default: + DBUG_ASSERT(0); + }; + } + + if (end) + *end= cur_func; + return result; +} + + +void Gcalc_function::clear_i_states() +{ + for (uint i= 0; i < n_shapes; i++) + i_states[i]= 0; +} + + +void Gcalc_function::clear_b_states() +{ + for (uint i= 0; i < n_shapes; i++) + b_states[i]= 0; } @@ -183,7 +255,7 @@ void Gcalc_function::reset() } -int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it) +int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) { const Gcalc_scan_iterator::point *eq_start, *cur_eq, *events; @@ -194,31 +266,58 @@ int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it) events= scan_it.get_events(); /* these kinds of events don't change the function */ - if (events->simple_event()) - continue; - Gcalc_point_iterator pit(&scan_it); - clear_state(); + clear_b_states(); + clear_i_states(); /* Walk to the event, marking polygons we met */ for (; pit.point() != scan_it.get_event_position(); ++pit) { gcalc_shape_info si= pit.point()->get_shape(); if ((get_shape_kind(si) == Gcalc_function::shape_polygon)) - invert_state(si); + invert_i_state(si); } - save_states(); + if (events->simple_event()) + { + if (events->event == scev_end) + set_b_state(events->get_shape()); + + if (count()) + return 1; + clear_b_states(); + continue; + } + /* Check the status of the event point */ for (; events; events= events->get_next()) - set_on_state(events->get_shape()); + { + gcalc_shape_info si= events->get_shape(); + if (events->event == scev_thread || + events->event == scev_end || + (get_shape_kind(si) == Gcalc_function::shape_polygon)) + set_b_state(si); + else if (get_shape_kind(si) == Gcalc_function::shape_line) + invert_i_state(si); + } if (count()) return 1; + /* Set back states changed in the loop above. */ + for (events= scan_it.get_events(); events; events= events->get_next()) + { + gcalc_shape_info si= events->get_shape(); + if (events->event == scev_thread || + events->event == scev_end || + (get_shape_kind(si) == Gcalc_function::shape_polygon)) + clear_b_state(si); + else if (get_shape_kind(si) == Gcalc_function::shape_line) + invert_i_state(si); + } + if (scan_it.get_event_position() == scan_it.get_event_end()) continue; /* Check the status after the event */ - restore_states(); eq_start= pit.point(); do { @@ -226,18 +325,28 @@ int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it) if (pit.point() != scan_it.get_event_end() && eq_start->cmp_dx_dy(pit.point()) == 0) continue; - save_states(); for (cur_eq= eq_start; cur_eq != pit.point(); cur_eq= cur_eq->get_next()) - set_on_state(cur_eq->get_shape()); + { + gcalc_shape_info si= cur_eq->get_shape(); + if (get_shape_kind(si) == Gcalc_function::shape_polygon) + set_b_state(si); + else + invert_i_state(si); + } if (count()) return 1; - restore_states(); + for (cur_eq= eq_start; cur_eq != pit.point(); cur_eq= cur_eq->get_next()) { gcalc_shape_info si= cur_eq->get_shape(); if ((get_shape_kind(si) == Gcalc_function::shape_polygon)) - invert_state(si); + { + clear_b_state(si); + invert_i_state(si); + } + else + invert_i_state(cur_eq->get_shape()); } if (count()) return 1; @@ -313,6 +422,15 @@ int Gcalc_operation_transporter::start_collection(int n_objects) } +int Gcalc_operation_transporter::empty_shape() +{ + if (m_fn->reserve_op_buffer(1)) + return 1; + m_fn->add_operation(Gcalc_function::op_false, 0); + return 0; +} + + int Gcalc_result_receiver::start_shape(Gcalc_function::shape_type shape) { if (buffer.reserve(4*2, 512)) @@ -661,7 +779,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) if (ca_counter == 11522) call_checkpoint(89); #endif /*NO_TESTING*/ - m_fn->clear_state(); + m_fn->clear_i_states(); /* Walk to the event, remembering what is needed. */ #ifndef NO_TESTING if (si->get_event_position() == pi.point()) @@ -678,7 +796,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) prev_range= prev_state ? cur_t : 0; } if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon) - m_fn->invert_state(pi.get_shape()); + m_fn->invert_i_state(pi.get_shape()); } events= si->get_events(); @@ -800,6 +918,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) eq_start= pi.point(); eq_thread= point_thread= *starting_t_hook; + m_fn->clear_b_states(); while (eq_start != si->get_event_end()) { const Gcalc_scan_iterator::point *cur_eq; @@ -812,17 +931,16 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) eq_start->cmp_dx_dy(pi.point()) == 0) continue; - m_fn->save_states(); for (cur_eq= eq_start; cur_eq != pi.point(); cur_eq= cur_eq->get_next()) - m_fn->set_on_state(cur_eq->get_shape()); + m_fn->set_b_state(cur_eq->get_shape()); in_state= m_fn->count(); - m_fn->restore_states(); + m_fn->clear_b_states(); for (cur_eq= eq_start; cur_eq != pi.point(); cur_eq= cur_eq->get_next()) { gcalc_shape_info si= cur_eq->get_shape(); if ((m_fn->get_shape_kind(si) == Gcalc_function::shape_polygon)) - m_fn->invert_state(si); + m_fn->invert_i_state(si); } after_state= m_fn->count(); if (prev_state != after_state) @@ -844,14 +962,15 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) if (!sav_prev_state && !m_poly_borders && !m_lines) { /* Check if we need to add the event point itself */ - m_fn->clear_state(); + m_fn->clear_i_states(); + /* b_states supposed to be clean already */ for (pi.restart(si); pi.point() != si->get_event_position(); ++pi) { if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon) - m_fn->invert_state(pi.get_shape()); + m_fn->invert_i_state(pi.get_shape()); } for (events= si->get_events(); events; events= events->get_next()) - m_fn->set_on_state(events->get_shape()); + m_fn->set_b_state(events->get_shape()); return m_fn->count() ? add_single_point(si) : 0; } diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index 39704dfeb56..5e98d46a90f 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -43,23 +43,35 @@ class Gcalc_function private: String shapes_buffer; String function_buffer; - const char *cur_func; int *i_states; - int *saved_i_states; + int *b_states; uint32 cur_object_id; uint n_shapes; - int count_internal(); + int count_internal(const char *cur_func, uint set_type, + const char **end); public: + enum value + { + v_empty= 0x0000000, + v_find_t= 0x1000000, + v_find_f= 0x2000000, + v_t_found= 0x3000000, + v_f_found= 0x4000000, + v_mask= 0x7000000 + }; enum op_type { - op_shape= 0, - op_not= 0x80000000, - op_union= 0x10000000, - op_intersection= 0x20000000, + op_not= 0x80000000, + op_shape= 0x00000000, + op_union= 0x10000000, + op_intersection= 0x20000000, op_symdifference= 0x30000000, - op_difference= 0x40000000, - op_backdifference= 0x50000000, - op_any= 0x70000000 + op_difference= 0x40000000, + op_repeat= 0x50000000, + op_border= 0x60000000, + op_internals= 0x70000000, + op_false= 0x08000000, + op_any= 0x78000000 /* The mask to get any of the operations */ }; enum shape_type { @@ -75,10 +87,11 @@ public: Also adds the shape to the list of operands. */ int single_shape_op(shape_type shape_kind, gcalc_shape_info *si); - void add_operation(op_type operation, uint32 n_operands); + void add_operation(uint operation, uint32 n_operands); void add_not_operation(op_type operation, uint32 n_operands); - uint32 get_next_operation_pos() { return function_buffer.length(); } + uint32 get_next_expression_pos() { return function_buffer.length(); } void add_operands_to_op(uint32 operation_pos, uint32 n_operands); + int repeat_expression(uint32 exp_pos); void set_cur_obj(uint32 cur_obj) { cur_object_id= cur_obj; } int reserve_shape_buffer(uint n_shapes); int reserve_op_buffer(uint n_ops); @@ -90,20 +103,20 @@ public: void set_states(int *shape_states) { i_states= shape_states; } int alloc_states(); - void invert_state(gcalc_shape_info shape) { i_states[shape]^= 1; } - void set_on_state(gcalc_shape_info shape) { i_states[shape]= 1; } - int get_state(gcalc_shape_info shape) { return i_states[shape]; } - void save_states(); - void restore_states(); + void invert_i_state(gcalc_shape_info shape) { i_states[shape]^= 1; } + void set_b_state(gcalc_shape_info shape) { b_states[shape]= 1; } + void clear_b_state(gcalc_shape_info shape) { b_states[shape]= 0; } + int get_state(gcalc_shape_info shape) + { return i_states[shape] | b_states[shape]; } + int get_i_state(gcalc_shape_info shape) { return i_states[shape]; } + int get_b_state(gcalc_shape_info shape) { return b_states[shape]; } int count() - { - cur_func= function_buffer.ptr(); - return count_internal(); - } - void clear_state() { bzero(i_states, n_shapes * sizeof(int)); } + { return count_internal(function_buffer.ptr(), 0, 0); } + void clear_i_states(); + void clear_b_states(); void reset(); - int find_function(Gcalc_scan_iterator &scan_it); + int check_function(Gcalc_scan_iterator &scan_it); }; @@ -132,6 +145,7 @@ public: int complete_ring(); int add_point(double x, double y); int start_collection(int n_objects); + int empty_shape(); }; diff --git a/sql/item_create.cc b/sql/item_create.cc index 2a8f7eec52a..626f0c5d91e 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -5144,7 +5144,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ENCRYPT") }, BUILDER(Create_func_encrypt)}, { { C_STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)}, { { C_STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)}, - { { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)}, + { { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)}, { { C_STRING_WITH_LEN("EXP") }, BUILDER(Create_func_exp)}, { { C_STRING_WITH_LEN("EXPORT_SET") }, BUILDER(Create_func_export_set)}, { { C_STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)}, @@ -5283,7 +5283,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ST_DISTANCE") }, GEOM_BUILDER(Create_func_distance)}, { { C_STRING_WITH_LEN("ST_ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)}, { { C_STRING_WITH_LEN("ST_ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)}, - { { C_STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)}, + { { C_STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)}, { { C_STRING_WITH_LEN("ST_EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)}, { { C_STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { C_STRING_WITH_LEN("ST_GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, @@ -5323,7 +5323,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)}, { { C_STRING_WITH_LEN("ST_TOUCHES") }, GEOM_BUILDER(Create_func_touches)}, { { C_STRING_WITH_LEN("ST_UNION") }, GEOM_BUILDER(Create_func_union)}, - { { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_mbr_within)}, + { { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)}, { { C_STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)}, { { C_STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)}, { { C_STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)}, diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index e490643f88b..4db8ee02d7f 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -660,6 +660,7 @@ 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) { @@ -786,139 +787,11 @@ exit: mem_error: DBUG_RETURN(1); } +#endif /*TMP_BLOCK*/ #define GIS_ZERO 0.00000000001 -int Item_func_spatial_rel::func_touches() -{ - bool above_cur_point; - double x1, x2, y1, y2, ex, ey; - double distance, area; - int result= 0; - int cur_func= 0; - - Gcalc_operation_transporter trn(&func, &collector); - - String *res1= args[0]->val_str(&tmp_value1); - String *res2= args[1]->val_str(&tmp_value2); - Geometry_buffer buffer1, buffer2; - Geometry *g1, *g2; - int obj2_si; - - DBUG_ENTER("Item_func_spatial_rel::func_touches"); - DBUG_ASSERT(fixed == 1); - - 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()))))) - goto mem_error; - - if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) && - (g2->get_class_info()->m_type_id == Geometry::wkb_point)) - { - if (((Gis_point *) g1)->get_xy(&x1, &y1) || - ((Gis_point *) g2)->get_xy(&x2, &y2)) - goto mem_error; - ex= x2 - x1; - ey= y2 - y1; - DBUG_RETURN((ex * ex + ey * ey) < GIS_ZERO); - } - - if (func.reserve_op_buffer(1)) - goto mem_error; - func.add_operation(Gcalc_function::op_intersection, 2); - - if (g1->store_shapes(&trn)) - goto mem_error; - obj2_si= func.get_nshapes(); - - if (g2->store_shapes(&trn) || func.alloc_states()) - goto mem_error; - - collector.prepare_operation(); - scan_it.init(&collector); - - if (calc_distance(&distance, &collector, obj2_si, &func, &scan_it)) - goto mem_error; - if (distance > GIS_ZERO) - goto exit; - - scan_it.reset(); - scan_it.init(&collector); - - above_cur_point= false; - distance= DBL_MAX; - - while (scan_it.more_trapezoids()) - { - if (scan_it.step()) - goto mem_error; - - func.clear_state(); - for (Gcalc_trapezoid_iterator ti(&scan_it); ti.more(); ++ti) - { - gcalc_shape_info si= ti.lb()->get_shape(); - if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon)) - { - func.invert_state(si); - cur_func= func.count(); - } - if (cur_func) - { - area= scan_it.get_h() * - ((scan_it.get_sp_x(ti.rb()) - scan_it.get_sp_x(ti.lb())) + - (scan_it.get_sp_x(ti.rt()) - scan_it.get_sp_x(ti.lt()))); - if (area > GIS_ZERO) - { - result= 0; - goto exit; - } - } - } - } - result= 1; - -exit: - collector.reset(); - func.reset(); - scan_it.reset(); - DBUG_RETURN(result); -mem_error: - null_value= 1; - DBUG_RETURN(0); -} - - -int Item_func_spatial_rel::func_equals() -{ - Gcalc_heap::Info *pi_s1, *pi_s2; - Gcalc_heap::Info *cur_pi= collector.get_first(); - double d; - - if (!cur_pi) - return 1; - - do { - pi_s1= cur_pi; - pi_s2= 0; - while ((cur_pi= cur_pi->get_next())) - { - d= fabs(pi_s1->x - cur_pi->x) + fabs(pi_s1->y - cur_pi->y); - if (d > GIS_ZERO) - break; - if (!pi_s2 && pi_s1->shape != cur_pi->shape) - pi_s2= cur_pi; - } - - if (!pi_s2) - return 0; - } while (cur_pi); - - return 1; -} - - longlong Item_func_spatial_rel::val_int() { DBUG_ENTER("Item_func_spatial_rel::val_int"); @@ -929,9 +802,7 @@ longlong Item_func_spatial_rel::val_int() Geometry *g1, *g2; int result= 0; int mask= 0; - - if (spatial_rel == SP_TOUCHES_FUNC) - DBUG_RETURN(func_touches()); + uint shape_a, shape_b; res1= args[0]->val_str(&tmp_value1); res2= args[1]->val_str(&tmp_value2); @@ -940,56 +811,103 @@ longlong Item_func_spatial_rel::val_int() if (func.reserve_op_buffer(1)) DBUG_RETURN(0); + 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()))))) + goto exit; + switch (spatial_rel) { case SP_CONTAINS_FUNC: mask= 1; - func.add_operation(Gcalc_function::op_backdifference, 2); + 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: 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: + mask= 1; + func.add_operation(Gcalc_function::op_symdifference, 2); + null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; case SP_DISJOINT_FUNC: mask= 1; func.add_operation(Gcalc_function::op_intersection, 2); + null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; case SP_INTERSECTS_FUNC: func.add_operation(Gcalc_function::op_intersection, 2); + null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn); break; case SP_OVERLAPS_FUNC: - func.add_operation(Gcalc_function::op_backdifference, 2); - break; case SP_CROSSES_FUNC: func.add_operation(Gcalc_function::op_intersection, 2); + func.add_operation(Gcalc_function::v_find_t | + Gcalc_function::op_intersection, 2); + shape_a= func.get_next_expression_pos(); + if ((null_value= g1->store_shapes(&trn))) + break; + shape_b= func.get_next_expression_pos(); + if ((null_value= g2->store_shapes(&trn))) + break; + func.add_operation(Gcalc_function::v_find_t | + Gcalc_function::op_intersection, 2); + func.add_operation(Gcalc_function::v_find_t | + Gcalc_function::op_difference, 2); + func.repeat_expression(shape_a); + func.repeat_expression(shape_b); + func.add_operation(Gcalc_function::v_find_t | + Gcalc_function::op_difference, 2); + func.repeat_expression(shape_b); + func.repeat_expression(shape_a); + break; + case SP_TOUCHES_FUNC: + func.add_operation(Gcalc_function::op_intersection, 2); + func.add_operation(Gcalc_function::v_find_f | + Gcalc_function::op_not | + Gcalc_function::op_intersection, 2); + func.add_operation(Gcalc_function::op_internals, 1); + shape_a= func.get_next_expression_pos(); + if ((null_value= g1->store_shapes(&trn))) + break; + func.add_operation(Gcalc_function::op_internals, 1); + shape_b= func.get_next_expression_pos(); + if ((null_value= g2->store_shapes(&trn))) + break; + func.add_operation(Gcalc_function::v_find_t | + Gcalc_function::op_intersection, 2); + func.add_operation(Gcalc_function::op_border, 1); + func.repeat_expression(shape_a); + func.add_operation(Gcalc_function::op_border, 1); + func.repeat_expression(shape_b); break; default: DBUG_ASSERT(FALSE); break; } - - 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)))) + if (null_value) goto exit; collector.prepare_operation(); scan_it.init(&collector); +#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; - result= func.find_function(scan_it) ^ mask; + result= func.check_function(scan_it) ^ mask; exit: collector.reset(); @@ -1307,7 +1225,7 @@ int Item_func_buffer::Transporter::start_line() if (m_fn->reserve_op_buffer(2)) return 1; - last_shape_pos= m_fn->get_next_operation_pos(); + last_shape_pos= m_fn->get_next_expression_pos(); m_fn->add_operation(buffer_op, 0); m_npoints= 0; int_start_line(); @@ -1321,7 +1239,7 @@ int Item_func_buffer::Transporter::start_poly() if (m_fn->reserve_op_buffer(2)) return 1; - last_shape_pos= m_fn->get_next_operation_pos(); + last_shape_pos= m_fn->get_next_expression_pos(); m_fn->add_operation(buffer_op, 0); return Gcalc_operation_transporter::start_poly(); } @@ -1827,19 +1745,20 @@ double Item_func_distance::val_real() of objects scev_thread | scev_two_threads | scev_single_point */ - func.clear_state(); + func.clear_i_states(); 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_i_state(si); } + func.clear_b_states(); for (; ev; ev= ev->get_next()) { if (ev->event != scev_intersection) cur_point= ev->pi; - func.set_on_state(ev->get_shape()); + func.set_b_state(ev->get_shape()); if (func.count()) { /* Point of one object is inside the other - intersection found */ diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index d5ed2c1f764..b4e495f39a8 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -251,9 +251,6 @@ public: void fix_length_and_dec() { maybe_null= 1; } bool is_null() { (void) val_int(); return null_value; } -protected: - int func_touches(); - int func_equals(); }; diff --git a/sql/spatial.cc b/sql/spatial.cc index 15dc42441a8..d18600dd7de 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -2519,6 +2519,12 @@ int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn) const n_objects= uint4korr(data); data+= 4; + if (!n_objects) + { + trn->empty_shape(); + return 0; + } + if (trn->start_collection(n_objects)) return 1; From 53ad390ff098cf6a1ef471128770b01219890058 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 23 Sep 2011 15:05:36 +0500 Subject: [PATCH 28/40] fix for 857050 ST_WITHIN returns wrong result with MULTIPOINT and POLYGON return GEOMETRYCOLLECTION EMPTY, not NULL for the query per-file comments: mysql-test/r/gis.result fix for 857050 ST_WITHIN returns wrong result with MULTIPOINT and POLYGON test result updated. sql/spatial.cc fix for 857050 ST_WITHIN returns wrong result with MULTIPOINT and POLYGON return of the Geometry::envelope() changed for the empty geometry. --- mysql-test/r/gis.result | 38 +++++++++++++++++++------------------- sql/spatial.cc | 13 +++++++++++-- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 7f54e088cf8..b7e5ccd6c53 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -236,8 +236,8 @@ fid AsText(Envelope(g)) 119 POLYGON((0 0,3 0,3 3,0 3,0 0)) 120 POLYGON((0 0,10 0,10 10,0 10,0 0)) 121 POLYGON((3 6,44 6,44 9,3 9,3 6)) -122 NULL -123 NULL +122 GEOMETRYCOLLECTION EMPTY +123 GEOMETRYCOLLECTION EMPTY explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelope(g)) from gis_geometry; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 23 100.00 @@ -404,22 +404,22 @@ Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second; first second w c o e d t i r -120 120 1 1 0 1 0 1 1 1 +120 120 1 1 0 1 0 1 1 0 120 121 0 0 1 0 0 0 1 0 -120 122 0 1 NULL NULL NULL 0 NULL 0 -120 123 0 1 NULL NULL NULL 0 NULL 0 +120 122 0 1 NULL 0 NULL 0 NULL 0 +120 123 0 1 NULL 0 NULL 0 NULL 0 121 120 0 0 1 0 0 0 1 0 -121 121 1 1 0 1 0 1 1 1 -121 122 0 1 NULL NULL NULL 0 NULL 0 -121 123 0 1 NULL NULL NULL 0 NULL 0 -122 120 1 0 NULL NULL NULL 0 NULL 0 -122 121 1 0 NULL NULL NULL 0 NULL 0 -122 122 1 1 NULL NULL NULL 0 NULL 0 -122 123 1 1 NULL NULL NULL 0 NULL 0 -123 120 1 0 NULL NULL NULL 0 NULL 0 -123 121 1 0 NULL NULL NULL 0 NULL 0 -123 122 1 1 NULL NULL NULL 0 NULL 0 -123 123 1 1 NULL NULL NULL 0 NULL 0 +121 121 1 1 0 1 0 1 1 0 +121 122 0 1 NULL 0 NULL 0 NULL 0 +121 123 0 1 NULL 0 NULL 0 NULL 0 +122 120 1 0 NULL 0 NULL 0 NULL 0 +122 121 1 0 NULL 0 NULL 0 NULL 0 +122 122 1 1 NULL 1 NULL 0 NULL 0 +122 123 1 1 NULL 1 NULL 0 NULL 0 +123 120 1 0 NULL 0 NULL 0 NULL 0 +123 121 1 0 NULL 0 NULL 0 NULL 0 +123 122 1 1 NULL 1 NULL 0 NULL 0 +123 123 1 1 NULL 1 NULL 0 NULL 0 explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -429,7 +429,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE g1 ALL NULL NULL NULL NULL 4 100.00 Using temporary; Using filesort 1 SIMPLE g2 ALL NULL NULL NULL NULL 4 100.00 Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,st_within(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,st_contains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,mbroverlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,mbrequals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,mbrdisjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,st_touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,mbrintersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,st_crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid` +Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,st_within(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,st_contains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,mbroverlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,st_equals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,mbrdisjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,st_touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,mbrintersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,st_crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid` DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry; CREATE TABLE t1 ( gp point, @@ -867,7 +867,7 @@ mbroverlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrtouches FROM t1 a1 JOIN t1 a2 ON MBRTouches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrtouches -big,down2,left,left2,right,right2,small,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrwithin FROM t1 a1 JOIN t1 a2 ON MBRWithin( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; mbrwithin big,center @@ -888,7 +888,7 @@ overlaps down,left,right,up SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS touches FROM t1 a1 JOIN t1 a2 ON Touches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; touches -big,down2,left,left2,right,right2,small,up2 +big,center,down,down2,left,left2,right,right2,small,up,up2 SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS within FROM t1 a1 JOIN t1 a2 ON Within( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name; within big,center diff --git a/sql/spatial.cc b/sql/spatial.cc index d18600dd7de..b4ce6f59185 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -305,8 +305,17 @@ bool Geometry::envelope(String *result) const MBR mbr; const char *end; - if (get_mbr(&mbr, &end) || - result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10)) + if (get_mbr(&mbr, &end)) + { + /* Empty geometry */ + if (result->reserve(1 + 4*2)) + return 1; + result->q_append((char) wkb_ndr); + result->q_append((uint32) wkb_geometrycollection); + result->q_append((uint32) 0); + return 0; + } + if (result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10)) return 1; result->q_append((char) wkb_ndr); From dca6ff48c1a26f8eab911f4ad246f56be5005fd7 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 23 Sep 2011 15:25:48 +0500 Subject: [PATCH 29/40] fix for bug 857051 ST_EQUALS returns TRUE on two nonidentical MULTIPOINTs The 'single point' event was forgotten in the relation's calculation per-file comments: mysql-test/r/gis-precise.result fix for bug 857051 ST_EQUALS returns TRUE on two nonidentical MULTIPOINTs test result updated. mysql-test/t/gis-precise.test fix for bug 857051 ST_EQUALS returns TRUE on two nonidentical MULTIPOINTs test case added. sql/gcalc_tools.cc fix for bug 857051 ST_EQUALS returns TRUE on two nonidentical MULTIPOINTs scev_single_point is properly handled. --- mysql-test/r/gis-precise.result | 68 ++++++++------------------------- mysql-test/t/gis-precise.test | 5 +++ sql/gcalc_tools.cc | 2 + 3 files changed, 22 insertions(+), 53 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index ef621d11e54..209004b565f 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -7,7 +7,7 @@ select 0, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFro 0 0 select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POINT(10 10)')); 1 ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POINT(10 10)')) -1 0 +1 1 select 1, ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); 1 ST_Intersects(GeomFromText('POLYGON((0 0,20 10,10 30, 0 0))'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')) 1 1 @@ -25,90 +25,46 @@ insert into t1 values (GeomFromText('POINT(8 2)')), (GeomFromText('POINT(8 4)')), (GeomFromText('POINT(8 6)')), (GeomFromText('POINT(8 8)')); select astext(g) from t1 where ST_Within(g, GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))')); astext(g) -POINT(2 2) -POINT(2 4) -POINT(2 6) -POINT(2 8) -POINT(4 2) POINT(4 4) -POINT(4 6) -POINT(4 8) POINT(6 2) POINT(6 4) POINT(6 6) -POINT(6 8) -POINT(8 2) -POINT(8 4) -POINT(8 6) -POINT(8 8) select 'Contains'; Contains Contains select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); astext(g) -POINT(2 2) -POINT(2 4) -POINT(2 6) -POINT(2 8) -POINT(4 2) POINT(4 4) -POINT(4 6) -POINT(4 8) POINT(6 2) POINT(6 4) POINT(6 6) -POINT(6 8) -POINT(8 2) -POINT(8 4) -POINT(8 6) -POINT(8 8) select 'Intersects'; Intersects Intersects select astext(g) from t1 where ST_Intersects(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); astext(g) +POINT(4 4) +POINT(6 2) +POINT(6 4) +POINT(6 6) select 'Contains'; Contains Contains select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1))'), g); astext(g) -POINT(2 2) -POINT(2 4) -POINT(2 6) -POINT(2 8) -POINT(4 2) POINT(4 4) -POINT(4 6) -POINT(4 8) POINT(6 2) POINT(6 4) POINT(6 6) -POINT(6 8) -POINT(8 2) -POINT(8 4) -POINT(8 6) -POINT(8 8) select 'Contains2'; Contains2 Contains2 select astext(g) from t1 where ST_Contains(GeomFromText('POLYGON((5 1, 7 1, 7 7, 5 7, 3 3, 5 3, 5 1), (5.01 3.01, 6 5, 9 5, 8 3, 5.01 3.01))'), g); astext(g) -POINT(2 2) -POINT(2 4) -POINT(2 6) -POINT(2 8) -POINT(4 2) POINT(4 4) -POINT(4 6) -POINT(4 8) POINT(6 2) -POINT(6 4) POINT(6 6) -POINT(6 8) -POINT(8 2) POINT(8 4) -POINT(8 6) -POINT(8 8) DROP TABLE t1; select 0, ST_Within(GeomFromText('LINESTRING(15 15, 50 50, 60 60)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')); 0 ST_Within(GeomFromText('LINESTRING(15 15, 50 50, 60 60)'), GeomFromText('POLYGON((10 10,30 20,20 40, 10 10))')) @@ -136,7 +92,7 @@ ST_Intersects(GeomFromText('POLYGON((0 0, 50 45, 40 50, 0 0))'), GeomFromText('P 1 select ST_contains(GeomFromText('MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)), ((6 6, 6 11, 11 11, 11 6, 6 6)))'), GeomFromText('POINT(5 10)')); ST_contains(GeomFromText('MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0)), ((6 6, 6 11, 11 11, 11 6, 6 6)))'), GeomFromText('POINT(5 10)')) -1 +0 select ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 15, 15 15, 15 10, 10 10))')); ST_Disjoint(GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), GeomFromText('POLYGON((10 10, 10 15, 15 15, 15 10, 10 10))')) 1 @@ -219,10 +175,10 @@ st_touches(geomfromtext('point(0 0)'), geomfromtext('point(1 1)')) 0 select st_touches(geomfromtext('point(1 1)'), geomfromtext('point(1 1)')); st_touches(geomfromtext('point(1 1)'), geomfromtext('point(1 1)')) -0 +1 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)')) -0 +1 select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)')); st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)')) 0 @@ -459,10 +415,16 @@ ST_WITHIN( POINTFROMTEXT(' POINT(1 2 ) ') , MULTIPOLYGONFROMTEXT(' MULTIPOLYGON( 1 select ST_ASTEXT(envelope(ST_GEOMCOLLFROMTEXT('GEOMETRYCOLLECTION EMPTY'))); ST_ASTEXT(envelope(ST_GEOMCOLLFROMTEXT('GEOMETRYCOLLECTION EMPTY'))) -NULL +GEOMETRYCOLLECTION EMPTY SELECT ST_EQUALS( GEOMETRYFROMTEXT(' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') , GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') ); ST_EQUALS( GEOMETRYFROMTEXT(' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') , GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 5, 2 4, 3 4, 3 5) ) ') ) 0 SELECT ST_TOUCHES( GEOMETRYFROMTEXT(' LINESTRING( 1 1 , 1 4 , 5 0 , 8 3 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ') ); ST_TOUCHES( GEOMETRYFROMTEXT(' LINESTRING( 1 1 , 1 4 , 5 0 , 8 3 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ') ) 0 +SELECT ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT(' MULTIPOINT( 5 8 , 5 2 , 1 8 , 3 0 , 3 0 , 7 8 ) ') ); +ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT(' MULTIPOINT( 5 8 , 5 2 , 1 8 , 3 0 , 3 0 , 7 8 ) ') ) +0 +SELECT ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT('MULTIPOINT( 4 0 , 6 9 , 5 1, 1 4 )') ); +ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT('MULTIPOINT( 4 0 , 6 9 , 5 1, 1 4 )') ) +1 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index bf5c48d11f6..78b2c0287f6 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -298,3 +298,8 @@ SELECT ST_EQUALS( GEOMETRYFROMTEXT(' MULTILINESTRING( (3 5, 2 5, 2 4, 3 4, 3 5) SELECT ST_TOUCHES( GEOMETRYFROMTEXT(' LINESTRING( 1 1 , 1 4 , 5 0 , 8 3 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ') ); +#bug 857051 ST_EQUALS returns TRUE on two nonidentical MULTIPOINTs + +SELECT ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT(' MULTIPOINT( 5 8 , 5 2 , 1 8 , 3 0 , 3 0 , 7 8 ) ') ); +SELECT ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT('MULTIPOINT( 4 0 , 6 9 , 5 1, 1 4 )') ); + diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 6a2fdbccacb..4c56e5c58bd 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -293,6 +293,7 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) gcalc_shape_info si= events->get_shape(); if (events->event == scev_thread || events->event == scev_end || + events->event == scev_single_point || (get_shape_kind(si) == Gcalc_function::shape_polygon)) set_b_state(si); else if (get_shape_kind(si) == Gcalc_function::shape_line) @@ -308,6 +309,7 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) gcalc_shape_info si= events->get_shape(); if (events->event == scev_thread || events->event == scev_end || + events->event == scev_single_point || (get_shape_kind(si) == Gcalc_function::shape_polygon)) clear_b_state(si); else if (get_shape_kind(si) == Gcalc_function::shape_line) From 5b83aee35dffff0de4758a2a595624a18bec2b3e Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 23 Sep 2011 15:36:56 +0500 Subject: [PATCH 30/40] bug #857050 ST_WITHIN returns wrong result with MULTIPOINT and POLYGON actually only testcase added as the bug was fixed already. modified: mysql-test/r/gis-precise.result bug #857050 ST_WITHIN returns wrong result with MULTIPOINT and POLYGON test result updated. mysql-test/t/gis-precise.test bug #857050 ST_WITHIN returns wrong result with MULTIPOINT and POLYGON test case added. sql/gcalc_tools.cc superfluous variable removed. --- mysql-test/r/gis-precise.result | 3 +++ mysql-test/t/gis-precise.test | 3 +++ sql/gcalc_tools.cc | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 209004b565f..1bfd805d141 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -428,3 +428,6 @@ ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPO SELECT ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT('MULTIPOINT( 4 0 , 6 9 , 5 1, 1 4 )') ); ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT('MULTIPOINT( 4 0 , 6 9 , 5 1, 1 4 )') ) 1 +SELECT ST_WITHIN( MULTIPOINTFROMTEXT(' MULTIPOINT( 2 9 , 2 9 , 4 9 , 9 1 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ')); +ST_WITHIN( MULTIPOINTFROMTEXT(' MULTIPOINT( 2 9 , 2 9 , 4 9 , 9 1 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ')) +0 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 78b2c0287f6..36218c56f17 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -303,3 +303,6 @@ SELECT ST_TOUCHES( GEOMETRYFROMTEXT(' LINESTRING( 1 1 , 1 4 , 5 0 , 8 3 ) ') , P SELECT ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT(' MULTIPOINT( 5 8 , 5 2 , 1 8 , 3 0 , 3 0 , 7 8 ) ') ); SELECT ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPOINTFROMTEXT('MULTIPOINT( 4 0 , 6 9 , 5 1, 1 4 )') ); +#bug 857050 ST_WITHIN returns wrong result with MULTIPOINT and POLYGON +SELECT ST_WITHIN( MULTIPOINTFROMTEXT(' MULTIPOINT( 2 9 , 2 9 , 4 9 , 9 1 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ')); + diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 4c56e5c58bd..69071c16ee8 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -766,7 +766,9 @@ int ca_counter= 0; int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { Gcalc_point_iterator pi(si); +#ifdef TMP_BLOCK const Gcalc_heap::Info *event_point= NULL; +#endif /*TMP_BLOCK*/ int prev_state= 0; int sav_prev_state; active_thread *prev_range= NULL; @@ -858,8 +860,10 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { active_thread *cur_t= *cur_t_hook; +#ifdef TMP_BLOCK if (!event_point && events->event != scev_intersection) event_point= events->pi; +#endif /*TMP_BLOCK*/ if (events->event == scev_single_point) continue; From 6e7d578b2b3fad8671504785b757e53b11516b22 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 23 Sep 2011 17:00:36 +0500 Subject: [PATCH 31/40] bug 857087 Wrong result with ST_INTERSECTS and LINESTRINGs Line autointersection point was treated as if it doesn't belong to the line. It's in some way logical, but seems to confuse people. Fixed. per_file_comments: mysql-test/r/gis-precise.result bug 857087 Wrong result with ST_INTERSECTS and LINESTRINGs test result updated. mysql-test/t/gis-precise.test bug 857087 Wrong result with ST_INTERSECTS and LINESTRINGs test case added. sql/gcalc_tools.cc bug 857087 Wrong result with ST_INTERSECTS and LINESTRINGs Point of line autointersection handled as it belongs to the line. sql/gcalc_tools.h bug 857087 Wrong result with ST_INTERSECTS and LINESTRINGs Gcalc_function::set_i_state() added --- mysql-test/r/gis-precise.result | 3 +++ mysql-test/t/gis-precise.test | 4 ++++ sql/gcalc_tools.cc | 4 ++-- sql/gcalc_tools.h | 2 ++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 1bfd805d141..9086dec78a0 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -431,3 +431,6 @@ ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , MULTIPO SELECT ST_WITHIN( MULTIPOINTFROMTEXT(' MULTIPOINT( 2 9 , 2 9 , 4 9 , 9 1 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ')); ST_WITHIN( MULTIPOINTFROMTEXT(' MULTIPOINT( 2 9 , 2 9 , 4 9 , 9 1 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ')) 0 +SELECT ST_INTERSECTS( GeomFromText('MULTILINESTRING( ( 4030 3045 , 3149 2461 , 3004 3831 , 3775 2976 ) )') , GeomFromText('LINESTRING(3058.41 3187.91,3081.52 3153.19,3042.99 3127.57,3019.89 3162.29,3039.07 3175.05,3039.07 3175.05,3058.41 3187.91,3081.52 3153.19,3042.99 3127.57,3019.89 3162.29)') ); +ST_INTERSECTS( GeomFromText('MULTILINESTRING( ( 4030 3045 , 3149 2461 , 3004 3831 , 3775 2976 ) )') , GeomFromText('LINESTRING(3058.41 3187.91,3081.52 3153.19,3042.99 3127.57,3019.89 3162.29,3039.07 3175.05,3039.07 3175.05,3058.41 3187.91,3081.52 3153.19, +1 diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index 36218c56f17..1de8726a7bc 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -306,3 +306,7 @@ SELECT ST_EQUALS( MULTIPOINTFROMTEXT(' MULTIPOINT( 5 1 , 6 9 , 1 4 , 4 0 ) ') , #bug 857050 ST_WITHIN returns wrong result with MULTIPOINT and POLYGON SELECT ST_WITHIN( MULTIPOINTFROMTEXT(' MULTIPOINT( 2 9 , 2 9 , 4 9 , 9 1 ) ') , POLYGONFROMTEXT(' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ')); +#bug 857087 Wrong result with ST_INTERSECTS and LINESTRINGs + +SELECT ST_INTERSECTS( GeomFromText('MULTILINESTRING( ( 4030 3045 , 3149 2461 , 3004 3831 , 3775 2976 ) )') , GeomFromText('LINESTRING(3058.41 3187.91,3081.52 3153.19,3042.99 3127.57,3019.89 3162.29,3039.07 3175.05,3039.07 3175.05,3058.41 3187.91,3081.52 3153.19,3042.99 3127.57,3019.89 3162.29)') ); + diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 69071c16ee8..8e881b84c5d 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -297,7 +297,7 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) (get_shape_kind(si) == Gcalc_function::shape_polygon)) set_b_state(si); else if (get_shape_kind(si) == Gcalc_function::shape_line) - invert_i_state(si); + set_i_state(si); } if (count()) @@ -313,7 +313,7 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) (get_shape_kind(si) == Gcalc_function::shape_polygon)) clear_b_state(si); else if (get_shape_kind(si) == Gcalc_function::shape_line) - invert_i_state(si); + clear_i_state(si); } if (scan_it.get_event_position() == scan_it.get_event_end()) diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index 5e98d46a90f..d79ba630506 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -104,6 +104,8 @@ public: void set_states(int *shape_states) { i_states= shape_states; } int alloc_states(); void invert_i_state(gcalc_shape_info shape) { i_states[shape]^= 1; } + void set_i_state(gcalc_shape_info shape) { i_states[shape]= 1; } + void clear_i_state(gcalc_shape_info shape) { i_states[shape]= 0; } void set_b_state(gcalc_shape_info shape) { b_states[shape]= 1; } void clear_b_state(gcalc_shape_info shape) { b_states[shape]= 0; } int get_state(gcalc_shape_info shape) From e99850774b67f012f078c1a2b36f27dbbea8e804 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 4 Oct 2011 15:01:21 +0500 Subject: [PATCH 32/40] GIS library code cleanup. GCALC_DBUG_OFF and related infrastructure defined so we can enable/disable debugging conveniently. per-file comments: sql/gcalc_slicescan.cc GIS library code cleanup. sql/gcalc_slicescan.h GIS library code cleanup. sql/gcalc_tools.cc GIS library code cleanup. sql/gcalc_tools.h GIS library code cleanup. --- sql/gcalc_slicescan.cc | 657 +++++++++++++++-------------------------- sql/gcalc_slicescan.h | 38 +-- sql/gcalc_tools.cc | 283 +++++++----------- sql/gcalc_tools.h | 12 +- 4 files changed, 370 insertions(+), 620 deletions(-) diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 8a9fcc60ad0..fb1aab029a8 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -39,6 +39,99 @@ typedef int (*sc_compare_func)(const void*, const void*); #include "plistsort.c" +#ifndef GCALC_DBUG_OFF + +int gcalc_step_counter= 0; + +void GCALC_DBUG_CHECK_COUNTER() +{ + if (++gcalc_step_counter == 0) + GCALC_DBUG_PRINT(("step_counter_0")); + else + GCALC_DBUG_PRINT(("%d step_counter", gcalc_step_counter)); +} + + +const char *gcalc_ev_name(int ev) +{ + switch (ev) + { + case scev_none: + return "n"; + case scev_thread: + return "t"; + case scev_two_threads: + return "tt"; + case scev_end: + return "e"; + case scev_two_ends: + return "ee"; + case scev_intersection: + return "i"; + case scev_point: + return "p"; + case scev_single_point: + return "sp"; + default:; + }; + GCALC_DBUG_ASSERT(0); + return "unk"; +} + + +static void GCALC_DBUG_PRINT_SLICE(const char *header, + const Gcalc_scan_iterator::point *slice) +{ + int nbuf1, nbuf2; + char buf1[1024], buf2[1024]; + nbuf1= nbuf2= strlen(header); + strcpy(buf1, header); + strcpy(buf2, header); + for (; slice; slice= slice->get_next()) + { + nbuf1+= sprintf(buf1+nbuf1, "%d\t", slice->thread); + nbuf2+= sprintf(buf2+nbuf2, "%s\t", gcalc_ev_name(slice->event)); + } + buf1[nbuf1]= 0; + buf2[nbuf2]= 0; + GCALC_DBUG_PRINT((buf1)); + GCALC_DBUG_PRINT((buf2)); +} + + +static void GCALC_DBUG_PRINT_INTERSECTIONS( + Gcalc_scan_iterator::intersection *isc) +{ + for (; isc; isc= isc->get_next()) + { + long double ix, iy; + isc->ii->calc_xy_ld(&ix, &iy); + GCALC_DBUG_PRINT(("%d %d %d %.8LG %.8LG", isc->thread_a, isc->thread_b, + isc->n_row, ix, iy)); + } +} + + +static void GCALC_DBUG_PRINT_STATE(Gcalc_scan_iterator::slice_state *s) +{ + if (s->event_position) + GCALC_DBUG_PRINT(("%d %d %d", s->event_position->thread, + ((Gcalc_scan_iterator::point *) *s->event_position_hook)->thread, + *s->event_end_hook ? + ((Gcalc_scan_iterator::point *) *s->event_end_hook)->thread : -1)); + else + GCALC_DBUG_PRINT(("position null")); +} + + +#else +#define GCALC_DBUG_CHECK_COUNTER(a) do { } while(0) +#define GCALC_DBUG_PRINT_SLICE(a, b) do { } while(0) +#define GCALC_DBUG_PRINT_INTERSECTIONS(a) do { } while(0) +#define GCALC_DBUG_PRINT_STATE(a) do { } while(0) +#endif /*GCALC_DBUG_OFF*/ + + Gcalc_dyn_list::Gcalc_dyn_list(size_t blk_size, size_t sizeof_item): m_blk_size(blk_size - ALLOC_ROOT_MIN_BLOCK_SIZE), m_sizeof_item(ALIGN_SIZE(sizeof_item)), @@ -52,7 +145,7 @@ Gcalc_dyn_list::Gcalc_dyn_list(size_t blk_size, size_t sizeof_item): void Gcalc_dyn_list::format_blk(void* block) { Item *pi_end, *cur_pi, *first_pi; - DBUG_ASSERT(m_free == NULL); + GCALC_DBUG_ASSERT(m_free == NULL); first_pi= cur_pi= (Item *)(((char *)block) + PH_DATA_OFFSET); pi_end= ptr_add(first_pi, m_points_per_blk - 1); do { @@ -170,8 +263,8 @@ static void do_add(Gcalc_internal_coord *result, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b) { - DBUG_ASSERT(a->n_digits == b->n_digits); - DBUG_ASSERT(a->n_digits == result->n_digits); + GCALC_DBUG_ASSERT(a->n_digits == b->n_digits); + GCALC_DBUG_ASSERT(a->n_digits == result->n_digits); int n_digit= a->n_digits-1; coord_digit_t carry= 0; @@ -186,7 +279,7 @@ static void do_add(Gcalc_internal_coord *result, else carry= 0; } while (n_digit--); - DBUG_ASSERT(carry == 0); + GCALC_DBUG_ASSERT(carry == 0); result->sign= a->sign; } @@ -195,8 +288,8 @@ static void do_sub(Gcalc_internal_coord *result, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b) { - DBUG_ASSERT(a->n_digits == b->n_digits); - DBUG_ASSERT(a->n_digits == result->n_digits); + GCALC_DBUG_ASSERT(a->n_digits == b->n_digits); + GCALC_DBUG_ASSERT(a->n_digits == result->n_digits); int n_digit= a->n_digits-1; coord_digit_t carry= 0; @@ -211,7 +304,7 @@ static void do_sub(Gcalc_internal_coord *result, else carry= 0; } while (n_digit--); - DBUG_ASSERT(carry == 0); + GCALC_DBUG_ASSERT(carry == 0); if (a->sign && result->is_zero()) result->sign= 0; else @@ -222,7 +315,7 @@ static void do_sub(Gcalc_internal_coord *result, static int do_cmp(const Gcalc_internal_coord *a, const Gcalc_internal_coord *b) { - DBUG_ASSERT(a->n_digits == b->n_digits); + GCALC_DBUG_ASSERT(a->n_digits == b->n_digits); int n_digit= 0; do @@ -243,23 +336,11 @@ static int do_cmp(const Gcalc_internal_coord *a, static int de_check(long double a, long double b) { long double d= a - b; - if (d < (long double) 1e-6 && d > (long double) -1e-6) + if (d < (long double) 1e-10 && d > (long double) -1e-10) return 1; - printf("xxx\n"); - return 0; -} -static int de_check1(long double a, long double b) -{ - long double d= a - b; - if (d < (long double) 1e-6 && d > (long double) -1e-6) - return 1; - return 0; -} -static int de_weak(long double a, long double b) -{ - long double d= a - b; - if (d < (long double) 1 && d > (long double) -1) + d/= fabsl(a) + fabsl(b); + if (d < (long double) 1e-10 && d > (long double) -1e-10) return 1; return 0; } @@ -270,7 +351,7 @@ void gcalc_mul_coord(Gcalc_internal_coord *result, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b) { - DBUG_ASSERT(result->n_digits == a->n_digits + b->n_digits); + GCALC_DBUG_ASSERT(result->n_digits == a->n_digits + b->n_digits); int n_a, n_b, n_res; coord_digit_t carry= 0; @@ -301,7 +382,7 @@ void gcalc_mul_coord(Gcalc_internal_coord *result, } while (n_a--); result->sign= a->sign != b->sign; #ifdef GCALC_CHECK_WITH_FLOAT - DBUG_ASSERT(de_check(a->get_double() * b->get_double(), + GCALC_DBUG_ASSERT(de_check(a->get_double() * b->get_double(), result->get_double())); #endif /*GCALC_CHECK_WITH_FLOAT*/ } @@ -324,7 +405,7 @@ void gcalc_add_coord(Gcalc_internal_coord *result, do_sub(result, b, a); } #ifdef GCALC_CHECK_WITH_FLOAT - DBUG_ASSERT(de_check(a->get_double() + b->get_double(), + GCALC_DBUG_ASSERT(de_check(a->get_double() + b->get_double(), result->get_double())); #endif /*GCALC_CHECK_WITH_FLOAT*/ } @@ -350,7 +431,7 @@ void gcalc_sub_coord(Gcalc_internal_coord *result, } } #ifdef GCALC_CHECK_WITH_FLOAT - DBUG_ASSERT(de_check(a->get_double() - b->get_double(), + GCALC_DBUG_ASSERT(de_check(a->get_double() - b->get_double(), result->get_double())); #endif /*GCALC_CHECK_WITH_FLOAT*/ } @@ -365,12 +446,12 @@ int gcalc_cmp_coord(const Gcalc_internal_coord *a, result= a->sign ? do_cmp(b, a) : do_cmp(a, b); #ifdef GCALC_CHECK_WITH_FLOAT if (result == 0) - DBUG_ASSERT(de_check(a->get_double(), b->get_double())); + GCALC_DBUG_ASSERT(de_check(a->get_double(), b->get_double())); else if (result == 1) - DBUG_ASSERT(de_check1(a->get_double(), b->get_double()) || + GCALC_DBUG_ASSERT(de_check(a->get_double(), b->get_double()) || a->get_double() > b->get_double()); else - DBUG_ASSERT(de_check1(a->get_double(), b->get_double()) || + GCALC_DBUG_ASSERT(de_check(a->get_double(), b->get_double()) || a->get_double() < b->get_double()); #endif /*GCALC_CHECK_WITH_FLOAT*/ return result; @@ -386,7 +467,7 @@ int Gcalc_coord1::set_double(double d) c[0]= (coord_digit_t) (ds / (double) DIG_BASE); c[1]= (coord_digit_t) (ds - ((double) c[0]) * DIG_BASE); #ifdef GCALC_CHECK_WITH_FLOAT - DBUG_ASSERT(de_check(d, get_double())); + GCALC_DBUG_ASSERT(de_check(d, get_double())); #endif /*GCALC_CHECK_WITH_FLOAT*/ return 0; } @@ -564,7 +645,7 @@ static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node { if (!node) return; - DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node)); + GCALC_DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node)); if (node->left == prev_node) node->left= node->right; node->right= NULL; @@ -591,7 +672,7 @@ static int compare_point_info(const void *e0, const void *e1) void Gcalc_heap::prepare_operation() { - DBUG_ASSERT(m_hook); + GCALC_DBUG_ASSERT(m_hook); *m_hook= NULL; m_first= sort_list(compare_point_info, m_first, m_n_points); m_hook= NULL; /* just to check it's not called twice */ @@ -644,7 +725,7 @@ int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info, double x, double y) { Gcalc_heap::Info *point; - DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y); + GCALC_DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y); if (!(point= m_heap->new_point_info(x, y, Info))) return 1; @@ -662,7 +743,7 @@ int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info, void Gcalc_shape_transporter::int_complete() { - DBUG_ASSERT(m_shape_started == 1 || m_shape_started == 3); + GCALC_DBUG_ASSERT(m_shape_started == 1 || m_shape_started == 3); if (!m_first) return; @@ -683,28 +764,28 @@ void Gcalc_shape_transporter::int_complete() return; } - DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y); + 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; } -#ifdef TMP_BLOCK -inline int GET_DX_DY(double *dxdy, - const Gcalc_heap::Info *p0, const Gcalc_heap::Info *p1) -{ - double dy= p1->y - p0->y; - *dxdy= p1->x - p0->x; - return (dy == 0.0) || - (*dxdy/= dy)>DBL_MAX || - (*dxdy)<-DBL_MAX; -} -#endif /*TMP_BLOCK*/ inline void calc_dx_dy(Gcalc_scan_iterator::point *p) { gcalc_sub_coord(&p->dx, &p->next_pi->ix, &p->pi->ix); gcalc_sub_coord(&p->dy, &p->next_pi->iy, &p->pi->iy); + if (p->dx.sign) + { + p->l_border= &p->next_pi->ix; + p->r_border= &p->pi->ix; + } + else + { + p->r_border= &p->next_pi->ix; + p->l_border= &p->pi->ix; + } + p->always_on_left= 0; } @@ -732,8 +813,8 @@ Gcalc_scan_iterator::point void Gcalc_scan_iterator::init(Gcalc_heap *points) { - DBUG_ASSERT(points->ready()); - DBUG_ASSERT(!state0.slice && !state1.slice); + GCALC_DBUG_ASSERT(points->ready()); + GCALC_DBUG_ASSERT(!state0.slice && !state1.slice); if (!(m_cur_pi= points->get_first())) return; @@ -746,9 +827,6 @@ void Gcalc_scan_iterator::init(Gcalc_heap *points) current_state= &state0; next_state= &state1; saved_state= &state_s; -#ifdef TMP_BLOCK - next_state->y= m_cur_pi->y; -#endif /*TMP_BLOCK*/ next_state->intersection_scan= 0; next_state->pi= m_cur_pi; } @@ -763,18 +841,13 @@ void Gcalc_scan_iterator::reset() void Gcalc_scan_iterator::point::copy_core(const point *from) { -#ifdef TMP_BLOCK - dx_dy= from->dx_dy; - horiz_dir= from->horiz_dir; -#endif /*TMP_BLOCK*/ pi= from->pi; next_pi= from->next_pi; thread= from->thread; dx.copy(&from->dx); dy.copy(&from->dy); -#ifdef TO_REMOVE - from->next_link= this; -#endif /*TO_REMOVE*/ + l_border= from->l_border; + r_border= from->r_border; } @@ -787,35 +860,11 @@ void Gcalc_scan_iterator::point::copy_all(const point *from) dy.copy(&from->dy); intersection_link= from->intersection_link; event= from->event; -} -#ifdef TMP_BLOCK -int Gcalc_scan_iterator::point::cmp_dx_dy(int horiz_dir_a, double dx_dy_a, - int horiz_dir_b, double dx_dy_b) -{ - if (!horiz_dir_a && !horiz_dir_b) - { - if (coord_eq(dx_dy_a, dx_dy_b)) - return 0; - return dx_dy_a < dx_dy_b ? -1 : 1; - } - if (!horiz_dir_a) - return -1; - if (!horiz_dir_b) - return 1; - - return 0; + l_border= from->l_border; + r_border= from->r_border; } -int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const -{ - if (is_bottom()) - return p->is_bottom() ? 0 : -1; - if (p->is_bottom()) - return 1; - return cmp_dx_dy(horiz_dir, dx_dy, p->horiz_dir, p->dx_dy); -} -#endif /*TMP_BLOCK*/ int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_coord1 *dx_a, const Gcalc_coord1 *dy_a, const Gcalc_coord1 *dx_b, @@ -899,15 +948,15 @@ static int cmp_sp_pi(const Gcalc_scan_iterator::point *sp, long double sp_x; sp->calc_x(&sp_x, pi->y, pi->x); if (result == 0) - DBUG_ASSERT(de_check1(sp->dy.get_double(), 0.0) || + GCALC_DBUG_ASSERT(de_check(sp->dy.get_double(), 0.0) || de_check(sp_x, pi->x)); if (result < 0) - DBUG_ASSERT(de_check1(sp->dy.get_double(), 0.0) || - de_check1(sp_x, pi->x) || + GCALC_DBUG_ASSERT(de_check(sp->dy.get_double(), 0.0) || + de_check(sp_x, pi->x) || sp_x < pi->x); if (result > 0) - DBUG_ASSERT(de_check1(sp->dy.get_double(), 0.0) || - de_check1(sp_x, pi->x) || + GCALC_DBUG_ASSERT(de_check(sp->dy.get_double(), 0.0) || + de_check(sp_x, pi->x) || sp_x > pi->x); #endif /*GCALC_CHECK_WITH_FLOAT*/ return result; @@ -954,11 +1003,11 @@ static int cmp_sp_sp_cnt(const Gcalc_scan_iterator::point *a, a->calc_x(&a_x, y->get_double(), 0); b->calc_x(&b_x, y->get_double(), 0); if (result == 0) - DBUG_ASSERT(de_check(a_x, b_x)); + GCALC_DBUG_ASSERT(de_check(a_x, b_x)); if (result < 0) - DBUG_ASSERT(de_check1(a_x, b_x) || a_x < b_x); + GCALC_DBUG_ASSERT(de_check(a_x, b_x) || a_x < b_x); if (result > 0) - DBUG_ASSERT(de_check1(a_x, b_x) || a_x > b_x); + GCALC_DBUG_ASSERT(de_check(a_x, b_x) || a_x > b_x); #endif /*GCALC_CHECK_WITH_FLOAT*/ return result; } @@ -1009,8 +1058,8 @@ int Gcalc_scan_iterator::arrange_event() if (m_events) free_list(m_events); ev_counter= 0; - DBUG_ASSERT(current_state->event_position == - *current_state->event_position_hook); + GCALC_DBUG_ASSERT(current_state->event_position == + *current_state->event_position_hook); for (sp= current_state->event_position; sp != *current_state->event_end_hook; sp= sp->get_next()) { @@ -1021,9 +1070,6 @@ int Gcalc_scan_iterator::arrange_event() new_sp->copy_all(sp); *ae_hook= new_sp; ae_hook= &new_sp->next; -#ifdef TO_REMOVE - sp->intersection_link= new_sp; -#endif /*TO_REMOVE*/ ev_counter++; } *ae_hook= NULL; @@ -1036,7 +1082,10 @@ int Gcalc_scan_iterator::arrange_event() after_event= (point *) sort_list(compare_events, after_event, ev_counter); /* Find last item in the list, ae_hook can change after the sorting */ for (cur_p= after_event->get_next(); cur_p->get_next(); - cur_p= cur_p->get_next()); + cur_p= cur_p->get_next()) + { + cur_p->always_on_left= 1; + } ae_hook= &cur_p->next; } @@ -1067,14 +1116,12 @@ int Gcalc_scan_iterator::insert_top_point() point *sp0= new_slice_point(); point *sp_inc; + GCALC_DBUG_ENTER("Gcalc_scan_iterator::insert_top_point"); if (!sp0) - return 1; + GCALC_DBUG_RETURN(1); sp0->pi= m_cur_pi; sp0->next_pi= m_cur_pi->left; sp0->thread= m_cur_thread++; -#ifdef TMP_BLOCK - sp0->x= coord_to_float(m_cur_pi->x); -#endif /*TMP_BLOCK*/ if (m_cur_pi->left) { calc_dx_dy(sp0); @@ -1082,20 +1129,17 @@ int Gcalc_scan_iterator::insert_top_point() /*Now just to increase the size of m_slice0 to be same*/ if (!(sp_inc= new_slice_point())) - return 1; + GCALC_DBUG_RETURN(1); sp_inc->next= current_state->slice; current_state->slice= sp_inc; if (m_cur_pi->right) { if (!(sp1= new_slice_point())) - return 1; + GCALC_DBUG_RETURN(1); sp1->event= sp0->event= scev_two_threads; sp1->pi= m_cur_pi; sp1->next_pi= m_cur_pi->right; sp1->thread= m_cur_thread++; -#ifdef TMP_BLOCK - sp1->x= sp0->x; -#endif /*TMP_BLOCK*/ calc_dx_dy(sp1); /* We have two threads so should decide which one will be first */ if (sp0->cmp_dx_dy(sp1)>0) @@ -1107,7 +1151,7 @@ int Gcalc_scan_iterator::insert_top_point() /*Now just to increase the size of m_slice0 to be same*/ if (!(sp_inc= new_slice_point())) - return 1; + GCALC_DBUG_RETURN(1); sp_inc->next= current_state->slice; current_state->slice= sp_inc; } @@ -1115,10 +1159,6 @@ int Gcalc_scan_iterator::insert_top_point() else { sp0->event= scev_single_point; -#ifdef TMP_BLOCK - sp0->horiz_dir= 0; - sp0->dx_dy= 0.0; -#endif /*TMP_BLOCK*/ } @@ -1154,36 +1194,10 @@ int Gcalc_scan_iterator::insert_top_point() sp0->next= sp; next_state->event_end_hook= &sp0->next; } - return 0; + GCALC_DBUG_RETURN(0); } -#ifndef NO_TESTING -const char *pev(int ev) -{ - switch (ev) - { - case scev_none: - return "n"; - case scev_thread: - return "t"; - case scev_two_threads: - return "tt"; - case scev_end: - return "e"; - case scev_two_ends: - return "ee"; - case scev_intersection: - return "i"; - case scev_point: - return "p"; - case scev_single_point: - return "sp"; - }; - return "fck"; -} -extern int ca_counter; -#endif /*NO_TESTING*/ int Gcalc_scan_iterator::normal_scan() { point *sp; @@ -1191,13 +1205,17 @@ int Gcalc_scan_iterator::normal_scan() Gcalc_heap::Info *next_pi; point *first_bottom_point; + GCALC_DBUG_ENTER("Gcalc_scan_iterator::normal_scan"); + GCALC_DBUG_CHECK_COUNTER(); + GCALC_DBUG_PRINT_SLICE("in\t", next_state->slice); if (m_next_is_top_point && insert_top_point()) - return 1; + GCALC_DBUG_RETURN(1); for (next_pi= m_cur_pi->get_next(); next_pi && cmp_point_info(m_cur_pi, next_pi) == 0; next_pi= next_pi->get_next()) { + GCALC_DBUG_PRINT(("eq_loop equal pi")); next_state->clear_event_position(); m_next_is_top_point= true; first_bottom_point= NULL; @@ -1205,40 +1223,52 @@ int Gcalc_scan_iterator::normal_scan() sp_hook= (Gcalc_dyn_list::Item **) &next_state->slice; sp; sp_hook= &sp->next, sp= sp->get_next()) { -#ifndef NO_TESTING - // if (ca_counter == 21) - printf("%s%d\t", pev(sp->event), sp->thread); -#endif /*NO_TESTING*/ + GCALC_DBUG_PRINT(("eq_loop normal_eq_step %s%d", gcalc_ev_name(sp->event), + sp->thread)); if (sp->next_pi == next_pi) /* End of the segment */ { -#ifdef TMP_BLOCK - sp->x= coord_to_float(next_pi->x); - sp->pi= next_pi; -#endif /*TMP_BLOCK*/ + GCALC_DBUG_PRINT(("eq_loop edge end")); if (cmp_point_info(sp->pi, next_pi)) + { + GCALC_DBUG_PRINT(("eq_loop zero-len edge")); sp->pi= next_pi; + } sp->next_pi= next_pi->left; m_next_is_top_point= false; if (next_pi->is_bottom()) { + GCALC_DBUG_PRINT(("eq_loop bottom_point")); if (sp->event == scev_thread) + { + /* Beginning of the thread, and the end are same */ + /* Make single point out of the line then. */ + GCALC_DBUG_PRINT(("eq_loop line_to_point")); sp->event= scev_single_point; + } else if (sp->event == scev_two_threads) { if (sp->get_next() && sp->get_next()->pi == sp->pi) + { + GCALC_DBUG_PRINT(("eq_loop two_threads_to_line %d", + sp->get_next()->thread)); sp->get_next()->event= scev_thread; + } else if (sp != next_state->slice) { point *fnd_sp; for (fnd_sp= next_state->slice; fnd_sp->get_next() != sp; - fnd_sp= fnd_sp->get_next()); - DBUG_ASSERT(fnd_sp->pi == sp->pi); + fnd_sp= fnd_sp->get_next()) + {} + GCALC_DBUG_ASSERT(fnd_sp->pi == sp->pi); + GCALC_DBUG_PRINT(("eq_loop two_threads_to_line %d", + fnd_sp->thread)); fnd_sp->event= scev_thread; } sp->event= scev_single_point; } else if (first_bottom_point) { + GCALC_DBUG_PRINT(("eq_loop two_ends")); first_bottom_point->event= sp->event= scev_two_ends; } else @@ -1249,6 +1279,8 @@ int Gcalc_scan_iterator::normal_scan() } else { + GCALC_DBUG_PRINT(("eq_loop no_bottom_point %d%s", sp->thread, + gcalc_ev_name(sp->event))); if ((sp->event & (scev_point | scev_thread | scev_two_threads)) == 0) sp->event= scev_point; calc_dx_dy(sp); @@ -1257,44 +1289,31 @@ int Gcalc_scan_iterator::normal_scan() } else if (sp->event || (cmp_sp_pi(sp, next_pi) == 0)) { + GCALC_DBUG_PRINT(("eq_loop l_event %d%s", sp->thread, + gcalc_ev_name(sp->event))); if (!sp->event) sp->event= scev_intersection; mark_event_position1(sp, sp_hook); } } -#ifndef NO_TESTING - //if (ca_counter == 21) - printf("\n"); -#endif /*NO_TESTING*/ m_cur_pi= next_pi; if (m_next_is_top_point) { if (insert_top_point()) - return 1; + GCALC_DBUG_RETURN(1); /* Set proper values to the event position */ /* TODO: can be done faster */ next_state->clear_event_position(); if (next_state->slice->event) mark_event_position1(next_state->slice, (Gcalc_dyn_list::Item **) &next_state->slice); -#ifndef NO_TESTING - //if (ca_counter == 21) - printf("*%s%d\t", pev(next_state->slice->event), next_state->slice->thread); -#endif /*NO_TESTING*/ for (sp= next_state->slice; sp->get_next(); sp= sp->get_next()) { -#ifndef NO_TESTING - //if (ca_counter == 21) - printf("%s%d\t", pev(sp->get_next()->event), sp->get_next()->thread); -#endif /*NO_TESTING*/ if (sp->get_next()->event) mark_event_position1(sp->get_next(), &sp->next); } -#ifndef NO_TESTING - //if (ca_counter == 21) - printf("\n"); -#endif /*NO_TESTING*/ } + GCALC_DBUG_PRINT_SLICE("eq_loop\t", next_state->slice); } /* Swap current <-> next */ @@ -1305,42 +1324,25 @@ int Gcalc_scan_iterator::normal_scan() } if (arrange_event()) - return 1; + GCALC_DBUG_RETURN(1); + GCALC_DBUG_PRINT_SLICE("after_arrange\t", current_state->slice); + GCALC_DBUG_PRINT_SLICE("events\t", m_events); + GCALC_DBUG_PRINT_STATE(current_state); point *sp0= current_state->slice; point *sp1= next_state->slice; point *prev_sp1= NULL; -#ifndef NO_TESTING - //if (ca_counter == 21) - { - point *sp= current_state->slice; - printf("After arrange\n"); - for (; sp; sp= sp->get_next()) - printf("%s%d\t", pev(sp->event), sp->thread); - printf("\nEvent\n"); - for (sp= m_events; sp; sp= sp->get_next()) - printf("%s%d\t", pev(sp->event), sp->thread); - printf("\n"); - } -#endif /*NO_TESTING*/ if (!(m_cur_pi= next_pi)) { free_list(sp1); next_state->slice= NULL; -#ifdef TO_REMOVE - for (; sp0; sp0= sp0->get_next()) - sp0->next_link= NULL; -#endif /*TO_REMOVE*/ - return 0; + GCALC_DBUG_RETURN(0); } next_state->intersection_scan= 0; next_state->pi= m_cur_pi; Gcalc_heap::Info *cur_pi= m_cur_pi; -#ifdef TMP_BLOCK - next_state->y= coord_to_float(cur_pi->y); -#endif /*TMP_BLOCK*/ first_bottom_point= NULL; @@ -1350,23 +1352,19 @@ int Gcalc_scan_iterator::normal_scan() for (; sp0; sp0= sp0->get_next()) { - DBUG_ASSERT(!sp0->is_bottom()); + GCALC_DBUG_ASSERT(!sp0->is_bottom()); if (sp0->next_pi == cur_pi) /* End of the segment */ { -#ifdef TMP_BLOCK - sp1->x= coord_to_float(cur_pi->x); -#endif /*TMP_BLOCK*/ + GCALC_DBUG_PRINT(("edge_end %d", sp0->thread)); sp1->pi= cur_pi; sp1->thread= sp0->thread; sp1->next_pi= cur_pi->left; -#ifdef TO_REMOVE - sp0->next_link= sp1; -#endif /*TO_REMOVE*/ m_next_is_top_point= false; if (sp1->is_bottom()) { + GCALC_DBUG_PRINT(("bottom_point")); if (!first_bottom_point) { sp1->event= scev_end; @@ -1374,6 +1372,7 @@ int Gcalc_scan_iterator::normal_scan() } else { + GCALC_DBUG_PRINT(("two_ends")); first_bottom_point->event= sp1->event= scev_two_ends; } } @@ -1388,15 +1387,12 @@ int Gcalc_scan_iterator::normal_scan() } else { + GCALC_DBUG_PRINT(("cut_edge %d", sp0->thread)); /* Cut current string with the height of the new point*/ sp1->copy_core(sp0); -#ifdef TMP_BLOCK - sp1->x= sp1->horiz_dir ? coord_to_float(cur_pi->x) : - (coord_to_float(sp1->pi->x) + - (next_state->y-coord_to_float(sp1->pi->y)) * sp1->dx_dy); -#endif /*TMP_BLOCK*/ if (cmp_sp_pi(sp1, cur_pi) == 0) { + GCALC_DBUG_PRINT(("equal_point")); mark_event_position1(sp1, prev_sp1 ? &prev_sp1->next : (Gcalc_dyn_list::Item **) &next_state->slice); @@ -1408,6 +1404,7 @@ int Gcalc_scan_iterator::normal_scan() intersections_found= intersections_found || (prev_sp1 && cmp_sp_sp(prev_sp1, sp1, cur_pi) > 0); + GCALC_DBUG_PRINT(("%s", intersections_found ? "X":"-")); prev_sp1= sp1; sp1= sp1->get_next(); @@ -1422,26 +1419,14 @@ int Gcalc_scan_iterator::normal_scan() free_list(sp1); } -#ifndef NO_TESTING - //if (ca_counter == 21) - { - point *sp= next_state->slice; - printf("After slice\n"); - for (; sp; sp= sp->get_next()) - printf("%s%d\t", pev(sp->event), sp->thread); - printf("\n"); - } -#endif /*NO_TESTING*/ + GCALC_DBUG_PRINT_SLICE("after_loop\t", next_state->slice); if (intersections_found) - return handle_intersections(); + GCALC_DBUG_RETURN(handle_intersections()); - return 0; + GCALC_DBUG_RETURN(0); } -#ifndef NO_TESTING -int isc_counter= 0; -#endif /*NO_TESTING*/ int Gcalc_scan_iterator::add_intersection(int n_row, const point *a, const point *b, Gcalc_dyn_list::Item ***p_hook) @@ -1450,8 +1435,9 @@ int Gcalc_scan_iterator::add_intersection(int n_row, const point *b0= b->intersection_link; intersection *isc= new_intersection(); + GCALC_DBUG_ENTER("Gcalc_scan_iterator::add_intersection"); if (!isc) - return 1; + GCALC_DBUG_RETURN(1); m_n_intersections++; **p_hook= isc; @@ -1462,15 +1448,7 @@ int Gcalc_scan_iterator::add_intersection(int n_row, isc->ii= m_heap->new_intersection(a0->pi, a0->next_pi, b0->pi, b0->next_pi); -#ifndef NO_TESTING - //if (isc_counter == 40) - { - long double ix, iy; - isc->ii->calc_xy_ld(&ix, &iy); - printf("%d\t%d\t%.20LG\t%.20LG\t%d\n", isc->thread_a, isc->thread_b, ix, iy, isc->n_row); - } -#endif /*NO_TESTING*/ - return isc->ii == NULL; + GCALC_DBUG_RETURN(isc->ii == NULL); } @@ -1478,10 +1456,7 @@ int Gcalc_scan_iterator::find_intersections() { Gcalc_dyn_list::Item **hook; -#ifndef NO_TESTING - ++isc_counter; - printf("Looking for intersections\n"); -#endif /*NO_TESTING*/ + GCALC_DBUG_ENTER("Gcalc_scan_iterator::find_intersections"); m_n_intersections= 0; { /* Set links between slicepoints */ @@ -1489,18 +1464,9 @@ int Gcalc_scan_iterator::find_intersections() point *sp1= next_state->slice; for (; sp1; sp0= sp0->get_next(),sp1= sp1->get_next()) { - DBUG_ASSERT(!sp0->is_bottom()); - DBUG_ASSERT(sp0->thread == sp1->thread); + GCALC_DBUG_ASSERT(!sp0->is_bottom()); + GCALC_DBUG_ASSERT(sp0->thread == sp1->thread); sp1->intersection_link= sp0; -#ifndef NO_TESTING - //if (isc_counter == 40) - { - long double spx, spx1; - sp0->calc_x(&spx, current_state->pi->y, current_state->pi->x); - sp1->calc_x(&spx1, m_cur_pi->y, m_cur_pi->x); - printf("%d\t%.20LG\t%.20LG\n", sp0->thread, spx, spx1); - } -#endif /*NO_TESTING*/ } } @@ -1526,7 +1492,7 @@ int Gcalc_scan_iterator::find_intersections() } intersections_found= true; if (add_intersection(n_row, prev_s1, s1, &hook)) - return 1; + GCALC_DBUG_RETURN(1); *pprev_s1= s1; prev_s1->next= s1->next; s1->next= prev_s1; @@ -1537,7 +1503,7 @@ int Gcalc_scan_iterator::find_intersections() } while (intersections_found); *hook= NULL; - return 0; + GCALC_DBUG_RETURN(0); } @@ -1584,76 +1550,6 @@ static void calc_isc_exp(Gcalc_coord5 *exp, } -#ifdef TMP_BLOCK -static void calc_aa1_b(Gcalc_coord2 *res, - const Gcalc_heap::Info *a0, - const Gcalc_heap::Info *a1, - const Gcalc_coord1 *xb, - const Gcalc_coord1 *yb) -{ - Gcalc_coord1 aa1_x, aa1_y; - Gcalc_coord2 p1, p2; - res->init(); - aa1_x.init(); - aa1_y.init(); - p1.init(); - p2.init(); - - gcalc_sub_coord(&aa1_x, &a1->ix, &a0->ix); - gcalc_sub_coord(&aa1_y, &a1->iy, &a0->iy); - gcalc_mul_coord(&p1, &aa1_x, yb); - gcalc_mul_coord(&p2, &aa1_y, xb); - gcalc_sub_coord(res, &p1, &p2); -} - - -static int cmp_intersections_y(const Gcalc_heap::Intersection_info *i1, - const Gcalc_heap::Intersection_info *i2) -{ - Gcalc_coord2 t_a1, t_b1; - Gcalc_coord2 t_a2, t_b2; - Gcalc_coord1 yb1, yb2; - Gcalc_coord1 xb1, xb2; - Gcalc_coord5 exp_a, exp_b; - - calc_t(&t_a1, &t_b1, &xb1, &yb1, i1); - calc_t(&t_a2, &t_b2, &xb2, &yb2, i2); - - calc_isc_exp(&exp_a, &t_b2, &i1->p1->iy, &t_b1, &yb1, &t_a1); - calc_isc_exp(&exp_b, &t_b1, &i2->p1->iy, &t_b2, &yb2, &t_a2); - - int result= gcalc_cmp_coord(&exp_a, &exp_b); -#ifdef GCALC_CHECK_WITH_FLOAT - long double x1, y1, x2,y2; - i1->calc_xy_ld(&x1, &y1); - i2->calc_xy_ld(&x2, &y2); - - if (result == 0) - DBUG_ASSERT(de_check(y1, y2)); - if (result < 0) - DBUG_ASSERT(de_check1(y1, y2) || y1 < y2); - if (result > 0) - DBUG_ASSERT(de_check1(y1, y2) || y1 > y2); -#endif /*GCALC_CHECK_WITH_FLOAT*/ - return result; -} - - -static int compare_intersections(const void *e1, const void *e2) -{ - Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1; - Gcalc_scan_iterator::intersection *i2= (Gcalc_scan_iterator::intersection *)e2; - int result= cmp_intersections_y(i1->ii, i2->ii); - if (result != 0) - return result > 0; - return (i1->n_row > i2->n_row); -} - -#endif /*TMP_BLOCK*/ - -#ifndef NO_TESTING -extern int ca_counter; -#endif /*NO_TESTING*/ static int cmp_intersections(const Gcalc_heap::Intersection_info *i1, const Gcalc_heap::Intersection_info *i2) { @@ -1677,15 +1573,11 @@ static int cmp_intersections(const Gcalc_heap::Intersection_info *i1, i2->calc_xy_ld(&x2, &y2); if (result == 0) - DBUG_ASSERT(de_weak(y1, y2)); -#ifndef NO_TESTING - if (ca_counter == 7) - printf("77"); -#endif /*NO_TESTING*/ + GCALC_DBUG_ASSERT(de_check(y1, y2)); if (result < 0) - DBUG_ASSERT(de_weak(y1, y2) || y1 < y2); + GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 < y2); if (result > 0) - DBUG_ASSERT(de_weak(y1, y2) || y1 > y2); + GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 > y2); #endif /*GCALC_CHECK_WITH_FLOAT*/ if (result != 0) @@ -1697,11 +1589,11 @@ static int cmp_intersections(const Gcalc_heap::Intersection_info *i1, result= gcalc_cmp_coord(&exp_a, &exp_b); #ifdef GCALC_CHECK_WITH_FLOAT if (result == 0) - DBUG_ASSERT(de_weak(x1, x2)); + GCALC_DBUG_ASSERT(de_check(x1, x2)); if (result < 0) - DBUG_ASSERT(de_weak(x1, x2) || x1 < x2); + GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 < x2); if (result > 0) - DBUG_ASSERT(de_weak(x1, x2) || x1 > x2); + GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 > x2); #endif /*GCALC_CHECK_WITH_FLOAT*/ return result; } @@ -1723,28 +1615,6 @@ inline int intersections_eq(const Gcalc_heap::Intersection_info *i1, } -#ifdef TMP_BLOCK -static void calc_isc_sp_exp(Gcalc_coord4 *exp, - const Gcalc_coord2 *bb, - const Gcalc_coord1 *x1, - const Gcalc_coord1 *y1, - const Gcalc_coord1 *x2, - const Gcalc_coord1 *y2) -{ - Gcalc_coord2 p1, p2, sum; - p1.init(); - p2.init(); - sum.init(); - exp->init(); - - gcalc_mul_coord(&p1, x1, y1); - gcalc_mul_coord(&p2, x2, y2); - gcalc_add_coord(&sum, &p1, &p2); - gcalc_mul_coord(exp, bb, &sum); -} -#endif /*TMP_BLOCK*/ - - static int sp_isc_eq(const Gcalc_scan_iterator::point *sp, const Gcalc_heap::Intersection_info *isc) { @@ -1753,17 +1623,6 @@ static int sp_isc_eq(const Gcalc_scan_iterator::point *sp, Gcalc_coord1 xb1, yb1; Gcalc_coord2 t_a, t_b; Gcalc_coord2 t_sp_a, t_sp_b; -#ifdef TMP_BLOCK - xa1a0.init(); - ya1a0.init(); - - gcalc_sub_coord(&xa1a0, &isc->p1->ix, &sp->pi->ix); - gcalc_sub_coord(&ya1a0, &isc->p1->iy, &sp->pi->iy); - calc_isc_sp_exp(&exp_a, &t_b, &sp->pi->ix, &ya1a0, &sp->pi->iy, &xa1a0); - calc_isc_sp_exp(&exp_b, &t_a, &sp->pi->iy, &isc->p1->ix, - &sp->pi->ix, &isc->p1->iy); - return gcalc_cmp_coord(&exp_a, &exp_b); -#endif /*TMP_BLOCK*/ exp_a.init(); exp_b.init(); calc_t(&t_a, &t_b, &xb1, &yb1, isc); @@ -1777,12 +1636,8 @@ static int sp_isc_eq(const Gcalc_scan_iterator::point *sp, isc->calc_xy_ld(&int_x, &int_y); sp->calc_x(&sp_x, int_y, int_x); if (result == 0) - DBUG_ASSERT(de_check1(sp->dy.get_double(), 0.0) || - de_check(sp_x, int_x)); -#ifdef TMP_BLOCK - else - DBUG_ASSERT(!de_check1(sp_x, int_x)); -#endif /*TMP_BLOCK*/ + GCALC_DBUG_ASSERT(de_check(sp->dy.get_double(), 0.0) || + de_check(sp_x, int_x)); #endif /*GCALC_CHECK_WITH_FLOAT*/ return result == 0; } @@ -1797,11 +1652,15 @@ inline void Gcalc_scan_iterator::sort_intersections() int Gcalc_scan_iterator::handle_intersections() { - DBUG_ASSERT(next_state->slice->next); + GCALC_DBUG_ENTER("Gcalc_scan_iterator::handle_intersections"); + GCALC_DBUG_ASSERT(next_state->slice->next); if (find_intersections()) - return 1; + GCALC_DBUG_RETURN(1); + GCALC_DBUG_PRINT_INTERSECTIONS(m_intersections); sort_intersections(); + GCALC_DBUG_PRINT(("After sorting")); + GCALC_DBUG_PRINT_INTERSECTIONS(m_intersections); /* Swap saved <-> next */ { @@ -1812,19 +1671,7 @@ int Gcalc_scan_iterator::handle_intersections() /* We need the next slice to be just equal */ next_state->slice= new_slice(saved_state->slice); m_cur_intersection= m_intersections; -#ifndef NO_TESTING - //if (isc_counter == 40) - { - printf("Sorted\n"); - for (intersection *isc= m_intersections; isc; isc= isc->get_next()) - { - long double ix, iy; - isc->ii->calc_xy_ld(&ix, &iy); - printf("%d\t%d\t%.20LG\t%.20LG\t%d\n", isc->thread_a, isc->thread_b, ix, iy, isc->n_row); - } - } -#endif /*NO_TESTING*/ - return intersection_scan(); + GCALC_DBUG_RETURN(intersection_scan()); } @@ -1834,8 +1681,11 @@ int Gcalc_scan_iterator::intersection_scan() Gcalc_dyn_list::Item **hook; intersection *next_intersection= NULL; + GCALC_DBUG_ENTER("Gcalc_scan_iterator::intersection_scan"); + GCALC_DBUG_CHECK_COUNTER(); if (m_cur_intersection != m_intersections) { + GCALC_DBUG_PRINT_SLICE("in_isc\t", next_state->slice); /* Swap current <-> next */ { slice_state *tmp= current_state; @@ -1844,33 +1694,9 @@ int Gcalc_scan_iterator::intersection_scan() } if (arrange_event()) - return 1; + GCALC_DBUG_RETURN(1); -#ifdef TMP_BLOCK - if (!m_cur_intersection) - { - saved_state->event_position_hook= - (Gcalc_dyn_list::Item **) &saved_state->slice; - - for (sp1= saved_state->slice; sp1; sp1= sp1->get_next()) - { - if (sp1->get_next() == saved_state->event_position) - saved_state->event_position_hook= &sp1->next; - } - /* Swap saved <-> next */ - { - slice_state *tmp= next_state; - next_state= saved_state; - saved_state= tmp; - } - free_list(saved_state->slice); - saved_state->slice= NULL; - - free_list(m_intersections); - m_intersections= NULL; - return 0; - } -#endif /*TMP_BLOCK*/ + GCALC_DBUG_PRINT_SLICE("isc_after_arrange\t", current_state->slice); if (!m_cur_intersection) { /* Swap saved <-> next */ @@ -1894,8 +1720,9 @@ int Gcalc_scan_iterator::intersection_scan() point *fnd_s= sp1->get_next(); Gcalc_dyn_list::Item **fnd_hook= &sp1->next; for (; fnd_s && fnd_s->thread != sp0->thread; - fnd_hook= &fnd_s->next, fnd_s= fnd_s->get_next()); - DBUG_ASSERT(fnd_s && fnd_s == *fnd_hook); + fnd_hook= &fnd_s->next, fnd_s= fnd_s->get_next()) + {} + GCALC_DBUG_ASSERT(fnd_s && fnd_s == *fnd_hook); /* Now swap items of the next_state->slice */ *n_hook= fnd_s; *fnd_hook= fnd_s->next; @@ -1905,19 +1732,19 @@ int Gcalc_scan_iterator::intersection_scan() if (sp1->event) mark_event_position1(sp1, n_hook); } -#ifndef DBUG_OFF +#ifndef GCALC_DBUG_OFF sp0= current_state->slice; sp1= next_state->slice; for (; sp0; sp0= sp0->get_next(), sp1= sp1->get_next()) - DBUG_ASSERT(sp0->thread == sp1->thread); - DBUG_ASSERT(!sp1); -#endif /*DBUG_OFF*/ + GCALC_DBUG_ASSERT(sp0->thread == sp1->thread); + GCALC_DBUG_ASSERT(!sp1); +#endif /*GCALC_DBUG_OFF*/ free_list(saved_state->slice); saved_state->slice= NULL; free_list(m_intersections); m_intersections= NULL; - return 0; + GCALC_DBUG_RETURN(0); } } @@ -1934,15 +1761,17 @@ int Gcalc_scan_iterator::intersection_scan() if (sp0->thread == m_cur_intersection->thread_a || sp0->thread == m_cur_intersection->thread_b) { - DBUG_ASSERT(sp0->thread != m_cur_intersection->thread_a || + GCALC_DBUG_ASSERT(sp0->thread != m_cur_intersection->thread_a || sp0->get_next()->thread == m_cur_intersection->thread_b || sp_isc_eq(sp0->get_next(), m_cur_intersection->ii)); + GCALC_DBUG_PRINT(("isc_i_thread %d", sp0->thread)); sp1->copy_core(sp0); sp1->event= scev_intersection; mark_event_position1(sp1, hook); } else { + GCALC_DBUG_PRINT(("isc_cut %d", sp0->thread)); sp1->copy_core(sp0); if (sp_isc_eq(sp1, m_cur_intersection->ii)) { @@ -1967,6 +1796,7 @@ int Gcalc_scan_iterator::intersection_scan() next_intersection= next_intersection->get_next()) { /* Handle equal intersections. We only need to set proper events */ + GCALC_DBUG_PRINT(("isc_eq_intersection")); sp0= current_state->slice; hook= (Gcalc_dyn_list::Item **) &next_state->slice; sp1= next_state->slice; @@ -1979,6 +1809,7 @@ int Gcalc_scan_iterator::intersection_scan() sp0->thread == next_intersection->thread_b || sp1->event == scev_intersection) { + GCALC_DBUG_PRINT(("isc_eq_thread %d", sp0->thread)); sp1->event= scev_intersection; mark_event_position1(sp1, hook); } @@ -1986,7 +1817,7 @@ int Gcalc_scan_iterator::intersection_scan() } m_cur_intersection= next_intersection; - return 0; + GCALC_DBUG_RETURN(0); } diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index fe7959c4172..7c2bc85fe03 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -17,6 +17,16 @@ #ifndef GCALC_SLICESCAN_INCLUDED #define GCALC_SLICESCAN_INCLUDED +#ifndef DBUG_OFF +#define GCALC_CHECK_WITH_FLOAT +#else +#define GCALC_DBUG_OFF +#endif /*DBUG_OFF*/ + +#define GCALC_DBUG_PRINT(b) DBUG_PRINT("Gcalc", b) +#define GCALC_DBUG_ENTER(a) DBUG_ENTER("Gcalc "a) +#define GCALC_DBUG_RETURN(r) DBUG_RETURN(r) +#define GCALC_DBUG_ASSERT(r) DBUG_ASSERT(r) /* Gcalc_dyn_list class designed to manage long lists of same-size objects @@ -102,12 +112,6 @@ typedef long long coord2; #define C_SCALE 1e13 #define COORD_BASE 2 -#ifndef DBUG_OFF -//#define GCALC_CHECK_WITH_FLOAT -#define NO_TESTING -#else -#define NO_TESTING -#endif /*DBUG_OFF*/ class Gcalc_internal_coord { @@ -349,22 +353,17 @@ public: class point : public Gcalc_dyn_list::Item { public: -#ifdef TMP_BLOCK - double x; - double dx_dy; - int horiz_dir; -#endif /*TMP_BLOCK*/ Gcalc_coord1 dx; Gcalc_coord1 dy; Gcalc_heap::Info *pi; Gcalc_heap::Info *next_pi; sc_thread_id thread; + const Gcalc_coord1 *l_border; + const Gcalc_coord1 *r_border; + int always_on_left; const point *intersection_link; Gcalc_scan_events event; -#ifdef TO_REMOVE - point *next_link; -#endif /*TO_REMOVE*/ inline const point *c_get_next() const { return (const point *)next; } @@ -377,10 +376,6 @@ public: void copy_all(const point *from); /* Compare the dx_dy parameters regarding the horiz_dir */ /* returns -1 if less, 0 if equal, 1 if bigger */ -#ifdef TMP_BLOCK - static int cmp_dx_dy(int horiz_dir_a, double dx_dy_a, - int horiz_dir_b, double dx_dy_b); -#endif /*TMP_BLOCK*/ static int cmp_dx_dy(const Gcalc_coord1 *dx_a, const Gcalc_coord1 *dy_a, const Gcalc_coord1 *dx_b, @@ -409,10 +404,6 @@ public: int n_row; sc_thread_id thread_a; sc_thread_id thread_b; -#ifdef TMP_BLOCK - double x; - double y; -#endif /*TMP_BLOCK*/ const Gcalc_heap::Intersection_info *ii; inline intersection *get_next() { return (intersection *)next; } }; @@ -430,9 +421,6 @@ public: const Gcalc_heap::Info *pi; const Gcalc_heap::Intersection_info *isc; }; -#ifdef TMP_BLOCK - double y; -#endif /*TMP_BLOCK*/ slice_state() : slice(NULL) {} void clear_event_position() { diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 8e881b84c5d..5871dce8642 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -135,6 +135,8 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type, int result; const char *sav_cur_func= cur_func; + // GCALC_DBUG_ENTER("Gcalc_function::count_internal"); + cur_func+= 4; if (next_func == op_shape) { @@ -167,6 +169,7 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type, if (n_ops == 0) return mask; + //GCALC_DBUG_RETURN(mask); result= count_internal(cur_func, set_type, &cur_func); @@ -219,13 +222,14 @@ exit: result= 0; break; default: - DBUG_ASSERT(0); + GCALC_DBUG_ASSERT(0); }; } if (end) *end= cur_func; return result; + //GCALC_DBUG_RETURN(result); } @@ -258,11 +262,12 @@ void Gcalc_function::reset() int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) { const Gcalc_scan_iterator::point *eq_start, *cur_eq, *events; + GCALC_DBUG_ENTER("Gcalc_function::check_function"); while (scan_it.more_points()) { if (scan_it.step()) - return -1; + GCALC_DBUG_RETURN(-1); events= scan_it.get_events(); /* these kinds of events don't change the function */ @@ -282,7 +287,7 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) set_b_state(events->get_shape()); if (count()) - return 1; + GCALC_DBUG_RETURN(1); clear_b_states(); continue; } @@ -301,7 +306,7 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) } if (count()) - return 1; + GCALC_DBUG_RETURN(1); /* Set back states changed in the loop above. */ for (events= scan_it.get_events(); events; events= events->get_next()) @@ -337,7 +342,7 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) invert_i_state(si); } if (count()) - return 1; + GCALC_DBUG_RETURN(1); for (cur_eq= eq_start; cur_eq != pit.point(); cur_eq= cur_eq->get_next()) { @@ -351,11 +356,11 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) invert_i_state(cur_eq->get_shape()); } if (count()) - return 1; + GCALC_DBUG_RETURN(1); eq_start= pit.point(); } while (pit.point() != scan_it.get_event_end()); } - return 0; + GCALC_DBUG_RETURN(0); } @@ -435,52 +440,51 @@ int Gcalc_operation_transporter::empty_shape() int Gcalc_result_receiver::start_shape(Gcalc_function::shape_type shape) { + GCALC_DBUG_ENTER("Gcalc_result_receiver::start_shape"); if (buffer.reserve(4*2, 512)) - return 1; + GCALC_DBUG_RETURN(1); cur_shape= shape; shape_pos= buffer.length(); buffer.length(shape_pos + ((shape == Gcalc_function::shape_point) ? 4:8)); n_points= 0; shape_area= 0.0; - return 0; + GCALC_DBUG_RETURN(0); } int Gcalc_result_receiver::add_point(double x, double y) { + GCALC_DBUG_ENTER("Gcalc_result_receiver::add_point"); if (n_points && x == prev_x && y == prev_y) - return 0; + GCALC_DBUG_RETURN(0); if (!n_points++) { prev_x= first_x= x; prev_y= first_y= y; - return 0; + GCALC_DBUG_RETURN(0); } shape_area+= prev_x*y - prev_y*x; if (buffer.reserve(8*2, 512)) - return 1; + GCALC_DBUG_RETURN(1); buffer.q_append(prev_x); buffer.q_append(prev_y); prev_x= x; prev_y= y; -#ifndef NO_TESTING - if (n_points == 53) - printf("xxx\n"); -#endif /*NO_TESTING*/ - return 0; + GCALC_DBUG_RETURN(0); } int Gcalc_result_receiver::complete_shape() { + GCALC_DBUG_ENTER("Gcalc_result_receiver::complete_shape"); if (n_points == 0) { buffer.length(shape_pos); - return 0; + GCALC_DBUG_RETURN(0); } if (n_points == 1) { @@ -489,7 +493,7 @@ int Gcalc_result_receiver::complete_shape() if (cur_shape == Gcalc_function::shape_hole) { buffer.length(shape_pos); - return 0; + GCALC_DBUG_RETURN(0); } cur_shape= Gcalc_function::shape_point; buffer.length(buffer.length()-4); @@ -504,7 +508,7 @@ int Gcalc_result_receiver::complete_shape() if (fabs(shape_area) < 1e-8) { buffer.length(shape_pos); - return 0; + GCALC_DBUG_RETURN(0); } } @@ -520,7 +524,7 @@ int Gcalc_result_receiver::complete_shape() } if (buffer.reserve(8*2, 512)) - return 1; + GCALC_DBUG_RETURN(1); buffer.q_append(prev_x); buffer.q_append(prev_y); @@ -540,7 +544,7 @@ do_complete: { collection_result= true; } - return 0; + GCALC_DBUG_RETURN(0); } @@ -593,28 +597,30 @@ int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_positio { char *ptr; int source_len; + GCALC_DBUG_ENTER("Gcalc_result_receiver::move_hole"); + GCALC_DBUG_PRINT(("ps %d %d", dest_position, source_position)); *position_shift= source_len= buffer.length() - source_position; if (dest_position == source_position) - return 0; + GCALC_DBUG_RETURN(0); if (buffer.reserve(source_len, MY_ALIGN(source_len, 512))) - return 1; + GCALC_DBUG_RETURN(1); ptr= (char *) buffer.ptr(); memmove(ptr + dest_position + source_len, ptr + dest_position, buffer.length() - dest_position); memcpy(ptr + dest_position, ptr + buffer.length(), source_len); - return 0; + GCALC_DBUG_RETURN(0); } Gcalc_operation_reducer::Gcalc_operation_reducer(size_t blk_size) : Gcalc_dyn_list(blk_size, sizeof(res_point)), -#ifndef DBUG_OFF +#ifndef GCALC_DBUG_OFF n_res_points(0), -#endif /*DBUG_OFF*/ +#endif /*GCALC_DBUG_OFF*/ m_res_hook((Gcalc_dyn_list::Item **)&m_result), m_first_active_thread(NULL) {} @@ -649,43 +655,35 @@ void Gcalc_operation_reducer::res_point::set(const Gcalc_scan_iterator *si) pi= si->get_cur_pi(); } -#ifndef NO_TESTING -void call_checkpoint(int d) -{ - printf("%d\n", d); -} -#endif /*NO_TESTING*/ Gcalc_operation_reducer::res_point * Gcalc_operation_reducer::add_res_point(Gcalc_function::shape_type type) { + GCALC_DBUG_ENTER("Gcalc_operation_reducer::add_res_point"); res_point *result= (res_point *)new_item(); *m_res_hook= result; result->prev_hook= m_res_hook; m_res_hook= &result->next; result->type= type; -#ifndef DBUG_OFF +#ifndef GCALC_DBUG_OFF result->point_n= n_res_points++; -#endif /*DBUG_OFF*/ -#ifndef NO_TESTING - if (result->point_n == 74) - call_checkpoint(74); -#endif /*NO_TESTING*/ - return result; +#endif /*GCALC_DBUG_OFF*/ + GCALC_DBUG_RETURN(result); } int Gcalc_operation_reducer::add_line(int incoming, active_thread *t, const Gcalc_scan_iterator::point *p) { line *l= new_line(); + GCALC_DBUG_ENTER("Gcalc_operation_reducer::add_line"); if (!l) - return 1; + GCALC_DBUG_RETURN(1); l->incoming= incoming; l->t= t; l->p= p; *m_lines_hook= l; m_lines_hook= &l->next; - return 0; + GCALC_DBUG_RETURN(0); } @@ -693,15 +691,16 @@ int Gcalc_operation_reducer::add_poly_border(int incoming, active_thread *t, int prev_state, const Gcalc_scan_iterator::point *p) { poly_border *b= new_poly_border(); + GCALC_DBUG_ENTER("Gcalc_operation_reducer::add_poly_border"); if (!b) - return 1; + GCALC_DBUG_RETURN(1); b->incoming= incoming; b->t= t; b->prev_state= prev_state; b->p= p; *m_poly_borders_hook= b; m_poly_borders_hook= &b->next; - return 0; + GCALC_DBUG_RETURN(0); } @@ -710,8 +709,9 @@ int Gcalc_operation_reducer::continue_range(active_thread *t, const Gcalc_heap::Info *p_next) { res_point *rp= add_res_point(t->rp->type); + GCALC_DBUG_ENTER("Gcalc_operation_reducer::continue_range"); if (!rp) - return 1; + GCALC_DBUG_RETURN(1); rp->glue= NULL; rp->down= t->rp; t->rp->up= rp; @@ -720,7 +720,7 @@ int Gcalc_operation_reducer::continue_range(active_thread *t, t->rp= rp; t->p1= p; t->p2= p_next; - return 0; + GCALC_DBUG_RETURN(0); } @@ -728,25 +728,27 @@ inline int Gcalc_operation_reducer::continue_i_range(active_thread *t, const Gcalc_heap::Intersection_info *ii) { res_point *rp= add_res_point(t->rp->type); + GCALC_DBUG_ENTER("Gcalc_operation_reducer::continue_i_range"); if (!rp) - return 1; + GCALC_DBUG_RETURN(1); rp->glue= NULL; rp->down= t->rp; t->rp->up= rp; rp->intersection_point= true; rp->ii= ii; t->rp= rp; - return 0; + GCALC_DBUG_RETURN(0); } int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p) { res_point *rp0, *rp1; + GCALC_DBUG_ENTER("Gcalc_operation_reducer::end_couple"); DBUG_ASSERT(t0->rp->type == t1->rp->type); if (!(rp0= add_res_point(t0->rp->type)) || !(rp1= add_res_point(t0->rp->type))) - return 1; + GCALC_DBUG_RETURN(1); rp0->down= t0->rp; rp1->down= t1->rp; rp1->glue= rp0; @@ -756,19 +758,13 @@ int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1, t1->rp->up= rp1; rp0->intersection_point= rp1->intersection_point= false; rp0->pi= rp1->pi= p; - return 0; + GCALC_DBUG_RETURN(0); } -#ifndef NO_TESTING -int ca_counter= 0; -#endif /*NO_TESTING*/ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { Gcalc_point_iterator pi(si); -#ifdef TMP_BLOCK - const Gcalc_heap::Info *event_point= NULL; -#endif /*TMP_BLOCK*/ int prev_state= 0; int sav_prev_state; active_thread *prev_range= NULL; @@ -778,17 +774,10 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) active_thread **starting_t_hook; active_thread *bottom_threads= NULL; active_thread *eq_thread, *point_thread;; + GCALC_DBUG_ENTER("Gcalc_operation_reducer::count_slice"); -#ifndef NO_TESTING - if (ca_counter == 11522) - call_checkpoint(89); -#endif /*NO_TESTING*/ m_fn->clear_i_states(); /* Walk to the event, remembering what is needed. */ -#ifndef NO_TESTING - if (si->get_event_position() == pi.point()) - printf("yyy\n"); -#endif /*NO_TESTING*/ for (; pi.point() != si->get_event_position(); ++pi, cur_t_hook= (active_thread **) &(*cur_t_hook)->next) { @@ -813,13 +802,13 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { if (cur_t->enabled() && continue_range(cur_t, events->pi, events->next_pi)) - return 1; + GCALC_DBUG_RETURN(1); break; } case scev_end: { if (cur_t->enabled() && end_line(cur_t, si)) - return 1; + GCALC_DBUG_RETURN(1); *cur_t_hook= cur_t->get_next(); free_item(cur_t); break; @@ -830,13 +819,13 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { /* When two threads are ended here */ if (end_couple(cur_t, cur_t->get_next(), events->pi)) - return 1; + GCALC_DBUG_RETURN(1); } else if (cur_t->enabled() || cur_t->get_next()->enabled()) { /* Rare case when edges of a polygon coincide */ if (end_line(cur_t->enabled() ? cur_t : cur_t->get_next(), si)) - return 1; + GCALC_DBUG_RETURN(1); } *cur_t_hook= cur_t->get_next()->get_next(); free_item(cur_t->next); @@ -846,10 +835,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) default: DBUG_ASSERT(0); } -#ifndef NO_TESTING - goto testing; -#endif /*NO_TESTING*/ - return 0; + GCALC_DBUG_RETURN(0); } starting_t_hook= cur_t_hook; @@ -860,10 +846,6 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { active_thread *cur_t= *cur_t_hook; -#ifdef TMP_BLOCK - if (!event_point && events->event != scev_intersection) - event_point= events->pi; -#endif /*TMP_BLOCK*/ if (events->event == scev_single_point) continue; @@ -872,7 +854,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { active_thread *new_t= new_active_thread(); if (!new_t) - return 1; + GCALC_DBUG_RETURN(1); new_t->rp= NULL; /* Insert into the main thread list before the current */ new_t->next= cur_t; @@ -904,7 +886,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { active_thread *new_t= new_active_thread(); if (!new_t) - return 1; + GCALC_DBUG_RETURN(1); new_t->rp= NULL; /* Replace the current thread with the new. */ new_t->next= cur_t->next; @@ -952,12 +934,12 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) if (prev_state != after_state) { if (add_poly_border(0, eq_thread, prev_state, eq_start)) - return 1; + GCALC_DBUG_RETURN(1); } else if (!prev_state /* &&!after_state */ && in_state) { if (add_line(0, eq_thread, eq_start)) - return 1; + GCALC_DBUG_RETURN(1); } prev_state= after_state; @@ -978,7 +960,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) for (events= si->get_events(); events; events= events->get_next()) m_fn->set_b_state(events->get_shape()); - return m_fn->count() ? add_single_point(si) : 0; + GCALC_DBUG_RETURN(m_fn->count() ? add_single_point(si) : 0); } if (m_poly_borders) @@ -988,10 +970,6 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { poly_border *pb1, *pb2; pb1= m_poly_borders; -#ifndef NO_TESTING - if (!m_poly_borders->next) - call_checkpoint(3); -#endif /*NO_TESTING*/ DBUG_ASSERT(m_poly_borders->next); pb2= get_pair_border(pb1); @@ -1000,7 +978,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) if (connect_threads(pb1->incoming, pb2->incoming, pb1->t, pb2->t, pb1->p, pb2->p, prev_range, si, Gcalc_function::shape_polygon)) - return 1; + GCALC_DBUG_RETURN(1); free_item(pb1); free_item(pb2); @@ -1019,7 +997,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) m_lines->t, m_lines->get_next()->t, m_lines->p, m_lines->get_next()->p, NULL, si, Gcalc_function::shape_line)) - return 1; + GCALC_DBUG_RETURN(1); } else { @@ -1028,7 +1006,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) if (cur_line->incoming) { if (end_line(cur_line->t, si)) - return 1; + GCALC_DBUG_RETURN(1); } else start_line(cur_line->t, cur_line->p, si); @@ -1042,57 +1020,19 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) if (bottom_threads) free_list(bottom_threads); -#ifndef NO_TESTING -testing: - { - Gcalc_point_iterator x_pi(si); - active_thread **x_cur_t_hook= &m_first_active_thread; - int x_prev_state= 0; - m_fn->save_states(); - m_fn->clear_state(); - if (ca_counter == /*11552*/90) - call_checkpoint(10); - for (; x_pi.point(); ++x_pi) - { - active_thread *cur_t= *x_cur_t_hook; - if (cur_t->enabled() && - cur_t->rp->type == Gcalc_function::shape_polygon) - x_prev_state^= 1; - int ppb= m_fn->count(); - if (m_fn->get_shape_kind(x_pi.get_shape()) == Gcalc_function::shape_polygon) - m_fn->invert_state(x_pi.get_shape()); - int ppa= m_fn->count(); - if (ppa != x_prev_state) - { - if (x_pi.point()->cmp_dx_dy(x_pi.point()->get_next()) != 0) - call_checkpoint(21); - } - if (cur_t->enabled()) - { - if (m_fn->get_shape_kind(x_pi.get_shape()) == Gcalc_function::shape_polygon) - if (ppa == ppb) - call_checkpoint(22); - else - if (ppa != 0 && ppb != 0) - call_checkpoint(23); - } - x_cur_t_hook= (active_thread **) &(*x_cur_t_hook)->next; - } - m_fn->restore_states(); - } -#endif /*NO_TESTING*/ - return 0; + GCALC_DBUG_RETURN(0); } int Gcalc_operation_reducer::add_single_point(const Gcalc_scan_iterator *si) { res_point *rp= add_res_point(Gcalc_function::shape_point); + GCALC_DBUG_ENTER("Gcalc_operation_reducer::add_single_point"); if (!rp) - return 1; + GCALC_DBUG_RETURN(1); rp->glue= rp->up= rp->down= NULL; rp->set(si); - return 0; + GCALC_DBUG_RETURN(0); } @@ -1101,6 +1041,7 @@ Gcalc_operation_reducer::poly_border { poly_border *prev_b= b1; poly_border *result= b1->get_next(); + GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_pair_border"); if (b1->prev_state) { if (b1->incoming) @@ -1140,7 +1081,7 @@ Gcalc_operation_reducer::poly_border } /* Delete the result from the list. */ prev_b->next= result->next; - return result; + GCALC_DBUG_RETURN(result); } @@ -1151,13 +1092,15 @@ int Gcalc_operation_reducer::connect_threads( active_thread *prev_range, const Gcalc_scan_iterator *si, Gcalc_function::shape_type s_t) { + GCALC_DBUG_ENTER("Gcalc_operation_reducer::connect_threads"); + GCALC_DBUG_PRINT(("incoming %d %d", incoming_a, incoming_b)); if (incoming_a && incoming_b) { res_point *rpa, *rpb; DBUG_ASSERT(ta->rp->type == tb->rp->type); if (!(rpa= add_res_point(ta->rp->type)) || !(rpb= add_res_point(ta->rp->type))) - return 1; + GCALC_DBUG_RETURN(1); rpa->down= ta->rp; rpb->down= tb->rp; rpb->glue= rpa; @@ -1168,7 +1111,7 @@ int Gcalc_operation_reducer::connect_threads( rpa->set(si); rpb->set(si); ta->rp= tb->rp= NULL; - return 0; + GCALC_DBUG_RETURN(0); } if (!incoming_a) { @@ -1176,7 +1119,7 @@ int Gcalc_operation_reducer::connect_threads( res_point *rp0, *rp1; if (!(rp0= add_res_point(s_t)) || !(rp1= add_res_point(s_t))) - return 1; + GCALC_DBUG_RETURN(1); rp0->glue= rp1; rp1->glue= rp0; rp0->set(si); @@ -1204,7 +1147,7 @@ int Gcalc_operation_reducer::connect_threads( /* Chack if needed */ tb->thread_start= rp0; } - return 0; + GCALC_DBUG_RETURN(0); } /* else, if only ta is incoming */ @@ -1217,15 +1160,12 @@ int Gcalc_operation_reducer::connect_threads( if (si->intersection_step() ? continue_i_range(tb, si->get_cur_ii()) : continue_range(tb, si->get_cur_pi(), pb->next_pi)) -#ifdef TMP_BLOCK - continue_range(tb, si->get_cur_pi()) -#endif /*TMP_BLOCK*/ - return 1; + GCALC_DBUG_RETURN(1); } tb->p1= pb->pi; tb->p2= pb->next_pi; - return 0; + GCALC_DBUG_RETURN(0); } @@ -1234,51 +1174,49 @@ int Gcalc_operation_reducer::start_line(active_thread *t, const Gcalc_scan_iterator *si) { res_point *rp= add_res_point(Gcalc_function::shape_line); + GCALC_DBUG_ENTER("Gcalc_operation_reducer::start_line"); if (!rp) - return 1; + GCALC_DBUG_RETURN(1); rp->glue= rp->down= NULL; rp->set(si); t->rp= rp; t->p1= p->pi; t->p2= p->next_pi; - return 0; + GCALC_DBUG_RETURN(0); } int Gcalc_operation_reducer::end_line(active_thread *t, const Gcalc_scan_iterator *si) { + GCALC_DBUG_ENTER("Gcalc_operation_reducer::end_line"); DBUG_ASSERT(t->rp->type == Gcalc_function::shape_line); res_point *rp= add_res_point(Gcalc_function::shape_line); if (!rp) - return 1; + GCALC_DBUG_RETURN(1); rp->glue= rp->up= NULL; rp->down= t->rp; rp->set(si); t->rp->up= rp; t->rp= NULL; - return 0; + GCALC_DBUG_RETURN(0); } int Gcalc_operation_reducer::count_all(Gcalc_heap *hp) { Gcalc_scan_iterator si; + GCALC_DBUG_ENTER("Gcalc_operation_reducer::count_all"); si.init(hp); while (si.more_points()) { -#ifndef NO_TESTING - printf("Point %d\n", ++ca_counter); - if (ca_counter == 12) - call_checkpoint(10); -#endif /*NO_TESTING*/ if (si.step()) - return 1; + GCALC_DBUG_RETURN(1); if (count_slice(&si)) - return 1; + GCALC_DBUG_RETURN(1); } - return 0; + GCALC_DBUG_RETURN(0); } inline void Gcalc_operation_reducer::free_result(res_point *res) @@ -1294,23 +1232,21 @@ inline void Gcalc_operation_reducer::free_result(res_point *res) inline int Gcalc_operation_reducer::get_single_result(res_point *res, Gcalc_result_receiver *storage) { + GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_single_result"); if (res->intersection_point) { double x, y; res->ii->calc_xy(&x, &y); if (storage->single_point(x,y)) - return 1; + GCALC_DBUG_RETURN(1); } else if (storage->single_point(res->pi->x, res->pi->y)) - return 1; + GCALC_DBUG_RETURN(1); free_result(res); - return 0; + GCALC_DBUG_RETURN(0); } -#ifndef NO_TESTING -int pc_counter= 0; -#endif /*NO_TESTING*/ int Gcalc_operation_reducer::get_result_thread(res_point *cur, Gcalc_result_receiver *storage, @@ -1320,13 +1256,9 @@ int Gcalc_operation_reducer::get_result_thread(res_point *cur, res_point *next; bool glue_step= false; double x, y; + GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_result_thread"); while (cur) { -#ifndef NO_TESTING - ++pc_counter; - if (pc_counter == 79) - call_checkpoint(79); -#endif /*NO_TESTING*/ if (!glue_step) { if (cur->intersection_point) @@ -1339,7 +1271,7 @@ int Gcalc_operation_reducer::get_result_thread(res_point *cur, y= cur->pi->y; } if (storage->add_point(x, y)) - return 1; + GCALC_DBUG_RETURN(1); } next= move_upward ? cur->up : cur->down; @@ -1358,7 +1290,7 @@ int Gcalc_operation_reducer::get_result_thread(res_point *cur, free_result(cur); cur= next; } - return 0; + GCALC_DBUG_RETURN(0); } @@ -1366,11 +1298,12 @@ int Gcalc_operation_reducer::get_polygon_result(res_point *cur, Gcalc_result_receiver *storage, res_point *first_poly_node) { + GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_polygon_result"); res_point *glue= cur->glue; glue->up->down= NULL; free_result(glue); - return get_result_thread(cur, storage, 1, first_poly_node) || - storage->complete_shape(); + GCALC_DBUG_RETURN(get_result_thread(cur, storage, 1, first_poly_node) || + storage->complete_shape()); } @@ -1380,6 +1313,7 @@ int Gcalc_operation_reducer::get_line_result(res_point *cur, res_point *next; res_point *cur_orig= cur; int move_upward= 1; + GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_line_result"); if (cur->glue) { /* Here we have to find the beginning of the line */ @@ -1405,8 +1339,8 @@ int Gcalc_operation_reducer::get_line_result(res_point *cur, } } - return get_result_thread(cur, storage, move_upward, 0) || - storage->complete_shape(); + GCALC_DBUG_RETURN(get_result_thread(cur, storage, move_upward, 0) || + storage->complete_shape()); } @@ -1414,6 +1348,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) { poly_instance *polygons= NULL; + GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_result"); *m_res_hook= NULL; while (m_result) @@ -1422,7 +1357,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) if (shape == Gcalc_function::shape_point) { if (get_single_result(m_result, storage)) - return 1; + GCALC_DBUG_RETURN(1); continue; } if (shape == Gcalc_function::shape_polygon) @@ -1439,7 +1374,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) m_result->outer_poly->first_poly_node) || storage->move_hole(insert_position, hole_position, &position_shift)) - return 1; + GCALC_DBUG_RETURN(1); for (cur_poly= polygons; cur_poly && *cur_poly->after_poly_position >= insert_position; cur_poly= cur_poly->get_next()) @@ -1454,7 +1389,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) polygons= p; storage->start_shape(Gcalc_function::shape_polygon); if (get_polygon_result(m_result, storage, m_result)) - return 1; + GCALC_DBUG_RETURN(1); *poly_position= storage->position(); } } @@ -1462,13 +1397,13 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) { storage->start_shape(shape); if (get_line_result(m_result, storage)) - return 1; + GCALC_DBUG_RETURN(1); } } m_res_hook= (Gcalc_dyn_list::Item **)&m_result; storage->done(); - return 0; + GCALC_DBUG_RETURN(0); } diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index d79ba630506..d1087aa83b2 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -222,9 +222,9 @@ public: int get_result(Gcalc_result_receiver *storage); void reset(); -#ifndef DBUG_OFF +#ifndef GCALC_DBUG_OFF int n_res_points; -#endif /*DBUG_OFF*/ +#endif /*GCALC_DBUG_OFF*/ class res_point : public Gcalc_dyn_list::Item { public: @@ -235,23 +235,19 @@ public: const Gcalc_heap::Intersection_info *ii; res_point *first_poly_node; }; -#ifdef TMP_BLOCK union { -#endif /*TMP_BLOCK*/ res_point *outer_poly; uint32 poly_position; -#ifdef TMP_BLOCK }; -#endif /*TMP_BLOCK*/ res_point *up; res_point *down; res_point *glue; Gcalc_function::shape_type type; Gcalc_dyn_list::Item **prev_hook; -#ifndef DBUG_OFF +#ifndef GCALC_DBUG_OFF int point_n; -#endif /*DBUG_OFF*/ +#endif /*GCALC_DBUG_OFF*/ void set(const Gcalc_scan_iterator *si); res_point *get_next() { return (res_point *)next; } }; From 0edb291d3addd93f24b99d1446ed9dfb89bc56ad Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 4 Oct 2011 15:29:39 +0500 Subject: [PATCH 33/40] GIS code cleanup. GCALC_xxx macros fixed for the GCALC_DBUG_OFF case. per-file comments: sql/gcalc_slicescan.h GIS code cleanup. --- sql/gcalc_slicescan.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index 7c2bc85fe03..bf37afd3d66 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -23,10 +23,17 @@ #define GCALC_DBUG_OFF #endif /*DBUG_OFF*/ +#ifndef GCALC_DBUG_OFF #define GCALC_DBUG_PRINT(b) DBUG_PRINT("Gcalc", b) #define GCALC_DBUG_ENTER(a) DBUG_ENTER("Gcalc "a) #define GCALC_DBUG_RETURN(r) DBUG_RETURN(r) #define GCALC_DBUG_ASSERT(r) DBUG_ASSERT(r) +#else +#define GCALC_DBUG_PRINT(b) do {} while(0) +#define GCALC_DBUG_ENTER(a) do {} while(0) +#define GCALC_DBUG_RETURN(r) return (r) +#define GCALC_DBUG_ASSERT(r) do {} while(0) +#endif /*GCALC_DBUG_OFF*/ /* Gcalc_dyn_list class designed to manage long lists of same-size objects From 0048f0b1aefa1206c6d8f35707ded2f87bc8aec1 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 5 Oct 2011 14:45:39 +0500 Subject: [PATCH 34/40] Valgrind warning fixed. Coordinate size limitation removed. per-file comments: mysql-test/r/gis-precise.result test result updated. sql/gcalc_slicescan.cc Check coordinate extent to pick better precidion in the ::set_double() sql/gcalc_slicescan.h free_list() can lead to valgrind warnig. Fixed sql/gcalc_tools.cc free_list() call changed. --- mysql-test/r/gis-precise.result | 6 +- sql/gcalc_slicescan.cc | 120 ++++++++++++++++++++++---------- sql/gcalc_slicescan.h | 37 +++++----- sql/gcalc_tools.cc | 2 +- 4 files changed, 105 insertions(+), 60 deletions(-) diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index 9086dec78a0..8c9495b1a8d 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -255,7 +255,7 @@ ST_NUMGEOMETRIES((ST_UNION(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((2 0,4 2,0 2,1 5,0 3,7 0,8 5,5 8), (6 2,4 0,3 5,3 6,4 3,6 4,3 9,0 7,3 7,8 4,2 9,5 0), -185 +192 SELECT Round(ST_AREA(ST_BUFFER( ST_UNION( POLYGONFROMTEXT('POLYGON((7 7, 7 7, 7 4, 7 7, 7 7))'), POLYGONFROMTEXT('POLYGON((7 7, 4 7, 2 9, 7 6, 7 7))')), 1)), 6); @@ -336,7 +336,7 @@ MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 3 1, 2 7, 4 2, 6 2, 1 5))') ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER(ST_UNION( MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 2 5, 7 6, 1 8),(0 0 ,1 6 ,0 1, 8 9, 2 4, 6 1, 3 5, 4 8), (9 3, 5 4, 1 8, 4 2, 5 8, 3 0))' ) , MULTILINESTRINGFROMTEXT('MULTILINESTRING((3 4, 3 1, 2 7, 4 2, 6 2 -275 +278 SELECT ST_NUMGEOMETRIES(ST_DIFFERENCE ( ST_UNION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 4 , 5 0 , 2 9 , 6 2 , 0 2 ) , ( 4 3 , 5 6 , 9 4 , 0 7 , 7 2 , 2 0 , 8 2 ) , ( 5 0 , 1 5 , 3 7 , 7 7 ) , ( 2 3 , 9 5 , 2 0 , 8 1 ) , ( 0 9 , 9 3 , 2 8 , 8 1 , 9 4 ) ) ' ), @@ -352,7 +352,7 @@ MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 9 , 1 3 , 7 3 , 8 5 ) , ( 5 0 , ST_NUMGEOMETRIES(ST_DIFFERENCE ( ST_UNION ( MULTILINESTRINGFROMTEXT( ' MULTILINESTRING( ( 2 4 , 5 0 , 2 9 , 6 2 , 0 2 ) , ( 4 3 , 5 6 , 9 4 , 0 7 , 7 2 , 2 0 , 8 2 ) , ( 5 0 , 1 5 , 3 7 , 7 7 ) , ( 2 3 , 9 5 , 2 0 , 8 1 ) , ( 0 9 , 9 3 , 2 8 , 8 1 , 9 4 ) -123 +125 SELECT ASTEXT(ST_DIFFERENCE ( POLYGONFROMTEXT( ' POLYGON( ( 2 2 , 2 8 , 8 8 , 8 2 , 2 2 ) , ( 4 4 , 4 6 , 6 6 , 6 4 , 4 4 ) ) ' ) , ST_UNION ( diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index fb1aab029a8..64e54fe0a36 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -235,21 +235,23 @@ int Gcalc_internal_coord::is_zero() const #ifdef GCALC_CHECK_WITH_FLOAT +double *Gcalc_internal_coord::coord_extent= NULL; + long double Gcalc_internal_coord::get_double() const { - int n= 0; - long double res= 0.0; + int n= 1; + long double res= (long double) digits[0]; do { - res*= (long double) DIG_BASE; - res+= digits[n]; + res*= (long double) GCALC_DIG_BASE; + res+= (long double) digits[n]; } while(++n < n_digits); n= 0; do { - if (n & 1) - res/= (long double) C_SCALE; + if ((n & 1) && coord_extent) + res/= *coord_extent; } while(++n < n_digits); if (sign) @@ -266,20 +268,21 @@ static void do_add(Gcalc_internal_coord *result, GCALC_DBUG_ASSERT(a->n_digits == b->n_digits); GCALC_DBUG_ASSERT(a->n_digits == result->n_digits); int n_digit= a->n_digits-1; - coord_digit_t carry= 0; + gcalc_digit_t carry= 0; do { if ((result->digits[n_digit]= - a->digits[n_digit] + b->digits[n_digit] + carry) >= DIG_BASE) + a->digits[n_digit] + b->digits[n_digit] + carry) >= GCALC_DIG_BASE) { carry= 1; - result->digits[n_digit]-= DIG_BASE; + result->digits[n_digit]-= GCALC_DIG_BASE; } else carry= 0; - } while (n_digit--); - GCALC_DBUG_ASSERT(carry == 0); + } while (--n_digit); + result->digits[0]= a->digits[0] + b->digits[0] + carry; + GCALC_DBUG_ASSERT(result->digits[0] < GCALC_DIG_BASE); result->sign= a->sign; } @@ -291,7 +294,7 @@ static void do_sub(Gcalc_internal_coord *result, GCALC_DBUG_ASSERT(a->n_digits == b->n_digits); GCALC_DBUG_ASSERT(a->n_digits == result->n_digits); int n_digit= a->n_digits-1; - coord_digit_t carry= 0; + gcalc_digit_t carry= 0; do { @@ -299,7 +302,7 @@ static void do_sub(Gcalc_internal_coord *result, a->digits[n_digit] - b->digits[n_digit] - carry) < 0) { carry= 1; - result->digits[n_digit]+= DIG_BASE; + result->digits[n_digit]+= GCALC_DIG_BASE; } else carry= 0; @@ -320,7 +323,7 @@ static int do_cmp(const Gcalc_internal_coord *a, do { - coord_digit_t d= a->digits[n_digit] - b->digits[n_digit]; + gcalc_digit_t d= a->digits[n_digit] - b->digits[n_digit]; if (d > 0) return 1; if (d < 0) @@ -353,7 +356,7 @@ void gcalc_mul_coord(Gcalc_internal_coord *result, { GCALC_DBUG_ASSERT(result->n_digits == a->n_digits + b->n_digits); int n_a, n_b, n_res; - coord_digit_t carry= 0; + gcalc_digit_t carry= 0; result->set_zero(); if (a->is_zero() || b->is_zero()) @@ -365,16 +368,17 @@ void gcalc_mul_coord(Gcalc_internal_coord *result, n_b= b->n_digits - 1; do { - coord2 mul= ((coord2) a->digits[n_a]) * b->digits[n_b] + carry + - result->digits[n_a + n_b + 1]; - result->digits[n_a + n_b + 1]= mul % DIG_BASE; - carry= mul / DIG_BASE; + gcalc_coord2 mul= ((gcalc_coord2) a->digits[n_a]) * b->digits[n_b] + + carry + result->digits[n_a + n_b + 1]; + result->digits[n_a + n_b + 1]= mul % GCALC_DIG_BASE; + carry= mul / GCALC_DIG_BASE; } while (n_b--); if (carry) { - for (n_res= n_a; (result->digits[n_res]+= carry) >= DIG_BASE; n_res--) + for (n_res= n_a; (result->digits[n_res]+= carry) >= GCALC_DIG_BASE; + n_res--) { - result->digits[n_res]-= DIG_BASE; + result->digits[n_res]-= GCALC_DIG_BASE; carry= 1; } carry= 0; @@ -458,14 +462,20 @@ int gcalc_cmp_coord(const Gcalc_internal_coord *a, } -int Gcalc_coord1::set_double(double d) +int Gcalc_coord1::set_double(double d, double ext) { - double ds= d * C_SCALE; + double ds= d * ext; init(); if ((sign= ds < 0)) ds= -ds; - c[0]= (coord_digit_t) (ds / (double) DIG_BASE); - c[1]= (coord_digit_t) (ds - ((double) c[0]) * DIG_BASE); + c[0]= (gcalc_digit_t) (ds / (double) GCALC_DIG_BASE); + c[1]= (gcalc_digit_t) nearbyint(ds - + ((double) c[0]) * (double) GCALC_DIG_BASE); + if (c[1] >= GCALC_DIG_BASE) + { + c[1]= 0; + c[0]++; + } #ifdef GCALC_CHECK_WITH_FLOAT GCALC_DBUG_ASSERT(de_check(d, get_double())); #endif /*GCALC_CHECK_WITH_FLOAT*/ @@ -486,17 +496,28 @@ void Gcalc_coord1::copy(const Gcalc_coord1 *from) 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; *m_hook= result; m_hook= &result->next; - m_n_points++; result->x= x; result->y= y; result->shape= shape; - result->ix.set_double(x); - result->iy.set_double(y); + 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; + + m_n_points++; return result; } @@ -520,11 +541,11 @@ Gcalc_heap::Intersection_info *Gcalc_heap::new_intersection( class Gcalc_coord3 : public Gcalc_internal_coord { - coord_digit_t c[COORD_BASE*3]; + gcalc_digit_t c[GCALC_COORD_BASE*3]; public: void init() { - n_digits= COORD_BASE*3; + n_digits= GCALC_COORD_BASE*3; digits= c; } }; @@ -670,15 +691,36 @@ 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_internal_coord::coord_extent= &coord_extent; +#endif /*GCALC_CHECK_WITH_FLOAT*/ + for (cur= get_first(); cur; cur= cur->get_next()) + { + cur->ix.set_double(cur->x, coord_extent); + cur->iy.set_double(cur->y, coord_extent); + } *m_hook= NULL; m_first= sort_list(compare_point_info, m_first, m_n_points); m_hook= NULL; /* just to check it's not called twice */ /* TODO - move this to the 'normal_scan' loop */ - for (Info *cur= get_first(); cur; cur= cur->get_next()) + for (cur= get_first(); cur; cur= cur->get_next()) { trim_node(cur->left, cur); trim_node(cur->right, cur); @@ -702,7 +744,8 @@ void Gcalc_heap::reset() if (m_n_points) { free_list(m_first); - free_list(m_first_intersection, m_intersection_hook); + free_list((Gcalc_dyn_list::Item **) &m_first_intersection, + m_intersection_hook); m_intersection_hook= (Gcalc_dyn_list::Item **) &m_first_intersection; m_n_points= 0; } @@ -913,12 +956,13 @@ int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const void Gcalc_scan_iterator::point::calc_x(long double *x, long double y, long double ix) const { - if (fabsl(dy.get_double()) < (long double) 1e-15) + long double ddy= dy.get_double(); + if (fabsl(ddy) < (long double) 1e-20) { *x= ix; } else - *x= (long double) pi->x + dx.get_double()/dy.get_double() * (y - pi->y); + *x= (ddy * (long double) pi->x + dx.get_double() * (y - pi->y)) / ddy; } #endif /*GCALC_CHECK_WITH_FLOAT*/ @@ -1509,22 +1553,22 @@ int Gcalc_scan_iterator::find_intersections() class Gcalc_coord4 : public Gcalc_internal_coord { - coord_digit_t c[COORD_BASE*4]; + gcalc_digit_t c[GCALC_COORD_BASE*4]; public: void init() { - n_digits= COORD_BASE*4; + n_digits= GCALC_COORD_BASE*4; digits= c; } }; class Gcalc_coord5 : public Gcalc_internal_coord { - coord_digit_t c[COORD_BASE*5]; + gcalc_digit_t c[GCALC_COORD_BASE*5]; public: void init() { - n_digits= COORD_BASE*5; + n_digits= GCALC_COORD_BASE*5; digits= c; } }; diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index bf37afd3d66..c052dcd118a 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -74,13 +74,10 @@ public: item->next= m_free; m_free= item; } - inline void free_list(Item *list, Item **hook) + inline void free_list(Item **list, Item **hook) { - if (*hook != list) - { - *hook= m_free; - m_free= list; - } + *hook= m_free; + m_free= *list; } void free_list(Item *list) @@ -88,7 +85,7 @@ public: Item **hook= &list; while (*hook) hook= &(*hook)->next; - free_list(list, hook); + free_list(&list, hook); } void reset(); @@ -113,22 +110,22 @@ protected: /* Internal Gcalc coordinates to provide the precise calculations */ -#define DIG_BASE 1000000000 -typedef int32 coord_digit_t; -typedef long long coord2; +#define GCALC_DIG_BASE 1000000000 +typedef int32 gcalc_digit_t; +typedef long long gcalc_coord2; -#define C_SCALE 1e13 -#define COORD_BASE 2 +#define GCALC_COORD_BASE 2 class Gcalc_internal_coord { public: - coord_digit_t *digits; + gcalc_digit_t *digits; int sign; int n_digits; void set_zero(); int is_zero() const; #ifdef GCALC_CHECK_WITH_FLOAT + static double *coord_extent; long double get_double() const; #endif /*GCALC_CHECK_WITH_FLOAT*/ }; @@ -136,25 +133,25 @@ public: class Gcalc_coord1 : public Gcalc_internal_coord { - coord_digit_t c[COORD_BASE]; + gcalc_digit_t c[GCALC_COORD_BASE]; public: void init() { - n_digits= COORD_BASE; + n_digits= GCALC_COORD_BASE; digits= c; } - int set_double(double d); + int set_double(double d, double ext); void copy(const Gcalc_coord1 *from); }; class Gcalc_coord2 : public Gcalc_internal_coord { - coord_digit_t c[COORD_BASE*2]; + gcalc_digit_t c[GCALC_COORD_BASE*2]; public: void init() { - n_digits= COORD_BASE*2; + n_digits= GCALC_COORD_BASE*2; digits= c; } }; @@ -235,12 +232,16 @@ public: const Info *get_first() const { return (const Info *)m_first; } Gcalc_dyn_list::Item **get_last_hook() { return m_hook; } void reset(); +#ifdef GCALC_CHECK_WITH_FLOAT + long double get_double(const Gcalc_internal_coord *c) const; +#endif /*GCALC_CHECK_WITH_FLOAT*/ private: Gcalc_dyn_list::Item *m_first; Gcalc_dyn_list::Item **m_hook; int m_n_points; Intersection_info *m_first_intersection; Gcalc_dyn_list::Item **m_intersection_hook; + double coord_extent; }; diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 5871dce8642..56a3c5ee5f2 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -1409,7 +1409,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) void Gcalc_operation_reducer::reset() { - free_list(m_result, m_res_hook); + free_list((Gcalc_heap::Item **) &m_result, m_res_hook); m_res_hook= (Gcalc_dyn_list::Item **)&m_result; free_list(m_first_active_thread); } From bf2deb5ed30b03e9cada6162d8aa837115dce4cc Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 6 Oct 2011 17:41:28 +0500 Subject: [PATCH 35/40] Copyright notices fixed. --- sql/gcalc_slicescan.cc | 1 + sql/gcalc_slicescan.h | 1 + sql/gcalc_tools.cc | 1 + sql/gcalc_tools.h | 1 + sql/item_geofunc.cc | 3 ++- sql/item_geofunc.h | 3 ++- 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 64e54fe0a36..10c64aa5d08 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -1,4 +1,5 @@ /* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. + Copyright (C) 2011 Monty Program Ab. 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 diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index c052dcd118a..22b7cc44027 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -1,4 +1,5 @@ /* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. + Copyright (C) 2011 Monty Program Ab. 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 diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 56a3c5ee5f2..eabc42a6c51 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -1,4 +1,5 @@ /* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. + Copyright (C) 2011 Monty Program Ab. 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 diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index d1087aa83b2..ca740dcdc11 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -1,4 +1,5 @@ /* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. + Copyright (C) 2011 Monty Program Ab. 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 diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 4db8ee02d7f..dd6914e5d66 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. + Copyright (C) 2011 Monty Program Ab. 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 diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index b4e495f39a8..f637167d6d2 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -1,7 +1,8 @@ #ifndef ITEM_GEOFUNC_INCLUDED #define ITEM_GEOFUNC_INCLUDED -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. + Copyright (C) 2011 Monty Program Ab. 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 From 8432284d4fe276db8fe99f434b98e3631e707146 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 14 Oct 2011 16:10:55 +0500 Subject: [PATCH 36/40] GIS code. Forward calculations introduced. per-file comments: sql/gcalc_slicescan.cc sql/gcalc_slicescan.h sql/gcalc_tools.cc sql/gcalc_tools.h sql/item_geofunc.cc --- sql/gcalc_slicescan.cc | 1906 ++++++++++++++++++++-------------------- sql/gcalc_slicescan.h | 251 +++--- sql/gcalc_tools.cc | 48 +- sql/gcalc_tools.h | 3 +- sql/item_geofunc.cc | 4 +- 5 files changed, 1104 insertions(+), 1108 deletions(-) diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 10c64aa5d08..6e32baab8de 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -40,6 +40,20 @@ typedef int (*sc_compare_func)(const void*, const void*); #include "plistsort.c" +static Gcalc_scan_iterator::point *eq_sp(const Gcalc_heap::Info *pi) +{ + GCALC_DBUG_ASSERT(pi->type == Gcalc_heap::nt_eq_node); + return (Gcalc_scan_iterator::point *) pi->eq_data; +} + + +static Gcalc_scan_iterator::intersection_info *i_data(const Gcalc_heap::Info *pi) +{ + GCALC_DBUG_ASSERT(pi->type == Gcalc_heap::nt_intersection); + return (Gcalc_scan_iterator::intersection_info *) pi->intersection_data; +} + + #ifndef GCALC_DBUG_OFF int gcalc_step_counter= 0; @@ -80,53 +94,101 @@ const char *gcalc_ev_name(int ev) } +static int gcalc_pi_str(char *str, const Gcalc_heap::Info *pi, const char *postfix) +{ + return sprintf(str, "%s %d %d | %s %d %d%s", + pi->ix.sign ? "-":"", pi->ix.digits[0],pi->ix.digits[1], + pi->iy.sign ? "-":"", pi->iy.digits[0],pi->iy.digits[1], + postfix); + +} + + +static void GCALC_DBUG_PRINT_PI(const Gcalc_heap::Info *pi) +{ + char buf[128]; + int n_buf; + if (pi->type == Gcalc_heap::nt_intersection) + { + const Gcalc_scan_iterator::intersection_info *ic= i_data(pi); + + GCALC_DBUG_PRINT(("intersection point %d %d", + ic->edge_a->thread, ic->edge_b->thread)); + return; + } + if (pi->type == Gcalc_heap::nt_eq_node) + { + const Gcalc_scan_iterator::point *e= eq_sp(pi); + GCALC_DBUG_PRINT(("eq point %d", e->thread)); + return; + } + n_buf= gcalc_pi_str(buf, pi, ""); + buf[n_buf]= 0; + GCALC_DBUG_PRINT(("%s", buf)); +} + + +#ifdef TMP_BLOCK static void GCALC_DBUG_PRINT_SLICE(const char *header, const Gcalc_scan_iterator::point *slice) { int nbuf1, nbuf2; + int nbuf3, nbuf4; char buf1[1024], buf2[1024]; - nbuf1= nbuf2= strlen(header); + char buf3[1024], buf4[1024]; + nbuf1= nbuf2= nbuf3= nbuf4= strlen(header); strcpy(buf1, header); strcpy(buf2, header); + strcpy(buf3, header); + strcpy(buf4, header); for (; slice; slice= slice->get_next()) { nbuf1+= sprintf(buf1+nbuf1, "%d\t", slice->thread); nbuf2+= sprintf(buf2+nbuf2, "%s\t", gcalc_ev_name(slice->event)); + + nbuf3+= gcalc_pi_str(buf3+nbuf3, slice->pi, "\t"); + if (slice->is_bottom()) + nbuf4+= sprintf(buf4+nbuf4, "bt\t"); + else + nbuf4+= gcalc_pi_str(buf4+nbuf4, slice->next_pi, "\t"); } buf1[nbuf1]= 0; buf2[nbuf2]= 0; + buf3[nbuf3]= 0; + buf4[nbuf4]= 0; GCALC_DBUG_PRINT((buf1)); GCALC_DBUG_PRINT((buf2)); + GCALC_DBUG_PRINT((buf3)); + GCALC_DBUG_PRINT((buf4)); } - - -static void GCALC_DBUG_PRINT_INTERSECTIONS( - Gcalc_scan_iterator::intersection *isc) +#endif /*TMP_BLOCK*/ +static void GCALC_DBUG_PRINT_SLICE(const char *header, + const Gcalc_scan_iterator::point *slice) { - for (; isc; isc= isc->get_next()) + int nbuf; + char buf[1024]; + nbuf= strlen(header); + strcpy(buf, header); + for (; slice; slice= slice->get_next()) { - long double ix, iy; - isc->ii->calc_xy_ld(&ix, &iy); - GCALC_DBUG_PRINT(("%d %d %d %.8LG %.8LG", isc->thread_a, isc->thread_b, - isc->n_row, ix, iy)); + int lnbuf= nbuf; + lnbuf+= sprintf(buf + lnbuf, "%d\t", slice->thread); + lnbuf+= sprintf(buf + lnbuf, "%s\t", gcalc_ev_name(slice->event)); + + lnbuf+= gcalc_pi_str(buf + lnbuf, slice->pi, "\t"); + if (slice->is_bottom()) + lnbuf+= sprintf(buf+lnbuf, "bt\t"); + else + lnbuf+= gcalc_pi_str(buf+lnbuf, slice->next_pi, "\t"); + buf[lnbuf]= 0; + GCALC_DBUG_PRINT((buf)); } } -static void GCALC_DBUG_PRINT_STATE(Gcalc_scan_iterator::slice_state *s) -{ - if (s->event_position) - GCALC_DBUG_PRINT(("%d %d %d", s->event_position->thread, - ((Gcalc_scan_iterator::point *) *s->event_position_hook)->thread, - *s->event_end_hook ? - ((Gcalc_scan_iterator::point *) *s->event_end_hook)->thread : -1)); - else - GCALC_DBUG_PRINT(("position null")); -} - - #else #define GCALC_DBUG_CHECK_COUNTER(a) do { } while(0) +#define GCALC_DBUG_PRINT_PI(pi) do { } while(0) #define GCALC_DBUG_PRINT_SLICE(a, b) do { } while(0) #define GCALC_DBUG_PRINT_INTERSECTIONS(a) do { } while(0) #define GCALC_DBUG_PRINT_STATE(a) do { } while(0) @@ -463,6 +525,9 @@ int gcalc_cmp_coord(const Gcalc_internal_coord *a, } +#define gcalc_cmp_coord1(a, b) gcalc_cmp_coord(a, b) + + int Gcalc_coord1::set_double(double d, double ext) { double ds= d * ext; @@ -491,66 +556,6 @@ void Gcalc_coord1::copy(const Gcalc_coord1 *from) sign= from->sign; } -/* Internal coordinates implementation end */ - - -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; - *m_hook= result; - m_hook= &result->next; - result->x= x; - result->y= y; - result->shape= shape; - 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; - - m_n_points++; - return result; -} - - -Gcalc_heap::Intersection_info *Gcalc_heap::new_intersection( - const Info *p1, const Info *p2, - const Info *p3, const Info *p4) -{ - Intersection_info *isc= (Intersection_info *)new_item(); - if (!isc) - return 0; - isc->p1= p1; - isc->p2= p2; - isc->p3= p3; - isc->p4= p4; - *m_intersection_hook= isc; - m_intersection_hook= &isc->next; - return isc; -} - - -class Gcalc_coord3 : public Gcalc_internal_coord -{ - gcalc_digit_t c[GCALC_COORD_BASE*3]; - public: - void init() - { - n_digits= GCALC_COORD_BASE*3; - digits= c; - } -}; - static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, Gcalc_coord1 *b1x, @@ -582,6 +587,8 @@ static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, gcalc_sub_coord(&b2x, &p4->ix, &p3->ix); gcalc_sub_coord(&b2y, &p4->iy, &p3->iy); + GCALC_DBUG_ASSERT(!b1y->is_zero() || !b2y.is_zero()); + gcalc_mul_coord(&x1y2, b1x, &b2y); gcalc_mul_coord(&x2y1, &b2x, b1y); gcalc_sub_coord(t_b, &x1y2, &x2y1); @@ -593,16 +600,224 @@ static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, } -inline void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, +static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, Gcalc_coord1 *b1x, Gcalc_coord1 *b1y, - const Gcalc_heap::Intersection_info *isc) + const Gcalc_heap::Info *i) { - calc_t(t_a, t_b, b1x, b1y, isc->p1, isc->p2, isc->p3, isc->p4); + GCALC_DBUG_ASSERT(i->type == Gcalc_heap::nt_intersection); + calc_t(t_a, t_b, b1x, b1y, i->p1, i->p2, i->p3, i->p4); } -void Gcalc_heap::Intersection_info::calc_xy(double *x, double *y) const +class Gcalc_coord4 : public Gcalc_internal_coord +{ + gcalc_digit_t c[GCALC_COORD_BASE*4]; + public: + void init() + { + n_digits= GCALC_COORD_BASE*4; + digits= c; + } +}; + + +class Gcalc_coord5 : public Gcalc_internal_coord +{ + gcalc_digit_t c[GCALC_COORD_BASE*5]; + public: + void init() + { + n_digits= GCALC_COORD_BASE*5; + digits= c; + } +}; + + +static void calc_isc_exp(Gcalc_coord5 *exp, + const Gcalc_coord2 *bb2, + const Gcalc_coord1 *ya1, + const Gcalc_coord2 *bb1, + const Gcalc_coord1 *yb1, + const Gcalc_coord2 *a21_b1) +{ + Gcalc_coord3 p1, p2, sum; + p1.init(); + p2.init(); + sum.init(); + exp->init(); + + gcalc_mul_coord(&p1, ya1, bb1); + gcalc_mul_coord(&p2, yb1, a21_b1); + gcalc_add_coord(&sum, &p1, &p2); + gcalc_mul_coord(exp, bb2, &sum); +} + + +static int cmp_intersections(const Gcalc_heap::Info *i1, + const Gcalc_heap::Info *i2) +{ + Gcalc_coord2 t_a1, t_b1; + Gcalc_coord2 t_a2, t_b2; + Gcalc_coord1 yb1, yb2; + Gcalc_coord1 xb1, xb2; + Gcalc_coord5 exp_a, exp_b; + int result; + + calc_t(&t_a1, &t_b1, &xb1, &yb1, i1); + calc_t(&t_a2, &t_b2, &xb2, &yb2, i2); + + calc_isc_exp(&exp_a, &t_b2, &i1->p1->iy, &t_b1, &yb1, &t_a1); + calc_isc_exp(&exp_b, &t_b1, &i2->p1->iy, &t_b2, &yb2, &t_a2); + + result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + long double x1, y1, x2, y2; + i1->calc_xy_ld(&x1, &y1); + i2->calc_xy_ld(&x2, &y2); + + if (result == 0) + GCALC_DBUG_ASSERT(de_check(y1, y2)); + if (result < 0) + GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 < y2); + if (result > 0) + GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 > y2); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + + if (result != 0) + return result; + + + calc_isc_exp(&exp_a, &t_b2, &i1->p1->ix, &t_b1, &xb1, &t_a1); + calc_isc_exp(&exp_b, &t_b1, &i2->p1->ix, &t_b2, &xb2, &t_a2); + result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + if (result == 0) + GCALC_DBUG_ASSERT(de_check(x1, x2)); + if (result < 0) + GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 < x2); + if (result > 0) + GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 > x2); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result; +} + + +static int cmp_node_isc(const Gcalc_heap::Info *node, + const Gcalc_heap::Info *isc) +{ + GCALC_DBUG_ASSERT(node->type == Gcalc_heap::nt_shape_node); + Gcalc_coord3 exp_a, exp_b; + Gcalc_coord1 xb1, yb1, d0; + Gcalc_coord2 t_a, t_b; + int result; + exp_a.init(); + exp_b.init(); + d0.init(); + + calc_t(&t_a, &t_b, &xb1, &yb1, isc); + + gcalc_sub_coord(&d0, &node->iy, &isc->p1->iy); + gcalc_mul_coord(&exp_a, &d0, &t_b); + gcalc_mul_coord(&exp_b, &yb1, &t_a); + + result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + long double int_x, int_y; + isc->calc_xy_ld(&int_x, &int_y); + if (result < 0) + GCALC_DBUG_ASSERT(de_check(int_y, node->y) || node->y < int_y); + else if (result > 0) + GCALC_DBUG_ASSERT(de_check(int_y, node->y) || node->y > int_y); + else + GCALC_DBUG_ASSERT(de_check(int_y, node->y)); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + if (result) + goto exit; + + gcalc_sub_coord(&d0, &node->ix, &isc->p1->ix); + gcalc_mul_coord(&exp_a, &d0, &t_b); + gcalc_mul_coord(&exp_b, &xb1, &t_a); + + result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + if (result < 0) + GCALC_DBUG_ASSERT(de_check(int_x, node->x) || node->x < int_x); + else if (result > 0) + GCALC_DBUG_ASSERT(de_check(int_x, node->x) || node->x > int_x); + else + GCALC_DBUG_ASSERT(de_check(int_x, node->x)); +#endif /*GCALC_CHECK_WITH_FLOAT*/ +exit: + return result; +} + + +/* Internal coordinates implementation end */ + + +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; + *m_hook= result; + m_hook= &result->next; + result->x= x; + result->y= 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; + + m_n_points++; + return result; +} + + +static Gcalc_heap::Info *new_intersection( + Gcalc_heap *heap, Gcalc_scan_iterator::intersection_info *ii) +{ + Gcalc_heap::Info *isc= (Gcalc_heap::Info *)heap->new_item(); + if (!isc) + return 0; + isc->type= Gcalc_heap::nt_intersection; + isc->p1= ii->edge_a->pi; + isc->p2= ii->edge_a->next_pi; + isc->p3= ii->edge_b->pi; + isc->p4= ii->edge_b->next_pi; + isc->intersection_data= ii; + return isc; +} + + +static Gcalc_heap::Info *new_eq_point( + Gcalc_heap *heap, const Gcalc_heap::Info *p, + Gcalc_scan_iterator::point *edge) +{ + Gcalc_heap::Info *eqp= (Gcalc_heap::Info *)heap->new_item(); + if (!eqp) + return 0; + eqp->type= Gcalc_heap::nt_eq_node; + eqp->node= p; + eqp->eq_data= edge; + return eqp; +} + + +void Gcalc_heap::Info::calc_xy(double *x, double *y) const { double b0_x= p2->x - p1->x; double b0_y= p2->y - p1->y; @@ -619,8 +834,7 @@ void Gcalc_heap::Intersection_info::calc_xy(double *x, double *y) const #ifdef GCALC_CHECK_WITH_FLOAT -void Gcalc_heap::Intersection_info::calc_xy_ld(long double *x, - long double *y) const +void Gcalc_heap::Info::calc_xy_ld(long double *x, long double *y) const { long double b0_x= p2->x - p1->x; long double b0_y= p2->y - p1->y; @@ -663,17 +877,6 @@ void Gcalc_heap::Intersection_info::calc_xy_ld(long double *x, #endif /*GCALC_CHECK_WITH_FLOAT*/ -static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node) -{ - if (!node) - return; - GCALC_DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node)); - if (node->left == prev_node) - node->left= node->right; - node->right= NULL; -} - - static int cmp_point_info(const Gcalc_heap::Info *i0, const Gcalc_heap::Info *i1) { @@ -684,6 +887,19 @@ static int cmp_point_info(const Gcalc_heap::Info *i0, } +static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node) +{ + if (!node) + return; + node->top_node= 0; + GCALC_DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node)); + if (node->left == prev_node) + node->left= node->right; + node->right= NULL; + GCALC_DBUG_ASSERT(cmp_point_info(node, prev_node)); +} + + static int compare_point_info(const void *e0, const void *e1) { const Gcalc_heap::Info *i0= (const Gcalc_heap::Info *)e0; @@ -711,14 +927,14 @@ void Gcalc_heap::prepare_operation() #ifdef GCALC_CHECK_WITH_FLOAT Gcalc_internal_coord::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()) { cur->ix.set_double(cur->x, coord_extent); cur->iy.set_double(cur->y, coord_extent); } - *m_hook= NULL; m_first= sort_list(compare_point_info, m_first, m_n_points); - m_hook= NULL; /* just to check it's not called twice */ /* TODO - move this to the 'normal_scan' loop */ for (cur= get_first(); cur; cur= cur->get_next()) @@ -745,9 +961,6 @@ void Gcalc_heap::reset() if (m_n_points) { free_list(m_first); - free_list((Gcalc_dyn_list::Item **) &m_first_intersection, - m_intersection_hook); - m_intersection_hook= (Gcalc_dyn_list::Item **) &m_first_intersection; m_n_points= 0; } m_hook= &m_first; @@ -829,86 +1042,44 @@ inline void calc_dx_dy(Gcalc_scan_iterator::point *p) p->r_border= &p->next_pi->ix; p->l_border= &p->pi->ix; } - p->always_on_left= 0; } Gcalc_scan_iterator::Gcalc_scan_iterator(size_t blk_size) : - Gcalc_dyn_list(blk_size, - (sizeof(point) > sizeof(intersection)) ? - sizeof(point) : sizeof(intersection)) -{} - -Gcalc_scan_iterator::point - *Gcalc_scan_iterator::new_slice(Gcalc_scan_iterator::point *example) + Gcalc_dyn_list(blk_size, sizeof(point) > sizeof(intersection_info) ? + sizeof(point) : + sizeof(intersection_info)) { - point *result= NULL; - Gcalc_dyn_list::Item **result_hook= (Gcalc_dyn_list::Item **) &result; - while (example) - { - *result_hook= new_slice_point(); - result_hook= &(*result_hook)->next; - example= example->get_next(); - } - *result_hook= NULL; - return result; + state.slice= NULL; + m_bottom_points= NULL; + m_bottom_hook= &m_bottom_points; } - + void Gcalc_scan_iterator::init(Gcalc_heap *points) { GCALC_DBUG_ASSERT(points->ready()); - GCALC_DBUG_ASSERT(!state0.slice && !state1.slice); + GCALC_DBUG_ASSERT(!state.slice); if (!(m_cur_pi= points->get_first())) return; m_heap= points; + state.event_position_hook= &state.slice; + state.event_end= NULL; +#ifndef GCALC_DBUG_OFF m_cur_thread= 0; - m_intersections= NULL; - m_cur_intersection= NULL; - m_next_is_top_point= true; - m_events= NULL; - current_state= &state0; - next_state= &state1; - saved_state= &state_s; - next_state->intersection_scan= 0; - next_state->pi= m_cur_pi; +#endif /*GCALC_DBUG_OFF*/ } void Gcalc_scan_iterator::reset() { - state0.slice= state1.slice= m_events= state_s.slice= NULL; - m_intersections= NULL; + state.slice= NULL; + m_bottom_points= NULL; + m_bottom_hook= &m_bottom_points; Gcalc_dyn_list::reset(); } -void Gcalc_scan_iterator::point::copy_core(const point *from) -{ - pi= from->pi; - next_pi= from->next_pi; - thread= from->thread; - dx.copy(&from->dx); - dy.copy(&from->dy); - l_border= from->l_border; - r_border= from->r_border; -} - - -void Gcalc_scan_iterator::point::copy_all(const point *from) -{ - pi= from->pi; - next_pi= from->next_pi; - thread= from->thread; - dx.copy(&from->dx); - dy.copy(&from->dy); - intersection_link= from->intersection_link; - event= from->event; - l_border= from->l_border; - r_border= from->r_border; -} - - int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_coord1 *dx_a, const Gcalc_coord1 *dy_a, const Gcalc_coord1 *dx_b, @@ -945,10 +1116,7 @@ int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_heap::Info *p1, int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const { - if (is_bottom()) - return p->is_bottom() ? 0 : -1; - if (p->is_bottom()) - return 1; + GCALC_DBUG_ASSERT(!is_bottom()); return cmp_dx_dy(&dx, &dy, &p->dx, &p->dy); } @@ -968,123 +1136,6 @@ void Gcalc_scan_iterator::point::calc_x(long double *x, long double y, #endif /*GCALC_CHECK_WITH_FLOAT*/ -static int cmp_sp_pi(const Gcalc_scan_iterator::point *sp, - const Gcalc_heap::Info *pi) -{ - Gcalc_coord1 dx_pi, dy_pi; - Gcalc_coord2 dx_sp_dy_pi, dy_sp_dx_pi; - - if (!sp->next_pi) - return cmp_point_info(sp->pi, pi); - - dx_pi.init(); - dy_pi.init(); - dx_sp_dy_pi.init(); - dy_sp_dx_pi.init(); - - - gcalc_sub_coord(&dx_pi, &pi->ix, &sp->pi->ix); - gcalc_sub_coord(&dy_pi, &pi->iy, &sp->pi->iy); - gcalc_mul_coord(&dx_sp_dy_pi, &sp->dx, &dy_pi); - gcalc_mul_coord(&dy_sp_dx_pi, &sp->dy, &dx_pi); - - int result= gcalc_cmp_coord(&dx_sp_dy_pi, &dy_sp_dx_pi); -#ifdef GCALC_CHECK_WITH_FLOAT - long double sp_x; - sp->calc_x(&sp_x, pi->y, pi->x); - if (result == 0) - GCALC_DBUG_ASSERT(de_check(sp->dy.get_double(), 0.0) || - de_check(sp_x, pi->x)); - if (result < 0) - GCALC_DBUG_ASSERT(de_check(sp->dy.get_double(), 0.0) || - de_check(sp_x, pi->x) || - sp_x < pi->x); - if (result > 0) - GCALC_DBUG_ASSERT(de_check(sp->dy.get_double(), 0.0) || - de_check(sp_x, pi->x) || - sp_x > pi->x); -#endif /*GCALC_CHECK_WITH_FLOAT*/ - return result; -} - - -static void calc_cmp_sp_sp_exp(Gcalc_coord3 *result, - const Gcalc_scan_iterator::point *a, - const Gcalc_scan_iterator::point *b, - const Gcalc_coord1 *ly) -{ - Gcalc_coord2 x_dy, dx_ly, sum; - - x_dy.init(); - dx_ly.init(); - sum.init(); - result->init(); - - gcalc_mul_coord(&x_dy, &a->pi->ix, &a->dy); - gcalc_mul_coord(&dx_ly, &a->dx, ly); - gcalc_add_coord(&sum, &x_dy, &dx_ly); - gcalc_mul_coord(result, &sum, &b->dy); -} - - -static int cmp_sp_sp_cnt(const Gcalc_scan_iterator::point *a, - const Gcalc_scan_iterator::point *b, - const Gcalc_coord1 *y) -{ - Gcalc_coord1 lya, lyb; - Gcalc_coord3 a_exp, b_exp; - - lya.init(); - lyb.init(); - gcalc_sub_coord(&lya, y, &a->pi->iy); - gcalc_sub_coord(&lyb, y, &b->pi->iy); - - calc_cmp_sp_sp_exp(&a_exp, a, b, &lya); - calc_cmp_sp_sp_exp(&b_exp, b, a, &lyb); - - int result= gcalc_cmp_coord(&a_exp, &b_exp); -#ifdef GCALC_CHECK_WITH_FLOAT - long double a_x, b_x; - a->calc_x(&a_x, y->get_double(), 0); - b->calc_x(&b_x, y->get_double(), 0); - if (result == 0) - GCALC_DBUG_ASSERT(de_check(a_x, b_x)); - if (result < 0) - GCALC_DBUG_ASSERT(de_check(a_x, b_x) || a_x < b_x); - if (result > 0) - GCALC_DBUG_ASSERT(de_check(a_x, b_x) || a_x > b_x); -#endif /*GCALC_CHECK_WITH_FLOAT*/ - return result; -} - - -static int cmp_sp_sp(const Gcalc_scan_iterator::point *a, - const Gcalc_scan_iterator::point *b, - const Gcalc_heap::Info *pi) -{ - if (a->event == scev_none && b->event == scev_none) - return cmp_sp_sp_cnt(a, b, &pi->iy); - if (a->event == scev_none) - return cmp_sp_pi(a, pi); - if (b->event == scev_none) - return -1 * cmp_sp_pi(b, pi); - - return 0; -} - - -void Gcalc_scan_iterator::mark_event_position1( - point *ep, Gcalc_dyn_list::Item **ep_hook) -{ - if (!next_state->event_position) - { - next_state->event_position= ep; - next_state->event_position_hook= ep_hook; - } - next_state->event_end_hook= &ep->next; -} - - static int compare_events(const void *e0, const void *e1) { const Gcalc_scan_iterator::point *p0= (const Gcalc_scan_iterator::point *)e0; @@ -1093,90 +1144,251 @@ static int compare_events(const void *e0, const void *e1) } -int Gcalc_scan_iterator::arrange_event() +int Gcalc_scan_iterator::arrange_event(int do_sorting, int n_intersections) { int ev_counter; - point *sp, *new_sp; - point *after_event; - Gcalc_dyn_list::Item **ae_hook= (Gcalc_dyn_list::Item **) &after_event; + point *sp; + point **sp_hook; - if (m_events) - free_list(m_events); ev_counter= 0; - GCALC_DBUG_ASSERT(current_state->event_position == - *current_state->event_position_hook); - for (sp= current_state->event_position; - sp != *current_state->event_end_hook; sp= sp->get_next()) + + *m_bottom_hook= NULL; + for (sp= m_bottom_points; sp; sp= sp->get_next()) + sp->ev_next= sp->get_next(); + + for (sp= state.slice, sp_hook= &state.slice; + sp; sp_hook= sp->next_ptr(), sp= sp->get_next()) { - if (sp->is_bottom()) - continue; - if (!(new_sp= new_slice_point())) - return 1; - new_sp->copy_all(sp); - *ae_hook= new_sp; - ae_hook= &new_sp->next; - ev_counter++; - } - *ae_hook= NULL; - m_events= current_state->event_position; - if (after_event) - { - if (after_event->get_next()) + if (sp->event) { - point *cur_p; - after_event= (point *) sort_list(compare_events, after_event, ev_counter); - /* Find last item in the list, ae_hook can change after the sorting */ - for (cur_p= after_event->get_next(); cur_p->get_next(); - cur_p= cur_p->get_next()) - { - cur_p->always_on_left= 1; - } - ae_hook= &cur_p->next; - + state.event_position_hook= sp_hook; + break; } - *ae_hook= *current_state->event_end_hook; - *current_state->event_end_hook= NULL; - *current_state->event_position_hook= after_event; - current_state->event_end_hook= ae_hook; - current_state->event_position= after_event; - } - else - { - *current_state->event_position_hook= *current_state->event_end_hook; - *current_state->event_end_hook= NULL; - current_state->event_position= sp; - current_state->event_end_hook= current_state->event_position_hook; } + for (sp= *(sp_hook= state.event_position_hook); + sp && sp->event; sp_hook= sp->next_ptr(), sp= sp->get_next()) + { + ev_counter++; + if (sp->get_next() && sp->get_next()->event) + sp->ev_next= sp->get_next(); + else + sp->ev_next= m_bottom_points; + } + +#ifndef GCALC_DBUG_OFF + { + point *cur_p= sp; + for (; cur_p; cur_p= cur_p->get_next()) + GCALC_DBUG_ASSERT(!cur_p->event); + } +#endif /*GCALC_DBUG_OFF*/ + + state.event_end= sp; + + if (ev_counter == 2 && n_intersections == 1) + { + /* If we had only intersection, just swap the two points. */ + sp= *state.event_position_hook; + *state.event_position_hook= sp->get_next(); + sp->next= (*state.event_position_hook)->next; + (*state.event_position_hook)->next= sp; + + /* The list of the events should be restored. */ + (*state.event_position_hook)->ev_next= sp; + sp->ev_next= m_bottom_points; + } + else if (ev_counter == 2 && get_events()->event == scev_two_threads) + { + /* Do nothing. */ + } + else if (ev_counter > 1 && do_sorting) + { + point *cur_p; + *sp_hook= NULL; + sp= (point *) sort_list(compare_events, *state.event_position_hook, + ev_counter); + /* Find last item in the list, it's changed after the sorting. */ + for (cur_p= sp->get_next(); cur_p->get_next(); + cur_p= cur_p->get_next()) + {} + cur_p->next= state.event_end; + *state.event_position_hook= sp; + /* The list of the events should be restored. */ + for (; sp && sp->event; sp= sp->get_next()) + { + if (sp->get_next() && sp->get_next()->event) + sp->ev_next= sp->get_next(); + else + sp->ev_next= m_bottom_points; + } + } + +#ifndef GCALC_DBUG_OFF + { + const event_point *ev= get_events(); + for (; ev && ev->get_next(); ev= ev->get_next()) + { + if (ev->is_bottom() || ev->get_next()->is_bottom()) + break; + GCALC_DBUG_ASSERT(ev->cmp_dx_dy(ev->get_next()) <= 0); + } + } +#endif /*GCALC_DBUG_OFF*/ return 0; } -int Gcalc_scan_iterator::insert_top_point() +int Gcalc_heap::Info::equal_pi(const Info *pi) const { - point *sp= next_state->slice; - Gcalc_dyn_list::Item **prev_hook= - (Gcalc_dyn_list::Item **) &next_state->slice; + if (type == nt_intersection) + return equal_intersection; + if (pi->type == nt_eq_node) + return 1; + if (type == nt_eq_node || pi->type == nt_intersection) + return 0; + return cmp_point_info(this, pi) == 0; +} + +int Gcalc_scan_iterator::step() +{ + int result= 0; + int do_sorting= 0; + int n_intersections= 0; + point *sp; + GCALC_DBUG_ENTER("Gcalc_scan_iterator::step"); + GCALC_DBUG_ASSERT(more_points()); + + /* Clear the old event marks. */ + if (m_bottom_points) + { + free_list((Gcalc_dyn_list::Item **) &m_bottom_points, + (Gcalc_dyn_list::Item **) m_bottom_hook); + m_bottom_points= NULL; + m_bottom_hook= &m_bottom_points; + } + for (sp= *state.event_position_hook; + sp != state.event_end; sp= sp->get_next()) + sp->event= scev_none; + +//#ifndef GCALC_DBUG_OFF + state.event_position_hook= NULL; + state.pi= NULL; +//#endif /*GCALC_DBUG_OFF*/ + + do + { +#ifndef GCALC_DBUG_OFF + if (m_cur_pi->type == Gcalc_heap::nt_intersection && + m_cur_pi->get_next()->type == Gcalc_heap::nt_intersection && + m_cur_pi->equal_intersection) + GCALC_DBUG_ASSERT(cmp_intersections(m_cur_pi, m_cur_pi->get_next()) == 0); +#endif /*GCALC_DBUG_OFF*/ + GCALC_DBUG_CHECK_COUNTER(); + GCALC_DBUG_PRINT_SLICE("step:", state.slice); + GCALC_DBUG_PRINT_PI(m_cur_pi); + if (m_cur_pi->type == Gcalc_heap::nt_shape_node) + { + if (m_cur_pi->is_top()) + { + result= insert_top_node(); + if (!m_cur_pi->is_bottom()) + do_sorting++; + } + else if (m_cur_pi->is_bottom()) + remove_bottom_node(); + else + { + do_sorting++; + result= node_scan(); + } + if (result) + GCALC_DBUG_RETURN(result); + state.pi= m_cur_pi; + } + else if (m_cur_pi->type == Gcalc_heap::nt_eq_node) + { + do_sorting++; + eq_scan(); + } + else + { + /* nt_intersection */ + do_sorting++; + n_intersections++; + intersection_scan(); + if (!state.pi || state.pi->type == Gcalc_heap::nt_intersection) + state.pi= m_cur_pi; + } + + m_cur_pi= m_cur_pi->get_next(); + } while (m_cur_pi && state.pi->equal_pi(m_cur_pi)); + + GCALC_DBUG_RETURN(arrange_event(do_sorting, n_intersections)); +} + + +static int node_on_right(const Gcalc_heap::Info *node, + const Gcalc_heap::Info *edge_a, const Gcalc_heap::Info *edge_b) +{ + Gcalc_coord1 a_x, a_y; + Gcalc_coord1 b_x, b_y; + Gcalc_coord2 ax_by, ay_bx; + a_x.init(); + a_y.init(); + b_x.init(); + b_y.init(); + ax_by.init(); + ay_bx.init(); + + gcalc_sub_coord(&a_x, &node->ix, &edge_a->ix); + gcalc_sub_coord(&a_y, &node->iy, &edge_a->iy); + gcalc_sub_coord(&b_x, &edge_b->ix, &edge_a->ix); + gcalc_sub_coord(&b_y, &edge_b->iy, &edge_a->iy); + gcalc_mul_coord(&ax_by, &a_x, &b_y); + gcalc_mul_coord(&ay_bx, &a_y, &b_x); + return gcalc_cmp_coord(&ax_by, &ay_bx); +} + + +static int cmp_tops(const Gcalc_heap::Info *top_node, + const Gcalc_heap::Info *edge_a, const Gcalc_heap::Info *edge_b) +{ + int cmp_res_a, cmp_res_b; + + cmp_res_a= gcalc_cmp_coord1(&edge_a->ix, &top_node->ix); + cmp_res_b= gcalc_cmp_coord1(&edge_b->ix, &top_node->ix); + + if (cmp_res_a <= 0 && cmp_res_b > 0) + return -1; + if (cmp_res_b <= 0 && cmp_res_a > 0) + return 1; + if (cmp_res_a == 0 && cmp_res_b == 0) + return 0; + + return node_on_right(edge_a, top_node, edge_b); +} + + +int Gcalc_scan_iterator::insert_top_node() +{ + point *sp= state.slice; + point **prev_hook= &state.slice; point *sp1; point *sp0= new_slice_point(); - point *sp_inc; + int cmp_res; - GCALC_DBUG_ENTER("Gcalc_scan_iterator::insert_top_point"); + GCALC_DBUG_ENTER("Gcalc_scan_iterator::insert_top_node"); if (!sp0) GCALC_DBUG_RETURN(1); sp0->pi= m_cur_pi; sp0->next_pi= m_cur_pi->left; +#ifndef GCALC_DBUG_OFF sp0->thread= m_cur_thread++; +#endif /*GCALC_DBUG_OFF*/ if (m_cur_pi->left) { calc_dx_dy(sp0); - sp0->event= scev_thread; - - /*Now just to increase the size of m_slice0 to be same*/ - if (!(sp_inc= new_slice_point())) - GCALC_DBUG_RETURN(1); - sp_inc->next= current_state->slice; - current_state->slice= sp_inc; if (m_cur_pi->right) { if (!(sp1= new_slice_point())) @@ -1184,683 +1396,424 @@ int Gcalc_scan_iterator::insert_top_point() sp1->event= sp0->event= scev_two_threads; sp1->pi= m_cur_pi; sp1->next_pi= m_cur_pi->right; +#ifndef GCALC_DBUG_OFF sp1->thread= m_cur_thread++; +#endif /*GCALC_DBUG_OFF*/ calc_dx_dy(sp1); /* We have two threads so should decide which one will be first */ - if (sp0->cmp_dx_dy(sp1)>0) + cmp_res= cmp_tops(m_cur_pi, m_cur_pi->left, m_cur_pi->right); + if (cmp_res > 0) { point *tmp= sp0; sp0= sp1; sp1= tmp; } - - /*Now just to increase the size of m_slice0 to be same*/ - if (!(sp_inc= new_slice_point())) - GCALC_DBUG_RETURN(1); - sp_inc->next= current_state->slice; - current_state->slice= sp_inc; - } - } - else - { - sp0->event= scev_single_point; - } - - - /* We need to find the place to insert. */ - for (; sp && cmp_sp_pi(sp, m_cur_pi) < 0; - prev_hook= &sp->next, sp=sp->get_next()) - {} - - next_state->event_position_hook= prev_hook; - if (sp && cmp_sp_pi(sp, m_cur_pi) == 0) - { - next_state->event_position= sp; - do - { - if (!sp->event) - sp->event= scev_intersection; - prev_hook= &sp->next; - sp= sp->get_next(); - } while (sp && cmp_sp_pi(sp, m_cur_pi) == 0); - } - else - next_state->event_position= sp0; - - *prev_hook= sp0; - if (sp0->event == scev_two_threads) - { - sp1->next= sp; - sp0->next= sp1; - next_state->event_end_hook= &sp1->next; - } - else - { - sp0->next= sp; - next_state->event_end_hook= &sp0->next; - } - GCALC_DBUG_RETURN(0); -} - - -int Gcalc_scan_iterator::normal_scan() -{ - point *sp; - Gcalc_dyn_list::Item **sp_hook; - Gcalc_heap::Info *next_pi; - point *first_bottom_point; - - GCALC_DBUG_ENTER("Gcalc_scan_iterator::normal_scan"); - GCALC_DBUG_CHECK_COUNTER(); - GCALC_DBUG_PRINT_SLICE("in\t", next_state->slice); - if (m_next_is_top_point && insert_top_point()) - GCALC_DBUG_RETURN(1); - - for (next_pi= m_cur_pi->get_next(); - next_pi && cmp_point_info(m_cur_pi, next_pi) == 0; - next_pi= next_pi->get_next()) - { - GCALC_DBUG_PRINT(("eq_loop equal pi")); - next_state->clear_event_position(); - m_next_is_top_point= true; - first_bottom_point= NULL; - for (sp= next_state->slice, - sp_hook= (Gcalc_dyn_list::Item **) &next_state->slice; sp; - sp_hook= &sp->next, sp= sp->get_next()) - { - GCALC_DBUG_PRINT(("eq_loop normal_eq_step %s%d", gcalc_ev_name(sp->event), - sp->thread)); - if (sp->next_pi == next_pi) /* End of the segment */ + else if (cmp_res == 0) { - GCALC_DBUG_PRINT(("eq_loop edge end")); - if (cmp_point_info(sp->pi, next_pi)) + /* Exactly same direction of the edges. */ + cmp_res= gcalc_cmp_coord1(&m_cur_pi->left->iy, &m_cur_pi->right->iy); + if (cmp_res != 0) { - GCALC_DBUG_PRINT(("eq_loop zero-len edge")); - sp->pi= next_pi; - } - sp->next_pi= next_pi->left; - m_next_is_top_point= false; - if (next_pi->is_bottom()) - { - GCALC_DBUG_PRINT(("eq_loop bottom_point")); - if (sp->event == scev_thread) + if (cmp_res < 0) { - /* Beginning of the thread, and the end are same */ - /* Make single point out of the line then. */ - GCALC_DBUG_PRINT(("eq_loop line_to_point")); - sp->event= scev_single_point; - } - else if (sp->event == scev_two_threads) - { - if (sp->get_next() && sp->get_next()->pi == sp->pi) - { - GCALC_DBUG_PRINT(("eq_loop two_threads_to_line %d", - sp->get_next()->thread)); - sp->get_next()->event= scev_thread; - } - else if (sp != next_state->slice) - { - point *fnd_sp; - for (fnd_sp= next_state->slice; fnd_sp->get_next() != sp; - fnd_sp= fnd_sp->get_next()) - {} - GCALC_DBUG_ASSERT(fnd_sp->pi == sp->pi); - GCALC_DBUG_PRINT(("eq_loop two_threads_to_line %d", - fnd_sp->thread)); - fnd_sp->event= scev_thread; - } - sp->event= scev_single_point; - } - else if (first_bottom_point) - { - GCALC_DBUG_PRINT(("eq_loop two_ends")); - first_bottom_point->event= sp->event= scev_two_ends; + if (add_eq_node(sp0->next_pi, sp1)) + GCALC_DBUG_RETURN(1); } else { - first_bottom_point= sp; - sp->event= scev_end; + if (add_eq_node(sp1->next_pi, sp0)) + GCALC_DBUG_RETURN(1); } } else { - GCALC_DBUG_PRINT(("eq_loop no_bottom_point %d%s", sp->thread, - gcalc_ev_name(sp->event))); - if ((sp->event & (scev_point | scev_thread | scev_two_threads)) == 0) - sp->event= scev_point; - calc_dx_dy(sp); - } - mark_event_position1(sp, sp_hook); - } - else if (sp->event || (cmp_sp_pi(sp, next_pi) == 0)) - { - GCALC_DBUG_PRINT(("eq_loop l_event %d%s", sp->thread, - gcalc_ev_name(sp->event))); - if (!sp->event) - sp->event= scev_intersection; - mark_event_position1(sp, sp_hook); - } - } - m_cur_pi= next_pi; - if (m_next_is_top_point) - { - if (insert_top_point()) - GCALC_DBUG_RETURN(1); - /* Set proper values to the event position */ - /* TODO: can be done faster */ - next_state->clear_event_position(); - if (next_state->slice->event) - mark_event_position1(next_state->slice, - (Gcalc_dyn_list::Item **) &next_state->slice); - for (sp= next_state->slice; sp->get_next(); sp= sp->get_next()) - { - if (sp->get_next()->event) - mark_event_position1(sp->get_next(), &sp->next); - } - } - GCALC_DBUG_PRINT_SLICE("eq_loop\t", next_state->slice); - } - - /* Swap current <-> next */ - { - slice_state *tmp= current_state; - current_state= next_state; - next_state= tmp; - } - - if (arrange_event()) - GCALC_DBUG_RETURN(1); - GCALC_DBUG_PRINT_SLICE("after_arrange\t", current_state->slice); - GCALC_DBUG_PRINT_SLICE("events\t", m_events); - GCALC_DBUG_PRINT_STATE(current_state); - - point *sp0= current_state->slice; - point *sp1= next_state->slice; - point *prev_sp1= NULL; - - if (!(m_cur_pi= next_pi)) - { - free_list(sp1); - next_state->slice= NULL; - GCALC_DBUG_RETURN(0); - } - - next_state->intersection_scan= 0; - next_state->pi= m_cur_pi; - Gcalc_heap::Info *cur_pi= m_cur_pi; - - - first_bottom_point= NULL; - m_next_is_top_point= true; - bool intersections_found= false; - next_state->clear_event_position(); - - for (; sp0; sp0= sp0->get_next()) - { - GCALC_DBUG_ASSERT(!sp0->is_bottom()); - if (sp0->next_pi == cur_pi) /* End of the segment */ - { - GCALC_DBUG_PRINT(("edge_end %d", sp0->thread)); - sp1->pi= cur_pi; - sp1->thread= sp0->thread; - sp1->next_pi= cur_pi->left; - - m_next_is_top_point= false; - - if (sp1->is_bottom()) - { - GCALC_DBUG_PRINT(("bottom_point")); - if (!first_bottom_point) - { - sp1->event= scev_end; - first_bottom_point= sp1; - } - else - { - GCALC_DBUG_PRINT(("two_ends")); - first_bottom_point->event= sp1->event= scev_two_ends; + cmp_res= gcalc_cmp_coord1(&m_cur_pi->left->ix, &m_cur_pi->right->ix); + if (cmp_res != 0) + { + if (cmp_res < 0) + { + if (add_eq_node(sp0->next_pi, sp1)) + GCALC_DBUG_RETURN(1); + } + else + { + if (add_eq_node(sp1->next_pi, sp0)) + GCALC_DBUG_RETURN(1); + } + } } } - else - { - sp1->event= scev_point; - calc_dx_dy(sp1); - } - mark_event_position1(sp1, - prev_sp1 ? &prev_sp1->next : - (Gcalc_dyn_list::Item **) &next_state->slice); } else - { - GCALC_DBUG_PRINT(("cut_edge %d", sp0->thread)); - /* Cut current string with the height of the new point*/ - sp1->copy_core(sp0); - if (cmp_sp_pi(sp1, cur_pi) == 0) - { - GCALC_DBUG_PRINT(("equal_point")); - mark_event_position1(sp1, - prev_sp1 ? &prev_sp1->next : - (Gcalc_dyn_list::Item **) &next_state->slice); - sp1->event= scev_intersection; - } - else - sp1->event= scev_none; - } - - intersections_found= intersections_found || - (prev_sp1 && cmp_sp_sp(prev_sp1, sp1, cur_pi) > 0); - GCALC_DBUG_PRINT(("%s", intersections_found ? "X":"-")); - - prev_sp1= sp1; - sp1= sp1->get_next(); + sp0->event= scev_thread; } + else + sp0->event= scev_single_point; - if (sp1) + + /* Check if we already have an event - then we'll place the node there */ + for (; sp && !sp->event; prev_hook= sp->next_ptr(), sp=sp->get_next()) + {} + if (!sp) { - if (prev_sp1) - prev_sp1->next= NULL; - else - next_state->slice= NULL; - free_list(sp1); - } - - GCALC_DBUG_PRINT_SLICE("after_loop\t", next_state->slice); - if (intersections_found) - GCALC_DBUG_RETURN(handle_intersections()); - - GCALC_DBUG_RETURN(0); -} - - -int Gcalc_scan_iterator::add_intersection(int n_row, - const point *a, const point *b, - Gcalc_dyn_list::Item ***p_hook) -{ - const point *a0= a->intersection_link; - const point *b0= b->intersection_link; - intersection *isc= new_intersection(); - - GCALC_DBUG_ENTER("Gcalc_scan_iterator::add_intersection"); - if (!isc) - GCALC_DBUG_RETURN(1); - - m_n_intersections++; - **p_hook= isc; - *p_hook= &isc->next; - isc->n_row= n_row; - isc->thread_a= a->thread; - isc->thread_b= b->thread; - - isc->ii= m_heap->new_intersection(a0->pi, a0->next_pi, - b0->pi, b0->next_pi); - GCALC_DBUG_RETURN(isc->ii == NULL); -} - - -int Gcalc_scan_iterator::find_intersections() -{ - Gcalc_dyn_list::Item **hook; - - GCALC_DBUG_ENTER("Gcalc_scan_iterator::find_intersections"); - m_n_intersections= 0; - { - /* Set links between slicepoints */ - point *sp0= current_state->slice; - point *sp1= next_state->slice; - for (; sp1; sp0= sp0->get_next(),sp1= sp1->get_next()) + sp= state.slice; + prev_hook= &state.slice; + /* We need to find the place to insert. */ + for (; sp; prev_hook= sp->next_ptr(), sp=sp->get_next()) { - GCALC_DBUG_ASSERT(!sp0->is_bottom()); - GCALC_DBUG_ASSERT(sp0->thread == sp1->thread); - sp1->intersection_link= sp0; - } - } - - hook= (Gcalc_dyn_list::Item **)&m_intersections; - bool intersections_found; - int n_row= 0; - - do - { - point **pprev_s1= &next_state->slice; - intersections_found= false; - n_row++; - for (;;) - { - point *prev_s1= *pprev_s1; - point *s1= prev_s1->get_next(); - if (!s1) - break; - if (cmp_sp_sp(prev_s1, s1, m_cur_pi) <= 0) - { - pprev_s1= (point **) &prev_s1->next; + if (sp->event || gcalc_cmp_coord(sp->r_border, &m_cur_pi->ix) < 0) continue; + cmp_res= node_on_right(m_cur_pi, sp->pi, sp->next_pi); + if (cmp_res == 0) + { + /* The top node lies on the edge. */ + /* Nodes of that edge will be handled in other places. */ + sp->event= scev_intersection; } - intersections_found= true; - if (add_intersection(n_row, prev_s1, s1, &hook)) - GCALC_DBUG_RETURN(1); - *pprev_s1= s1; - prev_s1->next= s1->next; - s1->next= prev_s1; - pprev_s1= (point **) &prev_s1->next; - if (!*pprev_s1) + else if (cmp_res < 0) break; - }; - } while (intersections_found); - - *hook= NULL; - GCALC_DBUG_RETURN(0); -} - - -class Gcalc_coord4 : public Gcalc_internal_coord -{ - gcalc_digit_t c[GCALC_COORD_BASE*4]; - public: - void init() - { - n_digits= GCALC_COORD_BASE*4; - digits= c; - } -}; - -class Gcalc_coord5 : public Gcalc_internal_coord -{ - gcalc_digit_t c[GCALC_COORD_BASE*5]; - public: - void init() - { - n_digits= GCALC_COORD_BASE*5; - digits= c; - } -}; - - -static void calc_isc_exp(Gcalc_coord5 *exp, - const Gcalc_coord2 *bb2, - const Gcalc_coord1 *ya1, - const Gcalc_coord2 *bb1, - const Gcalc_coord1 *yb1, - const Gcalc_coord2 *a21_b1) -{ - Gcalc_coord3 p1, p2, sum; - p1.init(); - p2.init(); - sum.init(); - exp->init(); - - gcalc_mul_coord(&p1, ya1, bb1); - gcalc_mul_coord(&p2, yb1, a21_b1); - gcalc_add_coord(&sum, &p1, &p2); - gcalc_mul_coord(exp, bb2, &sum); -} - - -static int cmp_intersections(const Gcalc_heap::Intersection_info *i1, - const Gcalc_heap::Intersection_info *i2) -{ - Gcalc_coord2 t_a1, t_b1; - Gcalc_coord2 t_a2, t_b2; - Gcalc_coord1 yb1, yb2; - Gcalc_coord1 xb1, xb2; - Gcalc_coord5 exp_a, exp_b; - int result; - - calc_t(&t_a1, &t_b1, &xb1, &yb1, i1); - calc_t(&t_a2, &t_b2, &xb2, &yb2, i2); - - calc_isc_exp(&exp_a, &t_b2, &i1->p1->iy, &t_b1, &yb1, &t_a1); - calc_isc_exp(&exp_b, &t_b1, &i2->p1->iy, &t_b2, &yb2, &t_a2); - - result= gcalc_cmp_coord(&exp_a, &exp_b); -#ifdef GCALC_CHECK_WITH_FLOAT - long double x1, y1, x2, y2; - i1->calc_xy_ld(&x1, &y1); - i2->calc_xy_ld(&x2, &y2); - - if (result == 0) - GCALC_DBUG_ASSERT(de_check(y1, y2)); - if (result < 0) - GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 < y2); - if (result > 0) - GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 > y2); -#endif /*GCALC_CHECK_WITH_FLOAT*/ - - if (result != 0) - return result; - - - calc_isc_exp(&exp_a, &t_b2, &i1->p1->ix, &t_b1, &xb1, &t_a1); - calc_isc_exp(&exp_b, &t_b1, &i2->p1->ix, &t_b2, &xb2, &t_a2); - result= gcalc_cmp_coord(&exp_a, &exp_b); -#ifdef GCALC_CHECK_WITH_FLOAT - if (result == 0) - GCALC_DBUG_ASSERT(de_check(x1, x2)); - if (result < 0) - GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 < x2); - if (result > 0) - GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 > x2); -#endif /*GCALC_CHECK_WITH_FLOAT*/ - return result; -} - -static int compare_intersections(const void *e1, const void *e2) -{ - Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1; - Gcalc_scan_iterator::intersection *i2= (Gcalc_scan_iterator::intersection *)e2; - int result= cmp_intersections(i1->ii, i2->ii); - if (result != 0) - return result > 0; - return (i1->n_row > i2->n_row); -} - -inline int intersections_eq(const Gcalc_heap::Intersection_info *i1, - const Gcalc_heap::Intersection_info *i2) -{ - return cmp_intersections(i1, i2) == 0; -} - - -static int sp_isc_eq(const Gcalc_scan_iterator::point *sp, - const Gcalc_heap::Intersection_info *isc) -{ - - Gcalc_coord4 exp_a, exp_b; - Gcalc_coord1 xb1, yb1; - Gcalc_coord2 t_a, t_b; - Gcalc_coord2 t_sp_a, t_sp_b; - exp_a.init(); - exp_b.init(); - calc_t(&t_a, &t_b, &xb1, &yb1, isc); - calc_t(&t_sp_a, &t_sp_b, &xb1, &yb1, isc->p1, isc->p2, sp->pi, sp->next_pi); - - gcalc_mul_coord(&exp_a, &t_a, &t_sp_b); - gcalc_mul_coord(&exp_b, &t_b, &t_sp_a); - int result= gcalc_cmp_coord(&exp_a, &exp_b); -#ifdef GCALC_CHECK_WITH_FLOAT - long double int_x, int_y, sp_x; - isc->calc_xy_ld(&int_x, &int_y); - sp->calc_x(&sp_x, int_y, int_x); - if (result == 0) - GCALC_DBUG_ASSERT(de_check(sp->dy.get_double(), 0.0) || - de_check(sp_x, int_x)); -#endif /*GCALC_CHECK_WITH_FLOAT*/ - return result == 0; -} - - -inline void Gcalc_scan_iterator::sort_intersections() -{ - m_intersections= (intersection *)sort_list(compare_intersections, - m_intersections,m_n_intersections); -} - - -int Gcalc_scan_iterator::handle_intersections() -{ - GCALC_DBUG_ENTER("Gcalc_scan_iterator::handle_intersections"); - GCALC_DBUG_ASSERT(next_state->slice->next); - - if (find_intersections()) - GCALC_DBUG_RETURN(1); - GCALC_DBUG_PRINT_INTERSECTIONS(m_intersections); - sort_intersections(); - GCALC_DBUG_PRINT(("After sorting")); - GCALC_DBUG_PRINT_INTERSECTIONS(m_intersections); - - /* Swap saved <-> next */ - { - slice_state *tmp= next_state; - next_state= saved_state; - saved_state= tmp; - } - /* We need the next slice to be just equal */ - next_state->slice= new_slice(saved_state->slice); - m_cur_intersection= m_intersections; - GCALC_DBUG_RETURN(intersection_scan()); -} - - -int Gcalc_scan_iterator::intersection_scan() -{ - point *sp0, *sp1; - Gcalc_dyn_list::Item **hook; - intersection *next_intersection= NULL; - - GCALC_DBUG_ENTER("Gcalc_scan_iterator::intersection_scan"); - GCALC_DBUG_CHECK_COUNTER(); - if (m_cur_intersection != m_intersections) - { - GCALC_DBUG_PRINT_SLICE("in_isc\t", next_state->slice); - /* Swap current <-> next */ - { - slice_state *tmp= current_state; - current_state= next_state; - next_state= tmp; } +#ifdef TMP_BLOCK + state.event_position_hook= prev_hook; +#endif /*TMP_BLOCK*/ + } - if (arrange_event()) + if (sp0->event == scev_single_point) + { + /* Add single point to the bottom list. */ + *m_bottom_hook= sp0; + m_bottom_hook= sp0->next_ptr(); + state.event_position_hook= prev_hook; + } + else + { + *prev_hook= sp0; + sp0->next= sp; + if (add_events_for_node(sp0)) GCALC_DBUG_RETURN(1); - GCALC_DBUG_PRINT_SLICE("isc_after_arrange\t", current_state->slice); - if (!m_cur_intersection) + if (sp0->event == scev_two_threads) { - /* Swap saved <-> next */ - { - slice_state *tmp= next_state; - next_state= saved_state; - saved_state= tmp; - } - Gcalc_dyn_list::Item **n_hook= - (Gcalc_dyn_list::Item **) &next_state->slice; + *prev_hook= sp1; + sp1->next= sp; + if (add_events_for_node(sp1)) + GCALC_DBUG_RETURN(1); - next_state->clear_event_position(); - sp0= current_state->slice; - sp1= next_state->slice; - - for (; sp0; - sp0= sp0->get_next(), n_hook= &sp1->next, sp1= sp1->get_next()) - { - if (sp0->thread != sp1->thread) - { - point *fnd_s= sp1->get_next(); - Gcalc_dyn_list::Item **fnd_hook= &sp1->next; - for (; fnd_s && fnd_s->thread != sp0->thread; - fnd_hook= &fnd_s->next, fnd_s= fnd_s->get_next()) - {} - GCALC_DBUG_ASSERT(fnd_s && fnd_s == *fnd_hook); - /* Now swap items of the next_state->slice */ - *n_hook= fnd_s; - *fnd_hook= fnd_s->next; - fnd_s->next= sp1; - sp1= fnd_s; - } - if (sp1->event) - mark_event_position1(sp1, n_hook); - } -#ifndef GCALC_DBUG_OFF - sp0= current_state->slice; - sp1= next_state->slice; - for (; sp0; sp0= sp0->get_next(), sp1= sp1->get_next()) - GCALC_DBUG_ASSERT(sp0->thread == sp1->thread); - GCALC_DBUG_ASSERT(!sp1); -#endif /*GCALC_DBUG_OFF*/ - free_list(saved_state->slice); - saved_state->slice= NULL; - - free_list(m_intersections); - m_intersections= NULL; - GCALC_DBUG_RETURN(0); + sp0->next= sp1; + *prev_hook= sp0; } } - sp0= current_state->slice; - hook= (Gcalc_dyn_list::Item **) &next_state->slice; - sp1= next_state->slice; - next_state->clear_event_position(); - next_state->intersection_scan= 1; - next_state->isc= m_cur_intersection->ii; + GCALC_DBUG_RETURN(0); +} - for (; sp0; - hook= &sp1->next, sp1= sp1->get_next(), sp0= sp0->get_next()) + +void Gcalc_scan_iterator::remove_bottom_node() +{ + point *sp= state.slice; + point **sp_hook= &state.slice; + point *first_bottom_point= NULL; + + GCALC_DBUG_ENTER("Gcalc_scan_iterator::remove_bottom_node"); + for (; sp; sp= sp->get_next()) { - if (sp0->thread == m_cur_intersection->thread_a || - sp0->thread == m_cur_intersection->thread_b) + if (sp->next_pi == m_cur_pi) { - GCALC_DBUG_ASSERT(sp0->thread != m_cur_intersection->thread_a || - sp0->get_next()->thread == m_cur_intersection->thread_b || - sp_isc_eq(sp0->get_next(), m_cur_intersection->ii)); - GCALC_DBUG_PRINT(("isc_i_thread %d", sp0->thread)); - sp1->copy_core(sp0); - sp1->event= scev_intersection; - mark_event_position1(sp1, hook); + *sp_hook= sp->get_next(); + sp->pi= m_cur_pi; + sp->next_pi= NULL; + if (first_bottom_point) + { + first_bottom_point->event= sp->event= scev_two_ends; + break; + } + first_bottom_point= sp; + sp->event= scev_end; + state.event_position_hook= sp_hook; } else + sp_hook= sp->next_ptr(); + } + GCALC_DBUG_ASSERT(first_bottom_point); + *m_bottom_hook= first_bottom_point; + m_bottom_hook= first_bottom_point->next_ptr(); + if (sp) + { + *m_bottom_hook= sp; + m_bottom_hook= sp->next_ptr(); + } + + GCALC_DBUG_VOID_RETURN; +} + + +int Gcalc_scan_iterator::add_events_for_node(point *sp_node) +{ + point *sp= state.slice; + int cur_pi_r, sp_pi_r; + + GCALC_DBUG_ENTER("Gcalc_scan_iterator::add_events_for_node"); + + /* Scan to the event point. */ + for (; sp != sp_node; sp= sp->get_next()) + { + GCALC_DBUG_ASSERT(!sp->is_bottom()); + GCALC_DBUG_PRINT(("left cut_edge %d", sp->thread)); + if (sp->next_pi == sp_node->next_pi || + gcalc_cmp_coord1(sp->r_border, sp_node->l_border) < 0) + continue; + sp_pi_r= node_on_right(sp->next_pi, sp_node->pi, sp_node->next_pi); + if (sp_pi_r < 0) + continue; + cur_pi_r= node_on_right(sp_node->next_pi, sp->pi, sp->next_pi); + if (cur_pi_r > 0) + continue; + if (cur_pi_r == 0 && sp_pi_r == 0) { - GCALC_DBUG_PRINT(("isc_cut %d", sp0->thread)); - sp1->copy_core(sp0); - if (sp_isc_eq(sp1, m_cur_intersection->ii)) + int cmp_res= cmp_point_info(sp->next_pi, sp_node->next_pi); + if (cmp_res > 0) { - sp1->event= scev_intersection; - mark_event_position1(sp1, hook); + if (add_eq_node(sp_node->next_pi, sp)) + GCALC_DBUG_RETURN(1); } + else if (cmp_res < 0) + { + if (add_eq_node(sp->next_pi, sp_node)) + GCALC_DBUG_RETURN(1); + } + continue; + } + + if (cur_pi_r == 0) + { + if (add_eq_node(sp_node->next_pi, sp)) + GCALC_DBUG_RETURN(1); + continue; + } + else if (sp_pi_r == 0) + { + if (add_eq_node(sp->next_pi, sp_node)) + GCALC_DBUG_RETURN(1); + continue; + } + + if (sp->event) + { +#ifndef GCALC_DBUG_OFF + cur_pi_r= node_on_right(sp_node->pi, sp->pi, sp->next_pi); + GCALC_DBUG_ASSERT(cur_pi_r == 0); +#endif /*GCALC_DBUG_OFF*/ + continue; + } + cur_pi_r= node_on_right(sp_node->pi, sp->pi, sp->next_pi); + GCALC_DBUG_ASSERT(cur_pi_r >= 0); + //GCALC_DBUG_ASSERT(cur_pi_r > 0); /* Is it ever violated? */ + if (cur_pi_r > 0 && add_intersection(sp, sp_node, m_cur_pi)) + GCALC_DBUG_RETURN(1); + } + + /* Scan to the end of the slice */ + sp= sp->get_next(); + + for (; sp; sp= sp->get_next()) + { + GCALC_DBUG_ASSERT(!sp->is_bottom()); + GCALC_DBUG_PRINT(("right cut_edge %d", sp->thread)); + if (sp->next_pi == sp_node->next_pi || + gcalc_cmp_coord1(sp_node->r_border, sp->l_border) < 0) + continue; + sp_pi_r= node_on_right(sp->next_pi, sp_node->pi, sp_node->next_pi); + if (sp_pi_r > 0) + continue; + cur_pi_r= node_on_right(sp_node->next_pi, sp->pi, sp->next_pi); + if (cur_pi_r < 0) + continue; + if (cur_pi_r == 0 && sp_pi_r == 0) + { + int cmp_res= cmp_point_info(sp->next_pi, sp_node->next_pi); + if (cmp_res > 0) + { + if (add_eq_node(sp_node->next_pi, sp)) + GCALC_DBUG_RETURN(1); + } + else if (cmp_res < 0) + { + if (add_eq_node(sp->next_pi, sp_node)) + GCALC_DBUG_RETURN(1); + } + continue; + } + if (cur_pi_r == 0) + { + if (add_eq_node(sp_node->next_pi, sp)) + GCALC_DBUG_RETURN(1); + continue; + } + else if (sp_pi_r == 0) + { + if (add_eq_node(sp->next_pi, sp_node)) + GCALC_DBUG_RETURN(1); + continue; + } + + if (sp->event) + { +#ifndef GCALC_DBUG_OFF + cur_pi_r= node_on_right(sp_node->pi, sp->pi, sp->next_pi); + GCALC_DBUG_ASSERT(cur_pi_r == 0); +#endif /*GCALC_DBUG_OFF*/ + continue; + } + cur_pi_r= node_on_right(sp_node->pi, sp->pi, sp->next_pi); + GCALC_DBUG_ASSERT(cur_pi_r <= 0); + //GCALC_DBUG_ASSERT(cur_pi_r < 0); /* Is it ever violated? */ + if (cur_pi_r < 0 && add_intersection(sp_node, sp, m_cur_pi)) + GCALC_DBUG_RETURN(1); + } + + GCALC_DBUG_RETURN(0); +} + + +int Gcalc_scan_iterator::node_scan() +{ + point *sp= state.slice; + Gcalc_heap::Info *cur_pi= m_cur_pi; + + GCALC_DBUG_ENTER("Gcalc_scan_iterator::node_scan"); + + /* Scan to the event point. */ + /* Can be avoided if we add link to the sp to the Info. */ + for (; sp->next_pi != cur_pi; sp= sp->get_next()) + {} + + GCALC_DBUG_PRINT(("node for %d", sp->thread)); + /* Handle the point itself. */ + sp->pi= cur_pi; + sp->next_pi= cur_pi->left; + sp->event= scev_point; + calc_dx_dy(sp); + + GCALC_DBUG_RETURN(add_events_for_node(sp)); +} + + +void Gcalc_scan_iterator::eq_scan() +{ + point *sp= eq_sp(m_cur_pi); + GCALC_DBUG_ENTER("Gcalc_scan_iterator::eq_scan"); + +#ifndef GCALC_DBUG_OFF + { + point *cur_p= state.slice; + for (; cur_p && cur_p != sp; cur_p= cur_p->get_next()) + {} + GCALC_DBUG_ASSERT(cur_p); + } +#endif /*GCALC_DBUG_OFF*/ + if (!sp->event) + { + sp->event= scev_intersection; + sp->ev_pi= m_cur_pi; + } + + GCALC_DBUG_VOID_RETURN; +} + + +void Gcalc_scan_iterator::intersection_scan() +{ + intersection_info *ii= i_data(m_cur_pi); + GCALC_DBUG_ENTER("Gcalc_scan_iterator::intersection_scan"); + +#ifndef GCALC_DBUG_OFF + { + point *sp= state.slice; + for (; sp && sp != ii->edge_a; sp= sp->get_next()) + {} + GCALC_DBUG_ASSERT(sp); + for (; sp && sp != ii->edge_b; sp= sp->get_next()) + {} + GCALC_DBUG_ASSERT(sp); + } +#endif /*GCALC_DBUG_OFF*/ + + ii->edge_a->event= ii->edge_b->event= scev_intersection; + ii->edge_a->ev_pi= ii->edge_b->ev_pi= m_cur_pi; + free_item(ii); + m_cur_pi->intersection_data= NULL; + + GCALC_DBUG_VOID_RETURN; +} + + +int Gcalc_scan_iterator::add_intersection(point *sp_a, point *sp_b, + Gcalc_heap::Info *pi_from) +{ + Gcalc_heap::Info *ii; + intersection_info *i_calc; + int cmp_res; + int skip_next= 0; + + GCALC_DBUG_ENTER("Gcalc_scan_iterator::add_intersection"); + if (!(i_calc= new_intersection_info(sp_a, sp_b)) || + !(ii= new_intersection(m_heap, i_calc))) + GCALC_DBUG_RETURN(1); + + ii->equal_intersection= 0; + + for (; + pi_from->get_next() != sp_a->next_pi && + pi_from->get_next() != sp_b->next_pi; + pi_from= pi_from->get_next()) + { + Gcalc_heap::Info *cur= pi_from->get_next(); + if (skip_next) + { + if (cur->type == Gcalc_heap::nt_intersection) + skip_next= cur->equal_intersection; else - sp1->event= scev_none; + skip_next= 0; + continue; } - } - - if (sp1) - { - free_list(sp1); - *hook= NULL; - } - - /* Now check equal intersections */ - for (next_intersection= m_cur_intersection->get_next(); - next_intersection && - intersections_eq(next_intersection->ii, m_cur_intersection->ii); - next_intersection= next_intersection->get_next()) - { - /* Handle equal intersections. We only need to set proper events */ - GCALC_DBUG_PRINT(("isc_eq_intersection")); - sp0= current_state->slice; - hook= (Gcalc_dyn_list::Item **) &next_state->slice; - sp1= next_state->slice; - next_state->clear_event_position(); - - for (; sp0; - hook= &sp1->next, sp1= sp1->get_next(), sp0= sp0->get_next()) + if (cur->type == Gcalc_heap::nt_intersection) { - if (sp0->thread == next_intersection->thread_a || - sp0->thread == next_intersection->thread_b || - sp1->event == scev_intersection) - { - GCALC_DBUG_PRINT(("isc_eq_thread %d", sp0->thread)); - sp1->event= scev_intersection; - mark_event_position1(sp1, hook); - } + cmp_res= cmp_intersections(cur, ii); + skip_next= cur->equal_intersection; } + else if (cur->type == Gcalc_heap::nt_eq_node) + continue; + else + cmp_res= cmp_node_isc(cur, ii); + if (cmp_res == 0) + { + ii->equal_intersection= 1; + break; + } + else if (cmp_res > 0) + break; } - m_cur_intersection= next_intersection; + + /* Intersection inserted before the equal point. */ + ii->next= pi_from->get_next(); + pi_from->next= ii; + + GCALC_DBUG_RETURN(0); +} + + +int Gcalc_scan_iterator::add_eq_node(Gcalc_heap::Info *node, point *sp) +{ + Gcalc_heap::Info *en; + + GCALC_DBUG_ENTER("Gcalc_scan_iterator::add_intersection"); + en= new_eq_point(m_heap, node, sp); + if (!en) + GCALC_DBUG_RETURN(1); + + /* eq_node iserted after teh equal point. */ + en->next= node->get_next(); + node->next= en; GCALC_DBUG_RETURN(0); } @@ -1868,40 +1821,40 @@ int Gcalc_scan_iterator::intersection_scan() double Gcalc_scan_iterator::get_y() const { - if (current_state->intersection_scan) + if (state.pi->type == Gcalc_heap::nt_intersection) { double x, y; - current_state->isc->calc_xy(&x, &y); + state.pi->calc_xy(&x, &y); return y; } else - return current_state->pi->y; + return state.pi->y; } double Gcalc_scan_iterator::get_event_x() const { - if (current_state->intersection_scan) + if (state.pi->type == Gcalc_heap::nt_intersection) { double x, y; - current_state->isc->calc_xy(&x, &y); + state.pi->calc_xy(&x, &y); return x; } else - return current_state->pi->x; + return state.pi->x; } double Gcalc_scan_iterator::get_h() const { double cur_y= get_y(); double next_y; - if (next_state->intersection_scan) + if (state.pi->type == Gcalc_heap::nt_intersection) { double x; - next_state->isc->calc_xy(&x, &next_y); + state.pi->calc_xy(&x, &next_y); } else - next_y= next_state->pi->y; + next_y= state.pi->y; return next_y - cur_y; } @@ -1919,4 +1872,3 @@ double Gcalc_scan_iterator::get_sp_x(const point *sp) const #endif /* HAVE_SPATIAL */ - diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index 22b7cc44027..3655b11bc15 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -28,11 +28,13 @@ #define GCALC_DBUG_PRINT(b) DBUG_PRINT("Gcalc", b) #define GCALC_DBUG_ENTER(a) DBUG_ENTER("Gcalc "a) #define GCALC_DBUG_RETURN(r) DBUG_RETURN(r) +#define GCALC_DBUG_VOID_RETURN DBUG_VOID_RETURN #define GCALC_DBUG_ASSERT(r) DBUG_ASSERT(r) #else #define GCALC_DBUG_PRINT(b) do {} while(0) #define GCALC_DBUG_ENTER(a) do {} while(0) #define GCALC_DBUG_RETURN(r) return (r) +#define GCALC_DBUG_VOID_RETURN do {} while(0) #define GCALC_DBUG_ASSERT(r) do {} while(0) #endif /*GCALC_DBUG_OFF*/ @@ -158,6 +160,18 @@ public: }; +class Gcalc_coord3 : public Gcalc_internal_coord +{ + gcalc_digit_t c[GCALC_COORD_BASE*3]; + public: + void init() + { + n_digits= GCALC_COORD_BASE*3; + digits= c; + } +}; + + void gcalc_mul_coord(Gcalc_internal_coord *result, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b); @@ -192,41 +206,71 @@ typedef uint gcalc_shape_info; class Gcalc_heap : public Gcalc_dyn_list { public: + enum node_type + { + nt_shape_node, + nt_intersection, + nt_eq_node + }; class Info : public Gcalc_dyn_list::Item { public: - gcalc_shape_info shape; - Info *left; - Info *right; - double x,y; - Gcalc_coord1 ix, iy; + node_type type; + union + { + struct + { + /* nt_shape_node */ + gcalc_shape_info shape; + Info *left; + Info *right; + double x,y; + Gcalc_coord1 ix, iy; + int top_node; + }; + struct + { + /* nt_intersection */ + /* Line p1-p2 supposed to intersect line p3-p4 */ + const Info *p1; + const Info *p2; + const Info *p3; + const Info *p4; + void *intersection_data; + int equal_intersection; + }; + struct + { + /* nt_eq_node */ + const Info *node; + void *eq_data; + }; + }; + + bool is_bottom() const + { GCALC_DBUG_ASSERT(type == nt_shape_node); return !left; } + bool is_top() const + { GCALC_DBUG_ASSERT(type == nt_shape_node); return top_node; } + bool is_single_node() const + { return is_bottom() && is_top(); } - inline bool is_bottom() const { return !left; } - inline Info *get_next() { return (Info *)next; } - inline const Info *get_next() const { return (const Info *)next; } - }; - class Intersection_info : public Gcalc_dyn_list::Item - { - public: - /* Line p1-p2 supposed to intersect line p3-p4 */ - const Info *p1; - const Info *p2; - const Info *p3; - const Info *p4; void calc_xy(double *x, double *y) const; + int equal_pi(const Info *pi) const; #ifdef GCALC_CHECK_WITH_FLOAT void calc_xy_ld(long double *x, long double *y) const; #endif /*GCALC_CHECK_WITH_FLOAT*/ + + Info *get_next() { return (Info *)next; } + const Info *get_next() const { return (const Info *)next; } }; Gcalc_heap(size_t blk_size=8192) : Gcalc_dyn_list(blk_size, sizeof(Info)), - m_hook(&m_first), m_n_points(0), - m_intersection_hook((Gcalc_dyn_list::Item **) &m_first_intersection) + m_hook(&m_first), m_n_points(0) {} Info *new_point_info(double x, double y, gcalc_shape_info shape); - Intersection_info *new_intersection(const Info *p1, const Info *p2, - const Info *p3, const Info *p4); + Info *new_intersection(const Info *p1, const Info *p2, + const Info *p3, const Info *p4); void prepare_operation(); inline bool ready() const { return m_hook == NULL; } Info *get_first() { return (Info *)m_first; } @@ -240,8 +284,6 @@ private: Gcalc_dyn_list::Item *m_first; Gcalc_dyn_list::Item **m_hook; int m_n_points; - Intersection_info *m_first_intersection; - Gcalc_dyn_list::Item **m_intersection_hook; double coord_extent; }; @@ -345,7 +387,6 @@ enum Gcalc_scan_events scev_single_point= 64 /* Got single point */ }; -typedef int sc_thread_id; /* Gcalc_scan_iterator incapsulates the slisescan algorithm. @@ -366,12 +407,11 @@ public: Gcalc_coord1 dy; Gcalc_heap::Info *pi; Gcalc_heap::Info *next_pi; - sc_thread_id thread; + Gcalc_heap::Info *ev_pi; const Gcalc_coord1 *l_border; const Gcalc_coord1 *r_border; - int always_on_left; + point *ev_next; - const point *intersection_link; Gcalc_scan_events event; inline const point *c_get_next() const @@ -380,9 +420,6 @@ public: gcalc_shape_info get_shape() const { return pi->shape; } inline point *get_next() { return (point *)next; } inline const point *get_next() const { return (const point *)next; } - /* copies all but 'next' 'x' and 'precursor' */ - void copy_core(const point *from); - void copy_all(const point *from); /* Compare the dx_dy parameters regarding the horiz_dir */ /* returns -1 if less, 0 if equal, 1 if bigger */ static int cmp_dx_dy(const Gcalc_coord1 *dx_a, @@ -394,48 +431,52 @@ public: const Gcalc_heap::Info *p3, const Gcalc_heap::Info *p4); int cmp_dx_dy(const point *p) const; - int simple_event() const - { - return !next ? (event & (scev_point | scev_end)) : - (!next->next && event == scev_two_ends); - } -#ifndef DBUG_OFF - void dbug_print(); -#endif /*DBUG_OFF*/ + point **next_ptr() { return (point **) &next; } +#ifndef GCALC_DBUG_OFF + unsigned int thread; +#endif /*GCALC_DBUG_OFF*/ #ifdef GCALC_CHECK_WITH_FLOAT void calc_x(long double *x, long double y, long double ix) const; #endif /*GCALC_CHECK_WITH_FLOAT*/ }; - class intersection : public Gcalc_dyn_list::Item + /* That class introduced mostly for the 'typecontrol' reason. */ + /* only difference from the point classis the get_next() function. */ + class event_point : public point { public: - int n_row; - sc_thread_id thread_a; - sc_thread_id thread_b; - const Gcalc_heap::Intersection_info *ii; - inline intersection *get_next() { return (intersection *)next; } + inline const event_point *get_next() const + { return (const event_point*) ev_next; } + int simple_event() const + { + return !ev_next ? (event & (scev_point | scev_end)) : + (!ev_next->ev_next && event == scev_two_ends); + } }; + class intersection_info : public Gcalc_dyn_list::Item + { + public: + point *edge_a; + point *edge_b; + + Gcalc_coord2 t_a; + Gcalc_coord2 t_b; + int t_calculated; + Gcalc_coord3 x_exp; + int x_calculated; + Gcalc_coord3 y_exp; + int y_calculated; + }; + + class slice_state { public: point *slice; - point *event_position; - Gcalc_dyn_list::Item **event_position_hook; - Gcalc_dyn_list::Item **event_end_hook; - int intersection_scan; - union - { - const Gcalc_heap::Info *pi; - const Gcalc_heap::Intersection_info *isc; - }; - slice_state() : slice(NULL) {} - void clear_event_position() - { - event_position= NULL; - event_end_hook= (Gcalc_dyn_list::Item **) &event_position; - } + point **event_position_hook; + point *event_end; + const Gcalc_heap::Info *pi; }; public: @@ -443,68 +484,56 @@ public: void init(Gcalc_heap *points); /* Iterator can be reused */ void reset(); - int step() - { - DBUG_ASSERT(more_points()); - return m_intersections ? intersection_scan() : normal_scan(); - } + int step(); - inline Gcalc_heap::Info *more_points() { return m_cur_pi; } - inline bool more_trapezoids() + Gcalc_heap::Info *more_points() { return m_cur_pi; } + bool more_trapezoids() { return m_cur_pi && m_cur_pi->next; } - inline const point *get_events() const - { return m_events; } - inline const point *get_event_position() const - { return current_state->event_position; } - inline const point *get_event_end() const - { return (point *) *current_state->event_end_hook; } - inline const point *get_b_slice() const { return current_state->slice; } - inline const point *get_t_slice() const { return next_state->slice; } + const point *get_bottom_points() const + { return m_bottom_points; } + const point *get_event_position() const + { return *state.event_position_hook; } + const point *get_event_end() const + { return state.event_end; } + const event_point *get_events() const + { return (const event_point *) + (*state.event_position_hook == state.event_end ? + m_bottom_points : *state.event_position_hook); } + const point *get_b_slice() const { return state.slice; } double get_h() const; double get_y() const; double get_event_x() const; double get_sp_x(const point *sp) const; - int intersection_step() const { return current_state->intersection_scan; } + int intersection_step() const + { return state.pi->type == Gcalc_heap::nt_intersection; } const Gcalc_heap::Info *get_cur_pi() const { - DBUG_ASSERT(!intersection_step()); - return current_state->pi; - } - const Gcalc_heap::Intersection_info *get_cur_ii() const - { - DBUG_ASSERT(intersection_step()); - return current_state->isc; + return state.pi; } private: Gcalc_heap *m_heap; Gcalc_heap::Info *m_cur_pi; - slice_state state0, state1, state_s; - slice_state *current_state; - slice_state *next_state; - slice_state *saved_state; + slice_state state; - intersection *m_intersections; - int m_n_intersections; - intersection *m_cur_intersection; - bool m_next_is_top_point; - sc_thread_id m_cur_thread; +#ifndef GCALC_DBUG_OFF + unsigned int m_cur_thread; +#endif /*GCALC_DBUG_OFF*/ - point *m_events; - int normal_scan(); - int intersection_scan(); - void sort_intersections(); - int handle_intersections(); - int insert_top_point(); - int add_intersection(int n_row, const point *a, const point *b, - Gcalc_dyn_list::Item ***p_hook); - int find_intersections(); + point *m_bottom_points; + point **m_bottom_hook; + + int node_scan(); + void eq_scan(); + void intersection_scan(); + void remove_bottom_node(); + int insert_top_node(); + int add_intersection(point *sp_a, point *sp_b, + Gcalc_heap::Info *pi_from); + int add_eq_node(Gcalc_heap::Info *node, point *sp); + int add_events_for_node(point *sp_node); - intersection *new_intersection() - { - return (intersection *)new_item(); - } point *new_slice_point() { point *new_point= (point *)new_item(); @@ -512,9 +541,15 @@ private: new_point->dy.init(); return new_point; } - point *new_slice(point *example); - int arrange_event(); - void mark_event_position1(point *ep, Gcalc_dyn_list::Item **ep_hook); + intersection_info *new_intersection_info(point *a, point *b) + { + intersection_info *ii= (intersection_info *)new_item(); + ii->edge_a= a; + ii->edge_b= b; + ii->t_calculated= ii->x_calculated= ii->y_calculated= 0; + return ii; + } + int arrange_event(int do_sorting, int n_intersections); }; @@ -525,6 +560,7 @@ private: previous and current slices. */ +#ifdef TMP_BLOCK class Gcalc_trapezoid_iterator { protected: @@ -556,6 +592,7 @@ public: sp1= rt(); } }; +#endif /*TMP_BLOCK*/ /* diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index eabc42a6c51..f6203ba552f 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -192,7 +192,7 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type, result= result & !next_res; break; default: - DBUG_ASSERT(FALSE); + GCALC_DBUG_ASSERT(FALSE); }; } @@ -262,7 +262,8 @@ void Gcalc_function::reset() int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it) { - const Gcalc_scan_iterator::point *eq_start, *cur_eq, *events; + const Gcalc_scan_iterator::point *eq_start, *cur_eq; + const Gcalc_scan_iterator::event_point *events; GCALC_DBUG_ENTER("Gcalc_function::check_function"); while (scan_it.more_points()) @@ -502,7 +503,7 @@ int Gcalc_result_receiver::complete_shape() } else { - DBUG_ASSERT(cur_shape != Gcalc_function::shape_point); + GCALC_DBUG_ASSERT(cur_shape != Gcalc_function::shape_point); if (cur_shape == Gcalc_function::shape_hole) { shape_area+= prev_x*first_y - prev_y*first_x; @@ -534,7 +535,7 @@ do_complete: if (!n_shapes++) { - DBUG_ASSERT(cur_shape != Gcalc_function::shape_hole); + GCALC_DBUG_ASSERT(cur_shape != Gcalc_function::shape_hole); common_shapetype= cur_shape; } else if (cur_shape == Gcalc_function::shape_hole) @@ -587,7 +588,7 @@ int Gcalc_result_receiver::get_result_typeid() return (n_shapes == 1) ? Geometry::wkb_linestring : Geometry::wkb_multilinestring; default: - DBUG_ASSERT(0); + GCALC_DBUG_ASSERT(0); } return 0; } @@ -648,6 +649,7 @@ 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())) @@ -655,6 +657,12 @@ void Gcalc_operation_reducer::res_point::set(const Gcalc_scan_iterator *si) 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(); + pi= si->get_cur_pi(); +} Gcalc_operation_reducer::res_point * @@ -726,7 +734,7 @@ int Gcalc_operation_reducer::continue_range(active_thread *t, inline int Gcalc_operation_reducer::continue_i_range(active_thread *t, - const Gcalc_heap::Intersection_info *ii) + const Gcalc_heap::Info *ii) { res_point *rp= add_res_point(t->rp->type); GCALC_DBUG_ENTER("Gcalc_operation_reducer::continue_i_range"); @@ -736,7 +744,7 @@ inline int Gcalc_operation_reducer::continue_i_range(active_thread *t, rp->down= t->rp; t->rp->up= rp; rp->intersection_point= true; - rp->ii= ii; + rp->pi= ii; t->rp= rp; GCALC_DBUG_RETURN(0); } @@ -746,7 +754,7 @@ int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1, { res_point *rp0, *rp1; GCALC_DBUG_ENTER("Gcalc_operation_reducer::end_couple"); - DBUG_ASSERT(t0->rp->type == t1->rp->type); + GCALC_DBUG_ASSERT(t0->rp->type == t1->rp->type); if (!(rp0= add_res_point(t0->rp->type)) || !(rp1= add_res_point(t0->rp->type))) GCALC_DBUG_RETURN(1); @@ -769,7 +777,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) int prev_state= 0; int sav_prev_state; active_thread *prev_range= NULL; - const Gcalc_scan_iterator::point *events; + const Gcalc_scan_iterator::event_point *events; const Gcalc_scan_iterator::point *eq_start; active_thread **cur_t_hook= &m_first_active_thread; active_thread **starting_t_hook; @@ -834,7 +842,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) break; } default: - DBUG_ASSERT(0); + GCALC_DBUG_ASSERT(0); } GCALC_DBUG_RETURN(0); } @@ -875,7 +883,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { if (cur_t->rp->type == Gcalc_function::shape_line) { - DBUG_ASSERT(!prev_state); + GCALC_DBUG_ASSERT(!prev_state); add_line(1, cur_t, events); } else @@ -971,7 +979,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si) { poly_border *pb1, *pb2; pb1= m_poly_borders; - DBUG_ASSERT(m_poly_borders->next); + GCALC_DBUG_ASSERT(m_poly_borders->next); pb2= get_pair_border(pb1); /* Remove pb1 from the list. The pb2 already removed in get_pair_border. */ @@ -1098,7 +1106,7 @@ int Gcalc_operation_reducer::connect_threads( if (incoming_a && incoming_b) { res_point *rpa, *rpb; - DBUG_ASSERT(ta->rp->type == tb->rp->type); + GCALC_DBUG_ASSERT(ta->rp->type == tb->rp->type); if (!(rpa= add_res_point(ta->rp->type)) || !(rpb= add_res_point(ta->rp->type))) GCALC_DBUG_RETURN(1); @@ -1116,7 +1124,7 @@ int Gcalc_operation_reducer::connect_threads( } if (!incoming_a) { - DBUG_ASSERT(!incoming_b); + GCALC_DBUG_ASSERT(!incoming_b); res_point *rp0, *rp1; if (!(rp0= add_res_point(s_t)) || !(rp1= add_res_point(s_t))) @@ -1152,14 +1160,14 @@ int Gcalc_operation_reducer::connect_threads( } /* else, if only ta is incoming */ - DBUG_ASSERT(tb != ta); + GCALC_DBUG_ASSERT(tb != ta); tb->rp= ta->rp; tb->thread_start= ta->thread_start; if (Gcalc_scan_iterator::point:: cmp_dx_dy(ta->p1, ta->p2, pb->pi, pb->next_pi) != 0) { if (si->intersection_step() ? - continue_i_range(tb, si->get_cur_ii()) : + continue_i_range(tb, si->get_cur_pi()) : continue_range(tb, si->get_cur_pi(), pb->next_pi)) GCALC_DBUG_RETURN(1); } @@ -1191,7 +1199,7 @@ int Gcalc_operation_reducer::end_line(active_thread *t, const Gcalc_scan_iterator *si) { GCALC_DBUG_ENTER("Gcalc_operation_reducer::end_line"); - DBUG_ASSERT(t->rp->type == Gcalc_function::shape_line); + GCALC_DBUG_ASSERT(t->rp->type == Gcalc_function::shape_line); res_point *rp= add_res_point(Gcalc_function::shape_line); if (!rp) GCALC_DBUG_RETURN(1); @@ -1237,7 +1245,7 @@ inline int Gcalc_operation_reducer::get_single_result(res_point *res, if (res->intersection_point) { double x, y; - res->ii->calc_xy(&x, &y); + res->pi->calc_xy(&x, &y); if (storage->single_point(x,y)) GCALC_DBUG_RETURN(1); } @@ -1264,7 +1272,7 @@ int Gcalc_operation_reducer::get_result_thread(res_point *cur, { if (cur->intersection_point) { - cur->ii->calc_xy(&x, &y); + cur->pi->calc_xy(&x, &y); } else { @@ -1368,7 +1376,7 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage) uint32 insert_position, hole_position, position_shift; poly_instance *cur_poly; insert_position= m_result->outer_poly->first_poly_node->poly_position; - DBUG_ASSERT(insert_position); + GCALC_DBUG_ASSERT(insert_position); hole_position= storage->position(); storage->start_shape(Gcalc_function::shape_hole); if (get_polygon_result(m_result, storage, diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index ca740dcdc11..b89a9a45e07 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -233,7 +233,6 @@ public: union { const Gcalc_heap::Info *pi; - const Gcalc_heap::Intersection_info *ii; res_point *first_poly_node; }; union @@ -331,7 +330,7 @@ private: int continue_range(active_thread *t, const Gcalc_heap::Info *p, const Gcalc_heap::Info *p_next); int continue_i_range(active_thread *t, - const Gcalc_heap::Intersection_info *ii); + const Gcalc_heap::Info *ii); int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p); int get_single_result(res_point *res, Gcalc_result_receiver *storage); int get_result_thread(res_point *cur, Gcalc_result_receiver *storage, diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index dd6914e5d66..c62978f37e2 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1445,7 +1445,7 @@ longlong Item_func_issimple::val_int() Gcalc_operation_transporter trn(&func, &collector); Geometry *g; int result= 1; - const Gcalc_scan_iterator::point *ev; + const Gcalc_scan_iterator::event_point *ev; DBUG_ENTER("Item_func_issimple::val_int"); DBUG_ASSERT(fixed == 1); @@ -1669,7 +1669,7 @@ double Item_func_distance::val_real() bool above_cur_point, cur_point_edge; const Gcalc_scan_iterator::point *evpos; const Gcalc_heap::Info *cur_point, *dist_point; - const Gcalc_scan_iterator::point *ev; + const Gcalc_scan_iterator::event_point *ev; double t, distance, cur_distance; double x1, x2, y1, y2; double ex, ey, vx, vy, e_sqrlen; From c34a8ed827b3d1901c34d6f2fef21e6b77fe828e Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 14 Oct 2011 17:57:07 +0500 Subject: [PATCH 37/40] repeating calcualtions eliminated. --- sql/gcalc_slicescan.cc | 151 +++++++++++++++++++++++++++++++++++++---- sql/gcalc_slicescan.h | 3 + 2 files changed, 139 insertions(+), 15 deletions(-) diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 6e32baab8de..99a94cecc4f 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -634,6 +634,7 @@ class Gcalc_coord5 : public Gcalc_internal_coord }; +#ifdef TMP_BLOCK static void calc_isc_exp(Gcalc_coord5 *exp, const Gcalc_coord2 *bb2, const Gcalc_coord1 *ya1, @@ -701,27 +702,94 @@ static int cmp_intersections(const Gcalc_heap::Info *i1, #endif /*GCALC_CHECK_WITH_FLOAT*/ return result; } +#endif /*TMP_BLOCK*/ + + +void Gcalc_scan_iterator::intersection_info::calc_t() +{ + if (t_calculated) + return; + + Gcalc_coord1 a2_a1x, a2_a1y; + Gcalc_coord2 x1y2, x2y1; + t_a.init(); + t_b.init(); + + a2_a1x.init(); + a2_a1y.init(); + x1y2.init(); + x2y1.init(); + + gcalc_sub_coord(&a2_a1x, &edge_b->pi->ix, &edge_a->pi->ix); + gcalc_sub_coord(&a2_a1y, &edge_b->pi->iy, &edge_a->pi->iy); + + GCALC_DBUG_ASSERT(!edge_a->dy.is_zero() || !edge_b->dy.is_zero()); + + gcalc_mul_coord(&x1y2, &edge_a->dx, &edge_b->dy); + gcalc_mul_coord(&x2y1, &edge_a->dy, &edge_b->dx); + gcalc_sub_coord(&t_b, &x1y2, &x2y1); + + + gcalc_mul_coord(&x1y2, &a2_a1x, &edge_b->dy); + gcalc_mul_coord(&x2y1, &a2_a1y, &edge_b->dx); + gcalc_sub_coord(&t_a, &x1y2, &x2y1); + t_calculated= 1; +} + + +void Gcalc_scan_iterator::intersection_info::calc_y_exp() +{ + if (y_calculated) + return; + GCALC_DBUG_ASSERT(t_calculated); + + Gcalc_coord3 a_tb, b_ta; + + y_exp.init(); + a_tb.init(); + b_ta.init(); + gcalc_mul_coord(&a_tb, &t_b, &edge_a->pi->iy); + gcalc_mul_coord(&b_ta, &t_a, &edge_a->dy); + + gcalc_add_coord(&y_exp, &a_tb, &b_ta); + y_calculated= 1; +} + + +void Gcalc_scan_iterator::intersection_info::calc_x_exp() +{ + if (x_calculated) + return; + GCALC_DBUG_ASSERT(t_calculated); + + Gcalc_coord3 a_tb, b_ta; + + x_exp.init(); + a_tb.init(); + b_ta.init(); + gcalc_mul_coord(&a_tb, &t_b, &edge_a->pi->ix); + gcalc_mul_coord(&b_ta, &t_a, &edge_a->dx); + + gcalc_add_coord(&x_exp, &a_tb, &b_ta); + x_calculated= 1; +} static int cmp_node_isc(const Gcalc_heap::Info *node, const Gcalc_heap::Info *isc) { GCALC_DBUG_ASSERT(node->type == Gcalc_heap::nt_shape_node); - Gcalc_coord3 exp_a, exp_b; - Gcalc_coord1 xb1, yb1, d0; - Gcalc_coord2 t_a, t_b; + Gcalc_scan_iterator::intersection_info *inf= i_data(isc); + Gcalc_coord3 exp; int result; - exp_a.init(); - exp_b.init(); - d0.init(); + exp.init(); - calc_t(&t_a, &t_b, &xb1, &yb1, isc); + inf->calc_t(); + inf->calc_y_exp(); - gcalc_sub_coord(&d0, &node->iy, &isc->p1->iy); - gcalc_mul_coord(&exp_a, &d0, &t_b); - gcalc_mul_coord(&exp_b, &yb1, &t_a); + gcalc_mul_coord(&exp, &node->iy, &inf->t_b); - result= gcalc_cmp_coord(&exp_a, &exp_b); + result= gcalc_cmp_coord(&exp, &inf->y_exp); #ifdef GCALC_CHECK_WITH_FLOAT long double int_x, int_y; isc->calc_xy_ld(&int_x, &int_y); @@ -735,11 +803,11 @@ static int cmp_node_isc(const Gcalc_heap::Info *node, if (result) goto exit; - gcalc_sub_coord(&d0, &node->ix, &isc->p1->ix); - gcalc_mul_coord(&exp_a, &d0, &t_b); - gcalc_mul_coord(&exp_b, &xb1, &t_a); - result= gcalc_cmp_coord(&exp_a, &exp_b); + inf->calc_x_exp(); + gcalc_mul_coord(&exp, &node->ix, &inf->t_b); + + result= gcalc_cmp_coord(&exp, &inf->x_exp); #ifdef GCALC_CHECK_WITH_FLOAT if (result < 0) GCALC_DBUG_ASSERT(de_check(int_x, node->x) || node->x < int_x); @@ -753,6 +821,59 @@ exit: } +static int cmp_intersections(const Gcalc_heap::Info *i1, + const Gcalc_heap::Info *i2) +{ + Gcalc_scan_iterator::intersection_info *inf1= i_data(i1); + Gcalc_scan_iterator::intersection_info *inf2= i_data(i2); + Gcalc_coord5 exp_a, exp_b; + int result; + + inf1->calc_t(); + inf2->calc_t(); + + inf1->calc_y_exp(); + inf2->calc_y_exp(); + + exp_a.init(); + exp_b.init(); + gcalc_mul_coord(&exp_a, &inf1->y_exp, &inf2->t_b); + gcalc_mul_coord(&exp_b, &inf2->y_exp, &inf1->t_b); + + result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + long double x1, y1, x2, y2; + i1->calc_xy_ld(&x1, &y1); + i2->calc_xy_ld(&x2, &y2); + + if (result == 0) + GCALC_DBUG_ASSERT(de_check(y1, y2)); + if (result < 0) + GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 < y2); + if (result > 0) + GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 > y2); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + + if (result != 0) + return result; + + + inf1->calc_x_exp(); + inf2->calc_x_exp(); + gcalc_mul_coord(&exp_a, &inf1->x_exp, &inf2->t_b); + gcalc_mul_coord(&exp_b, &inf2->x_exp, &inf1->t_b); + + result= gcalc_cmp_coord(&exp_a, &exp_b); +#ifdef GCALC_CHECK_WITH_FLOAT + if (result == 0) + GCALC_DBUG_ASSERT(de_check(x1, x2)); + if (result < 0) + GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 < x2); + if (result > 0) + GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 > x2); +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result; +} /* Internal coordinates implementation end */ diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index 3655b11bc15..e5323952afe 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -467,6 +467,9 @@ public: int x_calculated; Gcalc_coord3 y_exp; int y_calculated; + void calc_t(); + void calc_y_exp(); + void calc_x_exp(); }; From 486df97986d839b7ad24a6c36ad6ca43875312e6 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 14 Oct 2011 18:37:40 +0500 Subject: [PATCH 38/40] #define added --- sql/gcalc_slicescan.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 99a94cecc4f..0a7bbde16d1 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -557,6 +557,7 @@ void Gcalc_coord1::copy(const Gcalc_coord1 *from) } +#ifdef GCALC_CHECK_WITH_FLOAT static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, Gcalc_coord1 *b1x, Gcalc_coord1 *b1y, @@ -608,6 +609,7 @@ static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, GCALC_DBUG_ASSERT(i->type == Gcalc_heap::nt_intersection); calc_t(t_a, t_b, b1x, b1y, i->p1, i->p2, i->p3, i->p4); } +#endif /*GCALC_CHECK_WITH_FLOAT*/ class Gcalc_coord4 : public Gcalc_internal_coord From 248f2da679281c2b35a1719d830b6f0db4d791ac Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 16 Oct 2011 19:55:37 +0500 Subject: [PATCH 39/40] GIS code cleanup. --- sql/gcalc_slicescan.cc | 842 +++++++++++++++++++++-------------------- sql/gcalc_slicescan.h | 102 ++--- 2 files changed, 459 insertions(+), 485 deletions(-) diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 0a7bbde16d1..03c77163f49 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -40,6 +40,10 @@ typedef int (*sc_compare_func)(const void*, const void*); #include "plistsort.c" +#define GCALC_COORD_MINUS 0x80000000 +#define FIRST_DIGIT(d) ((d) & 0x7FFFFFFF) +#define GCALC_SIGN(d) ((d) & 0x80000000) + static Gcalc_scan_iterator::point *eq_sp(const Gcalc_heap::Info *pi) { GCALC_DBUG_ASSERT(pi->type == Gcalc_heap::nt_eq_node); @@ -97,8 +101,8 @@ const char *gcalc_ev_name(int ev) static int gcalc_pi_str(char *str, const Gcalc_heap::Info *pi, const char *postfix) { return sprintf(str, "%s %d %d | %s %d %d%s", - pi->ix.sign ? "-":"", pi->ix.digits[0],pi->ix.digits[1], - pi->iy.sign ? "-":"", pi->iy.digits[0],pi->iy.digits[1], + GCALC_SIGN(pi->ix[0]) ? "-":"", FIRST_DIGIT(pi->ix[0]),pi->ix[1], + GCALC_SIGN(pi->iy[0]) ? "-":"", FIRST_DIGIT(pi->iy[0]),pi->iy[1], postfix); } @@ -274,264 +278,327 @@ void Gcalc_dyn_list::reset() /* Internal coordinate operations implementations */ -void Gcalc_internal_coord::set_zero() +void gcalc_set_zero(Gcalc_internal_coord *d, int d_len) { - int n_res= 0; do { - digits[n_res++]= 0; - } while (n_res < n_digits); - sign= 0; + d[--d_len]= 0; + } while (d_len); } -int Gcalc_internal_coord::is_zero() const +int gcalc_is_zero(const Gcalc_internal_coord *d, int d_len) { - int n_res= 0; do { - if (digits[n_res++] != 0) + if (d[--d_len] != 0) return 0; - } while (n_res < n_digits); + } while (d_len); return 1; } #ifdef GCALC_CHECK_WITH_FLOAT -double *Gcalc_internal_coord::coord_extent= NULL; +static double *gcalc_coord_extent= NULL; -long double Gcalc_internal_coord::get_double() const +long double gcalc_get_double(const Gcalc_internal_coord *d, int d_len) { int n= 1; - long double res= (long double) digits[0]; + long double res= (long double) FIRST_DIGIT(d[0]); do { res*= (long double) GCALC_DIG_BASE; - res+= (long double) digits[n]; - } while(++n < n_digits); + res+= (long double) d[n]; + } while(++n < d_len); n= 0; do { - if ((n & 1) && coord_extent) - res/= *coord_extent; - } while(++n < n_digits); + if ((n & 1) && gcalc_coord_extent) + res/= *gcalc_coord_extent; + } while(++n < d_len); - if (sign) + if (GCALC_SIGN(d[0])) res*= -1.0; return res; } #endif /*GCALC_CHECK_WITH_FLOAT*/ -static void do_add(Gcalc_internal_coord *result, +static void do_add(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b) { - GCALC_DBUG_ASSERT(a->n_digits == b->n_digits); - GCALC_DBUG_ASSERT(a->n_digits == result->n_digits); - int n_digit= a->n_digits-1; + int n_digit= result_len-1; gcalc_digit_t carry= 0; do { - if ((result->digits[n_digit]= - a->digits[n_digit] + b->digits[n_digit] + carry) >= GCALC_DIG_BASE) + if ((result[n_digit]= + a[n_digit] + b[n_digit] + carry) >= GCALC_DIG_BASE) { carry= 1; - result->digits[n_digit]-= GCALC_DIG_BASE; + result[n_digit]-= GCALC_DIG_BASE; } else carry= 0; } while (--n_digit); - result->digits[0]= a->digits[0] + b->digits[0] + carry; - GCALC_DBUG_ASSERT(result->digits[0] < GCALC_DIG_BASE); - result->sign= a->sign; + + result[0]= (a[0] + FIRST_DIGIT(b[0]) + carry); + + GCALC_DBUG_ASSERT(FIRST_DIGIT(result[0]) < GCALC_DIG_BASE); } -static void do_sub(Gcalc_internal_coord *result, +static void do_sub(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b) { - GCALC_DBUG_ASSERT(a->n_digits == b->n_digits); - GCALC_DBUG_ASSERT(a->n_digits == result->n_digits); - int n_digit= a->n_digits-1; + int n_digit= result_len-1; + gcalc_digit_t carry= 0; + gcalc_digit_t cur_b, cur_a; + + do + { + cur_b= b[n_digit] + carry; + cur_a= a[n_digit]; + if (cur_a < cur_b) + { + carry= 1; + result[n_digit]= (GCALC_DIG_BASE - cur_b) + cur_a; + } + else + { + carry= 0; + result[n_digit]= cur_a - cur_b; + } + } while (--n_digit); + + + result[0]= a[0] - FIRST_DIGIT(b[0]) - carry; + + GCALC_DBUG_ASSERT(FIRST_DIGIT(a[0]) >= FIRST_DIGIT(b[0]) + carry); + GCALC_DBUG_ASSERT(!gcalc_is_zero(result, result_len)); +} +/* +static void do_sub(Gcalc_internal_coord *result, int result_len, + const Gcalc_internal_coord *a, + const Gcalc_internal_coord *b) +{ + int n_digit= result_len-1; gcalc_digit_t carry= 0; do { - if ((result->digits[n_digit]= - a->digits[n_digit] - b->digits[n_digit] - carry) < 0) + if ((result[n_digit]= a[n_digit] - b[n_digit] - carry) < 0) { carry= 1; - result->digits[n_digit]+= GCALC_DIG_BASE; + result[n_digit]+= GCALC_DIG_BASE; } else carry= 0; - } while (n_digit--); - GCALC_DBUG_ASSERT(carry == 0); - if (a->sign && result->is_zero()) - result->sign= 0; - else - result->sign= a->sign; -} + } while (--n_digit); + result[0]= a[0] - FIRST_DIGIT(b[0]) - carry; + + GCALC_DBUG_ASSERT(FIRST_DIGIT(a[0]) - FIRST_DIGIT(b[0]) - carry >= 0); + GCALC_DBUG_ASSERT(!gcalc_is_zero(result, result_len)); +} +*/ + static int do_cmp(const Gcalc_internal_coord *a, - const Gcalc_internal_coord *b) + const Gcalc_internal_coord *b, int len) { - GCALC_DBUG_ASSERT(a->n_digits == b->n_digits); - int n_digit= 0; + int n_digit= 1; + + if ((FIRST_DIGIT(a[0]) != FIRST_DIGIT(b[0]))) + return FIRST_DIGIT(a[0]) > FIRST_DIGIT(b[0]) ? 1 : -1; do { - gcalc_digit_t d= a->digits[n_digit] - b->digits[n_digit]; - if (d > 0) - return 1; - if (d < 0) - return -1; - n_digit++; - } while (n_digit < a->n_digits); + if ((a[n_digit] != b[n_digit])) + return a[n_digit] > b[n_digit] ? 1 : -1; + } while (++n_digit < len); return 0; } #ifdef GCALC_CHECK_WITH_FLOAT -static int de_check(long double a, long double b) +static int de_weak_check(long double a, long double b, long double ex) { long double d= a - b; - if (d < (long double) 1e-10 && d > (long double) -1e-10) + if (d < ex && d > -ex) return 1; d/= fabsl(a) + fabsl(b); - if (d < (long double) 1e-10 && d > (long double) -1e-10) + if (d < ex && d > -ex) return 1; return 0; } + +static int de_check(long double a, long double b) +{ + return de_weak_check(a, b, (long double) 1e-10); +} #endif /*GCALC_CHECK_WITH_FLOAT*/ -void gcalc_mul_coord(Gcalc_internal_coord *result, - const Gcalc_internal_coord *a, - const Gcalc_internal_coord *b) +void gcalc_mul_coord(Gcalc_internal_coord *result, int result_len, + const Gcalc_internal_coord *a, int a_len, + const Gcalc_internal_coord *b, int b_len) { - GCALC_DBUG_ASSERT(result->n_digits == a->n_digits + b->n_digits); + GCALC_DBUG_ASSERT(result_len == a_len + b_len); + GCALC_DBUG_ASSERT(a_len >= b_len); int n_a, n_b, n_res; gcalc_digit_t carry= 0; - result->set_zero(); - if (a->is_zero() || b->is_zero()) - return; + gcalc_set_zero(result, result_len); - n_a= a->n_digits - 1; + n_a= a_len - 1; do { - n_b= b->n_digits - 1; + gcalc_coord2 cur_a= n_a ? a[n_a] : FIRST_DIGIT(a[0]); + n_b= b_len - 1; do { - gcalc_coord2 mul= ((gcalc_coord2) a->digits[n_a]) * b->digits[n_b] + - carry + result->digits[n_a + n_b + 1]; - result->digits[n_a + n_b + 1]= mul % GCALC_DIG_BASE; + gcalc_coord2 cur_b= n_b ? b[n_b] : FIRST_DIGIT(b[0]); + gcalc_coord2 mul= cur_a * cur_b + carry + result[n_a + n_b + 1]; + result[n_a + n_b + 1]= mul % GCALC_DIG_BASE; carry= mul / GCALC_DIG_BASE; } while (n_b--); if (carry) { - for (n_res= n_a; (result->digits[n_res]+= carry) >= GCALC_DIG_BASE; + for (n_res= n_a; (result[n_res]+= carry) >= GCALC_DIG_BASE; n_res--) { - result->digits[n_res]-= GCALC_DIG_BASE; + result[n_res]-= GCALC_DIG_BASE; carry= 1; } carry= 0; } } while (n_a--); - result->sign= a->sign != b->sign; + if (!gcalc_is_zero(result, result_len)) + result[0]|= GCALC_SIGN(a[0] ^ b[0]); #ifdef GCALC_CHECK_WITH_FLOAT - GCALC_DBUG_ASSERT(de_check(a->get_double() * b->get_double(), - result->get_double())); + GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, a_len) * + gcalc_get_double(b, b_len), + gcalc_get_double(result, result_len))); #endif /*GCALC_CHECK_WITH_FLOAT*/ } -void gcalc_add_coord(Gcalc_internal_coord *result, +inline void gcalc_mul_coord1(Gcalc_coord1 result, + const Gcalc_coord1 a, const Gcalc_coord1 b) +{ + return gcalc_mul_coord(result, GCALC_COORD_BASE2, + a, GCALC_COORD_BASE, b, GCALC_COORD_BASE); +} + + +void gcalc_add_coord(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b) { - if (a->sign == b->sign) - do_add(result, a, b); + if (GCALC_SIGN(a[0]) == GCALC_SIGN(b[0])) + do_add(result, result_len, a, b); else { - int cmp_res= do_cmp(a, b); + int cmp_res= do_cmp(a, b, result_len); if (cmp_res == 0) - result->set_zero(); + gcalc_set_zero(result, result_len); else if (cmp_res > 0) - do_sub(result, a, b); + do_sub(result, result_len, a, b); else - do_sub(result, b, a); + do_sub(result, result_len, b, a); } #ifdef GCALC_CHECK_WITH_FLOAT - GCALC_DBUG_ASSERT(de_check(a->get_double() + b->get_double(), - result->get_double())); + GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, result_len) + + gcalc_get_double(b, result_len), + gcalc_get_double(result, result_len))); #endif /*GCALC_CHECK_WITH_FLOAT*/ } -void gcalc_sub_coord(Gcalc_internal_coord *result, +void gcalc_sub_coord(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b) { - if (a->sign != b->sign) - do_add(result, a, b); + if (GCALC_SIGN(a[0] ^ b[0])) + do_add(result, result_len, a, b); else { - int cmp_res= do_cmp(a, b); + int cmp_res= do_cmp(a, b, result_len); if (cmp_res == 0) - result->set_zero(); + gcalc_set_zero(result, result_len); else if (cmp_res > 0) - do_sub(result, a, b); + do_sub(result, result_len, a, b); else { - do_sub(result, b, a); - result->sign= 1 - result->sign; + do_sub(result, result_len, b, a); + result[0]^= GCALC_COORD_MINUS; } } #ifdef GCALC_CHECK_WITH_FLOAT - GCALC_DBUG_ASSERT(de_check(a->get_double() - b->get_double(), - result->get_double())); + GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, result_len) - + gcalc_get_double(b, result_len), + gcalc_get_double(result, result_len))); #endif /*GCALC_CHECK_WITH_FLOAT*/ } +inline void gcalc_sub_coord1(Gcalc_coord1 result, + const Gcalc_coord1 a, const Gcalc_coord1 b) +{ + return gcalc_sub_coord(result, GCALC_COORD_BASE, a, b); +} + + int gcalc_cmp_coord(const Gcalc_internal_coord *a, - const Gcalc_internal_coord *b) + const Gcalc_internal_coord *b, int len) { - int result; - if (a->sign != b->sign) - return a->sign ? -1 : 1; - result= a->sign ? do_cmp(b, a) : do_cmp(a, b); + int n_digit= 0; + int result= 0; + + do + { + if (a[n_digit] == b[n_digit]) + { + n_digit++; + continue; + } + if (a[n_digit] > b[n_digit]) + result= GCALC_SIGN(a[0]) ? -1 : 1; + else + result= GCALC_SIGN(b[0]) ? 1 : -1; + break; + + } while (n_digit < len); + #ifdef GCALC_CHECK_WITH_FLOAT if (result == 0) - GCALC_DBUG_ASSERT(de_check(a->get_double(), b->get_double())); + GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, len), + gcalc_get_double(b, len))); else if (result == 1) - GCALC_DBUG_ASSERT(de_check(a->get_double(), b->get_double()) || - a->get_double() > b->get_double()); + GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, len), + gcalc_get_double(b, len)) || + gcalc_get_double(a, len) > gcalc_get_double(b, len)); else - GCALC_DBUG_ASSERT(de_check(a->get_double(), b->get_double()) || - a->get_double() < b->get_double()); + GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, len), + gcalc_get_double(b, len)) || + gcalc_get_double(a, len) < gcalc_get_double(b, len)); #endif /*GCALC_CHECK_WITH_FLOAT*/ return result; } -#define gcalc_cmp_coord1(a, b) gcalc_cmp_coord(a, b) +#define gcalc_cmp_coord1(a, b) gcalc_cmp_coord(a, b, GCALC_COORD_BASE) - -int Gcalc_coord1::set_double(double d, double ext) +int gcalc_set_double(Gcalc_internal_coord *c, double d, double ext) { + int sign; double ds= d * ext; - init(); if ((sign= ds < 0)) ds= -ds; c[0]= (gcalc_digit_t) (ds / (double) GCALC_DIG_BASE); @@ -542,237 +609,70 @@ int Gcalc_coord1::set_double(double d, double ext) c[1]= 0; c[0]++; } + if (sign) + c[0]|= GCALC_COORD_MINUS; #ifdef GCALC_CHECK_WITH_FLOAT - GCALC_DBUG_ASSERT(de_check(d, get_double())); + GCALC_DBUG_ASSERT(de_check(d, gcalc_get_double(c, 2))); #endif /*GCALC_CHECK_WITH_FLOAT*/ return 0; } -void Gcalc_coord1::copy(const Gcalc_coord1 *from) -{ - c[0]= from->c[0]; - c[1]= from->c[1]; - sign= from->sign; -} +typedef gcalc_digit_t Gcalc_coord4[GCALC_COORD_BASE*4]; +typedef gcalc_digit_t Gcalc_coord5[GCALC_COORD_BASE*5]; -#ifdef GCALC_CHECK_WITH_FLOAT -static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, - Gcalc_coord1 *b1x, - Gcalc_coord1 *b1y, - const Gcalc_heap::Info *p1, - const Gcalc_heap::Info *p2, - const Gcalc_heap::Info *p3, - const Gcalc_heap::Info *p4) +void Gcalc_scan_iterator::intersection_info::do_calc_t() { Gcalc_coord1 a2_a1x, a2_a1y; - Gcalc_coord1 b2x, b2y; Gcalc_coord2 x1y2, x2y1; - a2_a1x.init(); - a2_a1y.init(); - x1y2.init(); - x2y1.init(); - t_a->init(); - t_b->init(); - b1y->init(); - b1x->init(); - b2x.init(); - b2y.init(); + gcalc_sub_coord1(a2_a1x, edge_b->pi->ix, edge_a->pi->ix); + gcalc_sub_coord1(a2_a1y, edge_b->pi->iy, edge_a->pi->iy); - gcalc_sub_coord(&a2_a1x, &p3->ix, &p1->ix); - gcalc_sub_coord(&a2_a1y, &p3->iy, &p1->iy); - gcalc_sub_coord(b1x, &p2->ix, &p1->ix); - gcalc_sub_coord(b1y, &p2->iy, &p1->iy); - gcalc_sub_coord(&b2x, &p4->ix, &p3->ix); - gcalc_sub_coord(&b2y, &p4->iy, &p3->iy); + GCALC_DBUG_ASSERT(!gcalc_is_zero(edge_a->dy, GCALC_COORD_BASE) || + !gcalc_is_zero(edge_b->dy, GCALC_COORD_BASE)); - GCALC_DBUG_ASSERT(!b1y->is_zero() || !b2y.is_zero()); - - gcalc_mul_coord(&x1y2, b1x, &b2y); - gcalc_mul_coord(&x2y1, &b2x, b1y); - gcalc_sub_coord(t_b, &x1y2, &x2y1); + gcalc_mul_coord1(x1y2, edge_a->dx, edge_b->dy); + gcalc_mul_coord1(x2y1, edge_a->dy, edge_b->dx); + gcalc_sub_coord(t_b, GCALC_COORD_BASE2, x1y2, x2y1); - gcalc_mul_coord(&x1y2, &a2_a1x, &b2y); - gcalc_mul_coord(&x2y1, &a2_a1y, &b2x); - gcalc_sub_coord(t_a, &x1y2, &x2y1); -} - - -static void calc_t(Gcalc_coord2 *t_a, Gcalc_coord2 *t_b, - Gcalc_coord1 *b1x, - Gcalc_coord1 *b1y, - const Gcalc_heap::Info *i) -{ - GCALC_DBUG_ASSERT(i->type == Gcalc_heap::nt_intersection); - calc_t(t_a, t_b, b1x, b1y, i->p1, i->p2, i->p3, i->p4); -} -#endif /*GCALC_CHECK_WITH_FLOAT*/ - - -class Gcalc_coord4 : public Gcalc_internal_coord -{ - gcalc_digit_t c[GCALC_COORD_BASE*4]; - public: - void init() - { - n_digits= GCALC_COORD_BASE*4; - digits= c; - } -}; - - -class Gcalc_coord5 : public Gcalc_internal_coord -{ - gcalc_digit_t c[GCALC_COORD_BASE*5]; - public: - void init() - { - n_digits= GCALC_COORD_BASE*5; - digits= c; - } -}; - - -#ifdef TMP_BLOCK -static void calc_isc_exp(Gcalc_coord5 *exp, - const Gcalc_coord2 *bb2, - const Gcalc_coord1 *ya1, - const Gcalc_coord2 *bb1, - const Gcalc_coord1 *yb1, - const Gcalc_coord2 *a21_b1) -{ - Gcalc_coord3 p1, p2, sum; - p1.init(); - p2.init(); - sum.init(); - exp->init(); - - gcalc_mul_coord(&p1, ya1, bb1); - gcalc_mul_coord(&p2, yb1, a21_b1); - gcalc_add_coord(&sum, &p1, &p2); - gcalc_mul_coord(exp, bb2, &sum); -} - - -static int cmp_intersections(const Gcalc_heap::Info *i1, - const Gcalc_heap::Info *i2) -{ - Gcalc_coord2 t_a1, t_b1; - Gcalc_coord2 t_a2, t_b2; - Gcalc_coord1 yb1, yb2; - Gcalc_coord1 xb1, xb2; - Gcalc_coord5 exp_a, exp_b; - int result; - - calc_t(&t_a1, &t_b1, &xb1, &yb1, i1); - calc_t(&t_a2, &t_b2, &xb2, &yb2, i2); - - calc_isc_exp(&exp_a, &t_b2, &i1->p1->iy, &t_b1, &yb1, &t_a1); - calc_isc_exp(&exp_b, &t_b1, &i2->p1->iy, &t_b2, &yb2, &t_a2); - - result= gcalc_cmp_coord(&exp_a, &exp_b); -#ifdef GCALC_CHECK_WITH_FLOAT - long double x1, y1, x2, y2; - i1->calc_xy_ld(&x1, &y1); - i2->calc_xy_ld(&x2, &y2); - - if (result == 0) - GCALC_DBUG_ASSERT(de_check(y1, y2)); - if (result < 0) - GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 < y2); - if (result > 0) - GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 > y2); -#endif /*GCALC_CHECK_WITH_FLOAT*/ - - if (result != 0) - return result; - - - calc_isc_exp(&exp_a, &t_b2, &i1->p1->ix, &t_b1, &xb1, &t_a1); - calc_isc_exp(&exp_b, &t_b1, &i2->p1->ix, &t_b2, &xb2, &t_a2); - result= gcalc_cmp_coord(&exp_a, &exp_b); -#ifdef GCALC_CHECK_WITH_FLOAT - if (result == 0) - GCALC_DBUG_ASSERT(de_check(x1, x2)); - if (result < 0) - GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 < x2); - if (result > 0) - GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 > x2); -#endif /*GCALC_CHECK_WITH_FLOAT*/ - return result; -} -#endif /*TMP_BLOCK*/ - - -void Gcalc_scan_iterator::intersection_info::calc_t() -{ - if (t_calculated) - return; - - Gcalc_coord1 a2_a1x, a2_a1y; - Gcalc_coord2 x1y2, x2y1; - t_a.init(); - t_b.init(); - - a2_a1x.init(); - a2_a1y.init(); - x1y2.init(); - x2y1.init(); - - gcalc_sub_coord(&a2_a1x, &edge_b->pi->ix, &edge_a->pi->ix); - gcalc_sub_coord(&a2_a1y, &edge_b->pi->iy, &edge_a->pi->iy); - - GCALC_DBUG_ASSERT(!edge_a->dy.is_zero() || !edge_b->dy.is_zero()); - - gcalc_mul_coord(&x1y2, &edge_a->dx, &edge_b->dy); - gcalc_mul_coord(&x2y1, &edge_a->dy, &edge_b->dx); - gcalc_sub_coord(&t_b, &x1y2, &x2y1); - - - gcalc_mul_coord(&x1y2, &a2_a1x, &edge_b->dy); - gcalc_mul_coord(&x2y1, &a2_a1y, &edge_b->dx); - gcalc_sub_coord(&t_a, &x1y2, &x2y1); + gcalc_mul_coord1(x1y2, a2_a1x, edge_b->dy); + gcalc_mul_coord1(x2y1, a2_a1y, edge_b->dx); + gcalc_sub_coord(t_a, GCALC_COORD_BASE2, x1y2, x2y1); t_calculated= 1; } -void Gcalc_scan_iterator::intersection_info::calc_y_exp() +void Gcalc_scan_iterator::intersection_info::do_calc_y() { - if (y_calculated) - return; GCALC_DBUG_ASSERT(t_calculated); Gcalc_coord3 a_tb, b_ta; - y_exp.init(); - a_tb.init(); - b_ta.init(); - gcalc_mul_coord(&a_tb, &t_b, &edge_a->pi->iy); - gcalc_mul_coord(&b_ta, &t_a, &edge_a->dy); + gcalc_mul_coord(a_tb, GCALC_COORD_BASE3, + t_b, GCALC_COORD_BASE2, edge_a->pi->iy, GCALC_COORD_BASE); + gcalc_mul_coord(b_ta, GCALC_COORD_BASE3, + t_a, GCALC_COORD_BASE2, edge_a->dy, GCALC_COORD_BASE); - gcalc_add_coord(&y_exp, &a_tb, &b_ta); + gcalc_add_coord(y_exp, GCALC_COORD_BASE3, a_tb, b_ta); y_calculated= 1; } -void Gcalc_scan_iterator::intersection_info::calc_x_exp() +void Gcalc_scan_iterator::intersection_info::do_calc_x() { - if (x_calculated) - return; GCALC_DBUG_ASSERT(t_calculated); Gcalc_coord3 a_tb, b_ta; - x_exp.init(); - a_tb.init(); - b_ta.init(); - gcalc_mul_coord(&a_tb, &t_b, &edge_a->pi->ix); - gcalc_mul_coord(&b_ta, &t_a, &edge_a->dx); + gcalc_mul_coord(a_tb, GCALC_COORD_BASE3, + t_b, GCALC_COORD_BASE2, edge_a->pi->ix, GCALC_COORD_BASE); + gcalc_mul_coord(b_ta, GCALC_COORD_BASE3, + t_a, GCALC_COORD_BASE2, edge_a->dx, GCALC_COORD_BASE); - gcalc_add_coord(&x_exp, &a_tb, &b_ta); + gcalc_add_coord(x_exp, GCALC_COORD_BASE3, a_tb, b_ta); x_calculated= 1; } @@ -784,39 +684,61 @@ static int cmp_node_isc(const Gcalc_heap::Info *node, Gcalc_scan_iterator::intersection_info *inf= i_data(isc); Gcalc_coord3 exp; int result; - exp.init(); inf->calc_t(); inf->calc_y_exp(); - gcalc_mul_coord(&exp, &node->iy, &inf->t_b); + gcalc_mul_coord(exp, GCALC_COORD_BASE3, + inf->t_b, GCALC_COORD_BASE2, node->iy, GCALC_COORD_BASE); - result= gcalc_cmp_coord(&exp, &inf->y_exp); + result= gcalc_cmp_coord(exp, inf->y_exp, GCALC_COORD_BASE3); #ifdef GCALC_CHECK_WITH_FLOAT long double int_x, int_y; isc->calc_xy_ld(&int_x, &int_y); if (result < 0) - GCALC_DBUG_ASSERT(de_check(int_y, node->y) || node->y < int_y); + { + if (!de_check(int_y, node->y) && node->y > int_y) + GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g < %LG", node->y, int_y)); + } else if (result > 0) - GCALC_DBUG_ASSERT(de_check(int_y, node->y) || node->y > int_y); + { + if (!de_check(int_y, node->y) && node->y < int_y) + GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g > %LG", node->y, int_y)); + } else - GCALC_DBUG_ASSERT(de_check(int_y, node->y)); + { + if (!de_check(int_y, node->y)) + GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g == %LG", node->y, int_y)); + } #endif /*GCALC_CHECK_WITH_FLOAT*/ if (result) goto exit; inf->calc_x_exp(); - gcalc_mul_coord(&exp, &node->ix, &inf->t_b); + gcalc_mul_coord(exp, GCALC_COORD_BASE3, + inf->t_b, GCALC_COORD_BASE2, node->ix, GCALC_COORD_BASE); - result= gcalc_cmp_coord(&exp, &inf->x_exp); + result= gcalc_cmp_coord(exp, inf->x_exp, GCALC_COORD_BASE3); #ifdef GCALC_CHECK_WITH_FLOAT if (result < 0) - GCALC_DBUG_ASSERT(de_check(int_x, node->x) || node->x < int_x); + { + if (!de_check(int_x, node->x) && node->x > int_x) + GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g < %LG", + node->x, int_x)); + } else if (result > 0) - GCALC_DBUG_ASSERT(de_check(int_x, node->x) || node->x > int_x); + { + if (!de_check(int_x, node->x) && node->x < int_x) + GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g > %LG", + node->x, int_x)); + } else - GCALC_DBUG_ASSERT(de_check(int_x, node->x)); + { + if (!de_check(int_x, node->x)) + GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g == %LG", + node->x, int_x)); + } #endif /*GCALC_CHECK_WITH_FLOAT*/ exit: return result; @@ -837,23 +759,35 @@ static int cmp_intersections(const Gcalc_heap::Info *i1, inf1->calc_y_exp(); inf2->calc_y_exp(); - exp_a.init(); - exp_b.init(); - gcalc_mul_coord(&exp_a, &inf1->y_exp, &inf2->t_b); - gcalc_mul_coord(&exp_b, &inf2->y_exp, &inf1->t_b); + gcalc_mul_coord(exp_a, GCALC_COORD_BASE5, + inf1->y_exp, GCALC_COORD_BASE3, inf2->t_b, GCALC_COORD_BASE2); + gcalc_mul_coord(exp_b, GCALC_COORD_BASE5, + inf2->y_exp, GCALC_COORD_BASE3, inf1->t_b, GCALC_COORD_BASE2); - result= gcalc_cmp_coord(&exp_a, &exp_b); + result= gcalc_cmp_coord(exp_a, exp_b, GCALC_COORD_BASE5); #ifdef GCALC_CHECK_WITH_FLOAT long double x1, y1, x2, y2; i1->calc_xy_ld(&x1, &y1); i2->calc_xy_ld(&x2, &y2); - if (result == 0) - GCALC_DBUG_ASSERT(de_check(y1, y2)); if (result < 0) - GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 < y2); - if (result > 0) - GCALC_DBUG_ASSERT(de_check(y1, y2) || y1 > y2); + { + if (!de_check(y1, y2) && y2 > y1) + GCALC_DBUG_PRINT(("floatcheck cmp_intersections_y failed %LG < %LG", + y2, y1)); + } + else if (result > 0) + { + if (!de_check(y1, y2) && y2 < y1) + GCALC_DBUG_PRINT(("floatcheck cmp_intersections_y failed %LG > %LG", + y2, y1)); + } + else + { + if (!de_check(y1, y2)) + GCALC_DBUG_PRINT(("floatcheck cmp_intersections_y failed %LG == %LG", + y2, y1)); + } #endif /*GCALC_CHECK_WITH_FLOAT*/ if (result != 0) @@ -862,17 +796,31 @@ static int cmp_intersections(const Gcalc_heap::Info *i1, inf1->calc_x_exp(); inf2->calc_x_exp(); - gcalc_mul_coord(&exp_a, &inf1->x_exp, &inf2->t_b); - gcalc_mul_coord(&exp_b, &inf2->x_exp, &inf1->t_b); + gcalc_mul_coord(exp_a, GCALC_COORD_BASE5, + inf1->x_exp, GCALC_COORD_BASE3, inf2->t_b, GCALC_COORD_BASE2); + gcalc_mul_coord(exp_b, GCALC_COORD_BASE5, + inf2->x_exp, GCALC_COORD_BASE3, inf1->t_b, GCALC_COORD_BASE2); - result= gcalc_cmp_coord(&exp_a, &exp_b); + result= gcalc_cmp_coord(exp_a, exp_b, GCALC_COORD_BASE5); #ifdef GCALC_CHECK_WITH_FLOAT - if (result == 0) - GCALC_DBUG_ASSERT(de_check(x1, x2)); if (result < 0) - GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 < x2); - if (result > 0) - GCALC_DBUG_ASSERT(de_check(x1, x2) || x1 > x2); + { + if (!de_check(x1, x2) && x2 > x1) + GCALC_DBUG_PRINT(("floatcheck cmp_intersectionsx failed %LG < %LG", + x2, x1)); + } + else if (result > 0) + { + if (!de_check(x1, x2) && x2 < x1) + GCALC_DBUG_PRINT(("floatcheck cmp_intersectionsx failed %LG > %LG", + x2, x1)); + } + else + { + if (!de_check(x1, x2)) + GCALC_DBUG_PRINT(("floatcheck cmp_intersectionsx failed %LG == %LG", + x2, x1)); + } #endif /*GCALC_CHECK_WITH_FLOAT*/ return result; } @@ -959,43 +907,26 @@ void Gcalc_heap::Info::calc_xy(double *x, double *y) const #ifdef GCALC_CHECK_WITH_FLOAT void Gcalc_heap::Info::calc_xy_ld(long double *x, long double *y) const { - long double b0_x= p2->x - p1->x; - long double b0_y= p2->y - p1->y; - long double b1_x= p4->x - p3->x; - long double b1_y= p4->y - p3->y; + long double b0_x= ((long double) p2->x) - p1->x; + long double b0_y= ((long double) p2->y) - p1->y; + long double b1_x= ((long double) p4->x) - p3->x; + long double b1_y= ((long double) p4->y) - p3->y; long double b0xb1= b0_x * b1_y - b0_y * b1_x; - long double t= (p3->x - p1->x) * b1_y - (p3->y - p1->y) * b1_x; - long double cx, cy; + long double ax= ((long double) p3->x) - p1->x; + long double ay= ((long double) p3->y) - p1->y; + long double t_a= ax * b1_y - ay * b1_x; + long double hx= (b0xb1 * (long double) p1->x + b0_x * t_a); + long double hy= (b0xb1 * (long double) p1->y + b0_y * t_a); - t/= b0xb1; - - cx= (long double) p1->x + b0_x * t; - cy= (long double) p1->y + b0_y * t; - - Gcalc_coord2 t_a, t_b; - Gcalc_coord1 yb, xb; - Gcalc_coord3 m1, m2, sum; - - calc_t(&t_a, &t_b, &xb, &yb, this); - if (t_b.is_zero()) + if (fabs(b0xb1) < 1e-15) { *x= p1->x; *y= p1->y; return; } - m1.init(); - m2.init(); - sum.init(); - gcalc_mul_coord(&m1, &p1->ix, &t_b); - gcalc_mul_coord(&m2, &xb, &t_a); - gcalc_add_coord(&sum, &m1, &m2); - *x= sum.get_double() / t_b.get_double(); - - gcalc_mul_coord(&m1, &p1->iy, &t_b); - gcalc_mul_coord(&m2, &yb, &t_a); - gcalc_add_coord(&sum, &m1, &m2); - *y= sum.get_double() / t_b.get_double(); + *x= hx/b0xb1; + *y= hy/b0xb1; } #endif /*GCALC_CHECK_WITH_FLOAT*/ @@ -1003,10 +934,10 @@ void Gcalc_heap::Info::calc_xy_ld(long double *x, long double *y) const static int cmp_point_info(const Gcalc_heap::Info *i0, const Gcalc_heap::Info *i1) { - int cmp_y= gcalc_cmp_coord(&i0->iy, &i1->iy); + int cmp_y= gcalc_cmp_coord1(i0->iy, i1->iy); if (cmp_y) return cmp_y; - return gcalc_cmp_coord(&i0->ix, &i1->ix); + return gcalc_cmp_coord1(i0->ix, i1->ix); } @@ -1048,14 +979,14 @@ void Gcalc_heap::prepare_operation() GCALC_DBUG_ASSERT(m_hook); coord_extent= find_scale(coord_extent); #ifdef GCALC_CHECK_WITH_FLOAT - Gcalc_internal_coord::coord_extent= &coord_extent; + 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()) { - cur->ix.set_double(cur->x, coord_extent); - cur->iy.set_double(cur->y, coord_extent); + 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); @@ -1153,9 +1084,9 @@ void Gcalc_shape_transporter::int_complete() inline void calc_dx_dy(Gcalc_scan_iterator::point *p) { - gcalc_sub_coord(&p->dx, &p->next_pi->ix, &p->pi->ix); - gcalc_sub_coord(&p->dy, &p->next_pi->iy, &p->pi->iy); - if (p->dx.sign) + gcalc_sub_coord1(p->dx, p->next_pi->ix, p->pi->ix); + gcalc_sub_coord1(p->dy, p->next_pi->iy, p->pi->iy); + if (GCALC_SIGN(p->dx[0])) { p->l_border= &p->next_pi->ix; p->r_border= &p->pi->ix; @@ -1203,19 +1134,17 @@ void Gcalc_scan_iterator::reset() } -int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_coord1 *dx_a, - const Gcalc_coord1 *dy_a, - const Gcalc_coord1 *dx_b, - const Gcalc_coord1 *dy_b) +int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_coord1 dx_a, + const Gcalc_coord1 dy_a, + const Gcalc_coord1 dx_b, + const Gcalc_coord1 dy_b) { Gcalc_coord2 dx_a_dy_b; Gcalc_coord2 dy_a_dx_b; - dx_a_dy_b.init(); - dy_a_dx_b.init(); - gcalc_mul_coord(&dx_a_dy_b, dx_a, dy_b); - gcalc_mul_coord(&dy_a_dx_b, dy_a, dx_b); + gcalc_mul_coord1(dx_a_dy_b, dx_a, dy_b); + gcalc_mul_coord1(dy_a_dx_b, dy_a, dx_b); - return gcalc_cmp_coord(&dx_a_dy_b, &dy_a_dx_b); + return gcalc_cmp_coord(dx_a_dy_b, dy_a_dx_b, GCALC_COORD_BASE2); } @@ -1225,22 +1154,18 @@ int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_heap::Info *p1, const Gcalc_heap::Info *p4) { Gcalc_coord1 dx_a, dy_a, dx_b, dy_b; - dx_a.init(); - dx_b.init(); - dy_a.init(); - dy_b.init(); - gcalc_sub_coord(&dx_a, &p2->ix, &p1->ix); - gcalc_sub_coord(&dy_a, &p2->iy, &p1->iy); - gcalc_sub_coord(&dx_b, &p4->ix, &p3->ix); - gcalc_sub_coord(&dy_b, &p4->iy, &p3->iy); - return cmp_dx_dy(&dx_a, &dy_a, &dx_b, &dy_b); + gcalc_sub_coord1(dx_a, p2->ix, p1->ix); + gcalc_sub_coord1(dy_a, p2->iy, p1->iy); + gcalc_sub_coord1(dx_b, p4->ix, p3->ix); + gcalc_sub_coord1(dy_b, p4->iy, p3->iy); + return cmp_dx_dy(dx_a, dy_a, dx_b, dy_b); } int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const { GCALC_DBUG_ASSERT(!is_bottom()); - return cmp_dx_dy(&dx, &dy, &p->dx, &p->dy); + return cmp_dx_dy(dx, dy, p->dx, p->dy); } @@ -1248,13 +1173,14 @@ int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const void Gcalc_scan_iterator::point::calc_x(long double *x, long double y, long double ix) const { - long double ddy= dy.get_double(); + long double ddy= gcalc_get_double(dy, GCALC_COORD_BASE); if (fabsl(ddy) < (long double) 1e-20) { *x= ix; } else - *x= (ddy * (long double) pi->x + dx.get_double() * (y - pi->y)) / ddy; + *x= (ddy * (long double) pi->x + gcalc_get_double(dx, GCALC_COORD_BASE) * + (y - pi->y)) / ddy; } #endif /*GCALC_CHECK_WITH_FLOAT*/ @@ -1457,20 +1383,35 @@ static int node_on_right(const Gcalc_heap::Info *node, Gcalc_coord1 a_x, a_y; Gcalc_coord1 b_x, b_y; Gcalc_coord2 ax_by, ay_bx; - a_x.init(); - a_y.init(); - b_x.init(); - b_y.init(); - ax_by.init(); - ay_bx.init(); + int result; - gcalc_sub_coord(&a_x, &node->ix, &edge_a->ix); - gcalc_sub_coord(&a_y, &node->iy, &edge_a->iy); - gcalc_sub_coord(&b_x, &edge_b->ix, &edge_a->ix); - gcalc_sub_coord(&b_y, &edge_b->iy, &edge_a->iy); - gcalc_mul_coord(&ax_by, &a_x, &b_y); - gcalc_mul_coord(&ay_bx, &a_y, &b_x); - return gcalc_cmp_coord(&ax_by, &ay_bx); + gcalc_sub_coord1(a_x, node->ix, edge_a->ix); + gcalc_sub_coord1(a_y, node->iy, edge_a->iy); + gcalc_sub_coord1(b_x, edge_b->ix, edge_a->ix); + gcalc_sub_coord1(b_y, edge_b->iy, edge_a->iy); + gcalc_mul_coord1(ax_by, a_x, b_y); + gcalc_mul_coord1(ay_bx, a_y, b_x); + result= gcalc_cmp_coord(ax_by, ay_bx, GCALC_COORD_BASE2); +#ifdef GCALC_CHECK_WITH_FLOAT + { + long double dx= gcalc_get_double(edge_b->ix, GCALC_COORD_BASE) - + gcalc_get_double(edge_a->ix, GCALC_COORD_BASE); + long double dy= gcalc_get_double(edge_b->iy, GCALC_COORD_BASE) - + gcalc_get_double(edge_a->iy, GCALC_COORD_BASE); + long double ax= gcalc_get_double(node->ix, GCALC_COORD_BASE) - + gcalc_get_double(edge_a->ix, GCALC_COORD_BASE); + long double ay= gcalc_get_double(node->iy, GCALC_COORD_BASE) - + gcalc_get_double(edge_a->iy, GCALC_COORD_BASE); + long double d= ax * dy - ay * dx; + if (result == 0) + GCALC_DBUG_ASSERT(de_check(d, 0.0)); + else if (result < 0) + GCALC_DBUG_ASSERT(de_check(d, 0.0) || d < 0); + else + GCALC_DBUG_ASSERT(de_check(d, 0.0) || d > 0); + } +#endif /*GCALC_CHECK_WITH_FLOAT*/ + return result; } @@ -1479,8 +1420,8 @@ static int cmp_tops(const Gcalc_heap::Info *top_node, { int cmp_res_a, cmp_res_b; - cmp_res_a= gcalc_cmp_coord1(&edge_a->ix, &top_node->ix); - cmp_res_b= gcalc_cmp_coord1(&edge_b->ix, &top_node->ix); + cmp_res_a= gcalc_cmp_coord1(edge_a->ix, top_node->ix); + cmp_res_b= gcalc_cmp_coord1(edge_b->ix, top_node->ix); if (cmp_res_a <= 0 && cmp_res_b > 0) return -1; @@ -1534,7 +1475,7 @@ int Gcalc_scan_iterator::insert_top_node() else if (cmp_res == 0) { /* Exactly same direction of the edges. */ - cmp_res= gcalc_cmp_coord1(&m_cur_pi->left->iy, &m_cur_pi->right->iy); + cmp_res= gcalc_cmp_coord1(m_cur_pi->left->iy, m_cur_pi->right->iy); if (cmp_res != 0) { if (cmp_res < 0) @@ -1550,7 +1491,7 @@ int Gcalc_scan_iterator::insert_top_node() } else { - cmp_res= gcalc_cmp_coord1(&m_cur_pi->left->ix, &m_cur_pi->right->ix); + cmp_res= gcalc_cmp_coord1(m_cur_pi->left->ix, m_cur_pi->right->ix); if (cmp_res != 0) { if (cmp_res < 0) @@ -1584,7 +1525,7 @@ int Gcalc_scan_iterator::insert_top_node() /* We need to find the place to insert. */ for (; sp; prev_hook= sp->next_ptr(), sp=sp->get_next()) { - if (sp->event || gcalc_cmp_coord(sp->r_border, &m_cur_pi->ix) < 0) + if (sp->event || gcalc_cmp_coord1(*sp->r_border, m_cur_pi->ix) < 0) continue; cmp_res= node_on_right(m_cur_pi, sp->pi, sp->next_pi); if (cmp_res == 0) @@ -1683,7 +1624,7 @@ int Gcalc_scan_iterator::add_events_for_node(point *sp_node) GCALC_DBUG_ASSERT(!sp->is_bottom()); GCALC_DBUG_PRINT(("left cut_edge %d", sp->thread)); if (sp->next_pi == sp_node->next_pi || - gcalc_cmp_coord1(sp->r_border, sp_node->l_border) < 0) + gcalc_cmp_coord1(*sp->r_border, *sp_node->l_border) < 0) continue; sp_pi_r= node_on_right(sp->next_pi, sp_node->pi, sp_node->next_pi); if (sp_pi_r < 0) @@ -1743,7 +1684,7 @@ int Gcalc_scan_iterator::add_events_for_node(point *sp_node) GCALC_DBUG_ASSERT(!sp->is_bottom()); GCALC_DBUG_PRINT(("right cut_edge %d", sp->thread)); if (sp->next_pi == sp_node->next_pi || - gcalc_cmp_coord1(sp_node->r_border, sp->l_border) < 0) + gcalc_cmp_coord1(*sp_node->r_border, *sp->l_border) < 0) continue; sp_pi_r= node_on_right(sp->next_pi, sp_node->pi, sp_node->next_pi); if (sp_pi_r > 0) @@ -1942,13 +1883,54 @@ int Gcalc_scan_iterator::add_eq_node(Gcalc_heap::Info *node, point *sp) } +void calc_t(Gcalc_coord2 t_a, Gcalc_coord2 t_b, + Gcalc_coord1 dxa, Gcalc_coord1 dxb, + const Gcalc_heap::Info *p1, const Gcalc_heap::Info *p2, + const Gcalc_heap::Info *p3, const Gcalc_heap::Info *p4) +{ + Gcalc_coord1 a2_a1x, a2_a1y; + Gcalc_coord2 x1y2, x2y1; + Gcalc_coord1 dya, dyb; + + gcalc_sub_coord1(a2_a1x, p3->ix, p1->ix); + gcalc_sub_coord1(a2_a1y, p3->iy, p1->iy); + + gcalc_sub_coord1(dxa, p2->ix, p1->ix); + gcalc_sub_coord1(dya, p2->iy, p1->iy); + gcalc_sub_coord1(dxb, p4->ix, p3->ix); + gcalc_sub_coord1(dyb, p4->iy, p3->iy); + + gcalc_mul_coord1(x1y2, dxa, dyb); + gcalc_mul_coord1(x2y1, dya, dxb); + gcalc_sub_coord(t_b, GCALC_COORD_BASE2, x1y2, x2y1); + + + gcalc_mul_coord1(x1y2, a2_a1x, dyb); + gcalc_mul_coord1(x2y1, a2_a1y, dxb); + gcalc_sub_coord(t_a, GCALC_COORD_BASE2, x1y2, x2y1); +} + + double Gcalc_scan_iterator::get_y() const { if (state.pi->type == Gcalc_heap::nt_intersection) { - double x, y; - state.pi->calc_xy(&x, &y); - return y; + Gcalc_coord1 dxa, dya; + Gcalc_coord2 t_a, t_b; + Gcalc_coord3 a_tb, b_ta, y_exp; + calc_t(t_a, t_b, dxa, dya, + state.pi->p1, state.pi->p2, state.pi->p3, state.pi->p4); + + + gcalc_mul_coord(a_tb, GCALC_COORD_BASE3, + t_b, GCALC_COORD_BASE2, state.pi->p1->iy, GCALC_COORD_BASE); + gcalc_mul_coord(b_ta, GCALC_COORD_BASE3, + t_a, GCALC_COORD_BASE2, dya, GCALC_COORD_BASE); + + gcalc_add_coord(y_exp, GCALC_COORD_BASE3, a_tb, b_ta); + + return (get_pure_double(y_exp, GCALC_COORD_BASE3) / + get_pure_double(t_b, GCALC_COORD_BASE2)) / m_heap->coord_extent; } else return state.pi->y; @@ -1959,9 +1941,22 @@ double Gcalc_scan_iterator::get_event_x() const { if (state.pi->type == Gcalc_heap::nt_intersection) { - double x, y; - state.pi->calc_xy(&x, &y); - return x; + Gcalc_coord1 dxa, dya; + Gcalc_coord2 t_a, t_b; + Gcalc_coord3 a_tb, b_ta, x_exp; + calc_t(t_a, t_b, dxa, dya, + state.pi->p1, state.pi->p2, state.pi->p3, state.pi->p4); + + + gcalc_mul_coord(a_tb, GCALC_COORD_BASE3, + t_b, GCALC_COORD_BASE2, state.pi->p1->ix, GCALC_COORD_BASE); + gcalc_mul_coord(b_ta, GCALC_COORD_BASE3, + t_a, GCALC_COORD_BASE2, dxa, GCALC_COORD_BASE); + + gcalc_add_coord(x_exp, GCALC_COORD_BASE3, a_tb, b_ta); + + return (get_pure_double(x_exp, GCALC_COORD_BASE3) / + get_pure_double(t_b, GCALC_COORD_BASE2)) / m_heap->coord_extent; } else return state.pi->x; @@ -1994,4 +1989,21 @@ double Gcalc_scan_iterator::get_sp_x(const point *sp) const } +double Gcalc_scan_iterator::get_pure_double(const Gcalc_internal_coord *d, + int d_len) +{ + int n= 1; + long double res= (long double) FIRST_DIGIT(d[0]); + do + { + res*= (long double) GCALC_DIG_BASE; + res+= (long double) d[n]; + } while(++n < d_len); + + if (GCALC_SIGN(d[0])) + res*= -1.0; + return res; +} + + #endif /* HAVE_SPATIAL */ diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index e5323952afe..92f22d9db44 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -114,78 +114,34 @@ protected: /* Internal Gcalc coordinates to provide the precise calculations */ #define GCALC_DIG_BASE 1000000000 -typedef int32 gcalc_digit_t; -typedef long long gcalc_coord2; - +typedef uint32 gcalc_digit_t; +typedef unsigned long long gcalc_coord2; +typedef gcalc_digit_t Gcalc_internal_coord; #define GCALC_COORD_BASE 2 +#define GCALC_COORD_BASE2 4 +#define GCALC_COORD_BASE3 6 +#define GCALC_COORD_BASE4 8 +#define GCALC_COORD_BASE5 10 -class Gcalc_internal_coord -{ -public: - gcalc_digit_t *digits; - int sign; - int n_digits; - void set_zero(); - int is_zero() const; -#ifdef GCALC_CHECK_WITH_FLOAT - static double *coord_extent; - long double get_double() const; -#endif /*GCALC_CHECK_WITH_FLOAT*/ -}; +typedef gcalc_digit_t Gcalc_coord1[GCALC_COORD_BASE]; +typedef gcalc_digit_t Gcalc_coord2[GCALC_COORD_BASE*2]; +typedef gcalc_digit_t Gcalc_coord3[GCALC_COORD_BASE*3]; -class Gcalc_coord1 : public Gcalc_internal_coord -{ - gcalc_digit_t c[GCALC_COORD_BASE]; -public: - void init() - { - n_digits= GCALC_COORD_BASE; - digits= c; - } - int set_double(double d, double ext); - void copy(const Gcalc_coord1 *from); -}; +void gcalc_mul_coord(Gcalc_internal_coord *result, int result_len, + const Gcalc_internal_coord *a, int a_len, + const Gcalc_internal_coord *b, int b_len); - -class Gcalc_coord2 : public Gcalc_internal_coord -{ - gcalc_digit_t c[GCALC_COORD_BASE*2]; -public: - void init() - { - n_digits= GCALC_COORD_BASE*2; - digits= c; - } -}; - - -class Gcalc_coord3 : public Gcalc_internal_coord -{ - gcalc_digit_t c[GCALC_COORD_BASE*3]; - public: - void init() - { - n_digits= GCALC_COORD_BASE*3; - digits= c; - } -}; - - -void gcalc_mul_coord(Gcalc_internal_coord *result, +void gcalc_add_coord(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b); -void gcalc_add_coord(Gcalc_internal_coord *result, - const Gcalc_internal_coord *a, - const Gcalc_internal_coord *b); - -void gcalc_sub_coord(Gcalc_internal_coord *result, +void gcalc_sub_coord(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b); int gcalc_cmp_coord(const Gcalc_internal_coord *a, - const Gcalc_internal_coord *b); + const Gcalc_internal_coord *b, int len); /* Internal coordinates declarations end. */ @@ -280,11 +236,11 @@ public: #ifdef GCALC_CHECK_WITH_FLOAT long double get_double(const Gcalc_internal_coord *c) const; #endif /*GCALC_CHECK_WITH_FLOAT*/ + double coord_extent; private: Gcalc_dyn_list::Item *m_first; Gcalc_dyn_list::Item **m_hook; int m_n_points; - double coord_extent; }; @@ -422,10 +378,10 @@ public: inline const point *get_next() const { return (const point *)next; } /* Compare the dx_dy parameters regarding the horiz_dir */ /* returns -1 if less, 0 if equal, 1 if bigger */ - static int cmp_dx_dy(const Gcalc_coord1 *dx_a, - const Gcalc_coord1 *dy_a, - const Gcalc_coord1 *dx_b, - const Gcalc_coord1 *dy_b); + static int cmp_dx_dy(const Gcalc_coord1 dx_a, + const Gcalc_coord1 dy_a, + const Gcalc_coord1 dx_b, + const Gcalc_coord1 dy_b); static int cmp_dx_dy(const Gcalc_heap::Info *p1, const Gcalc_heap::Info *p2, const Gcalc_heap::Info *p3, @@ -467,9 +423,16 @@ public: int x_calculated; Gcalc_coord3 y_exp; int y_calculated; - void calc_t(); - void calc_y_exp(); - void calc_x_exp(); + void calc_t() + {if (!t_calculated) do_calc_t(); } + void calc_y_exp() + { if (!y_calculated) do_calc_y(); } + void calc_x_exp() + { if (!x_calculated) do_calc_x(); } + + void do_calc_t(); + void do_calc_x(); + void do_calc_y(); }; @@ -540,8 +503,6 @@ private: point *new_slice_point() { point *new_point= (point *)new_item(); - new_point->dx.init(); - new_point->dy.init(); return new_point; } intersection_info *new_intersection_info(point *a, point *b) @@ -553,6 +514,7 @@ private: return ii; } int arrange_event(int do_sorting, int n_intersections); + static double get_pure_double(const Gcalc_internal_coord *d, int d_len); }; From 45bb808c7ec0a77bb51038ff370753f8ed5c7ddf Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 16 Oct 2011 21:16:53 +0500 Subject: [PATCH 40/40] code cleanup. --- sql/gcalc_slicescan.cc | 48 ------------------------------------------ 1 file changed, 48 deletions(-) diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 03c77163f49..56732101e5f 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -132,40 +132,6 @@ static void GCALC_DBUG_PRINT_PI(const Gcalc_heap::Info *pi) } -#ifdef TMP_BLOCK -static void GCALC_DBUG_PRINT_SLICE(const char *header, - const Gcalc_scan_iterator::point *slice) -{ - int nbuf1, nbuf2; - int nbuf3, nbuf4; - char buf1[1024], buf2[1024]; - char buf3[1024], buf4[1024]; - nbuf1= nbuf2= nbuf3= nbuf4= strlen(header); - strcpy(buf1, header); - strcpy(buf2, header); - strcpy(buf3, header); - strcpy(buf4, header); - for (; slice; slice= slice->get_next()) - { - nbuf1+= sprintf(buf1+nbuf1, "%d\t", slice->thread); - nbuf2+= sprintf(buf2+nbuf2, "%s\t", gcalc_ev_name(slice->event)); - - nbuf3+= gcalc_pi_str(buf3+nbuf3, slice->pi, "\t"); - if (slice->is_bottom()) - nbuf4+= sprintf(buf4+nbuf4, "bt\t"); - else - nbuf4+= gcalc_pi_str(buf4+nbuf4, slice->next_pi, "\t"); - } - buf1[nbuf1]= 0; - buf2[nbuf2]= 0; - buf3[nbuf3]= 0; - buf4[nbuf4]= 0; - GCALC_DBUG_PRINT((buf1)); - GCALC_DBUG_PRINT((buf2)); - GCALC_DBUG_PRINT((buf3)); - GCALC_DBUG_PRINT((buf4)); -} -#endif /*TMP_BLOCK*/ static void GCALC_DBUG_PRINT_SLICE(const char *header, const Gcalc_scan_iterator::point *slice) { @@ -1001,17 +967,6 @@ void Gcalc_heap::prepare_operation() void Gcalc_heap::reset() { -#ifdef TMP_BLOCK - if (!m_hook) - { - m_hook= &m_first; - for (; *m_hook; m_hook= &(*m_hook)->next) - {} - } - - *m_hook= m_free; - m_free= m_first; -#endif /*TMP_BLOCK*/ if (m_n_points) { free_list(m_first); @@ -1537,9 +1492,6 @@ int Gcalc_scan_iterator::insert_top_node() else if (cmp_res < 0) break; } -#ifdef TMP_BLOCK - state.event_position_hook= prev_hook; -#endif /*TMP_BLOCK*/ } if (sp0->event == scev_single_point)