You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

917 lines
22 KiB

  1. /* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; version 2 of the License.
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License
  10. along with this program; if not, write to the Free Software
  11. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
  12. #include "mysql_priv.h"
  13. #ifdef HAVE_SPATIAL
  14. #include "gcalc_slicescan.h"
  15. #define PH_DATA_OFFSET 8
  16. #define coord_to_float(d) ((double) d)
  17. #define coord_eq(a, b) (a == b)
  18. typedef int (*sc_compare_func)(const void*, const void*);
  19. #define LS_LIST_ITEM Gcalc_dyn_list::Item
  20. #define LS_COMPARE_FUNC_DECL sc_compare_func compare,
  21. #define LS_COMPARE_FUNC_CALL(list_el1, list_el2) (*compare)(list_el1, list_el2)
  22. #define LS_NEXT(A) (A)->next
  23. #define LS_SET_NEXT(A,val) (A)->next= val
  24. #define LS_P_NEXT(A) &(A)->next
  25. #define LS_NAME sort_list
  26. #define LS_SCOPE static
  27. #define LS_STRUCT_NAME sort_list_stack_struct
  28. #include "plistsort.c"
  29. Gcalc_dyn_list::Gcalc_dyn_list(size_t blk_size, size_t sizeof_item):
  30. m_blk_size(blk_size - ALLOC_ROOT_MIN_BLOCK_SIZE),
  31. m_sizeof_item(ALIGN_SIZE(sizeof_item)),
  32. m_points_per_blk((m_blk_size - PH_DATA_OFFSET) / m_sizeof_item),
  33. m_blk_hook(&m_first_blk),
  34. m_free(NULL),
  35. m_keep(NULL)
  36. {}
  37. void Gcalc_dyn_list::format_blk(void* block)
  38. {
  39. Item *pi_end, *cur_pi, *first_pi;
  40. DBUG_ASSERT(m_free == NULL);
  41. first_pi= cur_pi= (Item *)(((char *)block) + PH_DATA_OFFSET);
  42. pi_end= ptr_add(first_pi, m_points_per_blk - 1);
  43. do {
  44. cur_pi= cur_pi->next= ptr_add(cur_pi, 1);
  45. } while (cur_pi<pi_end);
  46. cur_pi->next= m_free;
  47. m_free= first_pi;
  48. }
  49. Gcalc_dyn_list::Item *Gcalc_dyn_list::alloc_new_blk()
  50. {
  51. void *new_block= my_malloc(m_blk_size, MYF(MY_WME));
  52. if (!new_block)
  53. return NULL;
  54. *m_blk_hook= new_block;
  55. m_blk_hook= (void**)new_block;
  56. format_blk(new_block);
  57. return new_item();
  58. }
  59. static void free_blk_list(void *list)
  60. {
  61. void *next_blk;
  62. while (list)
  63. {
  64. next_blk= *((void **)list);
  65. my_free(list, MYF(0));
  66. list= next_blk;
  67. }
  68. }
  69. void Gcalc_dyn_list::cleanup()
  70. {
  71. *m_blk_hook= NULL;
  72. free_blk_list(m_first_blk);
  73. m_first_blk= NULL;
  74. m_blk_hook= &m_first_blk;
  75. m_free= NULL;
  76. }
  77. Gcalc_dyn_list::~Gcalc_dyn_list()
  78. {
  79. cleanup();
  80. }
  81. void Gcalc_dyn_list::reset()
  82. {
  83. *m_blk_hook= NULL;
  84. if (m_first_blk)
  85. {
  86. free_blk_list(*((void **)m_first_blk));
  87. m_blk_hook= (void**)m_first_blk;
  88. m_free= NULL;
  89. format_blk(m_first_blk);
  90. }
  91. }
  92. static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node)
  93. {
  94. if (!node)
  95. return;
  96. DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node));
  97. if (node->left == prev_node)
  98. node->left= node->right;
  99. node->right= NULL;
  100. }
  101. static int compare_point_info(const void *e0, const void *e1)
  102. {
  103. const Gcalc_heap::Info *i0= (const Gcalc_heap::Info *)e0;
  104. const Gcalc_heap::Info *i1= (const Gcalc_heap::Info *)e1;
  105. if (!coord_eq(i0->y, i1->y))
  106. return i0->y > i1->y;
  107. return i0->x > i1->x;
  108. }
  109. void Gcalc_heap::prepare_operation()
  110. {
  111. DBUG_ASSERT(m_hook);
  112. *m_hook= NULL;
  113. m_first= sort_list(compare_point_info, m_first, m_n_points);
  114. m_hook= NULL; /* just to check it's not called twice */
  115. /* TODO - move this to the 'normal_scan' loop */
  116. for (Info *cur= get_first(); cur; cur= cur->get_next())
  117. {
  118. trim_node(cur->left, cur);
  119. trim_node(cur->right, cur);
  120. }
  121. }
  122. void Gcalc_heap::reset()
  123. {
  124. if (!m_hook)
  125. {
  126. m_hook= &m_first;
  127. for (; *m_hook; m_hook= &(*m_hook)->next)
  128. {}
  129. }
  130. *m_hook= m_free;
  131. m_free= m_first;
  132. m_hook= &m_first;
  133. m_n_points= 0;
  134. }
  135. int Gcalc_shape_transporter::int_single_point(gcalc_shape_info Info,
  136. double x, double y)
  137. {
  138. Gcalc_heap::Info *point= m_heap->new_point_info(x, y, Info);
  139. if (!point)
  140. return 1;
  141. point->left= point->right= 0;
  142. return 0;
  143. }
  144. int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info,
  145. double x, double y)
  146. {
  147. Gcalc_heap::Info *point;
  148. DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y);
  149. if (!(point= m_heap->new_point_info(x, y, Info)))
  150. return 1;
  151. if (m_first)
  152. {
  153. m_prev->left= point;
  154. point->right= m_prev;
  155. }
  156. else
  157. m_first= point;
  158. m_prev= point;
  159. return 0;
  160. }
  161. void Gcalc_shape_transporter::int_complete()
  162. {
  163. DBUG_ASSERT(m_shape_started == 1 || m_shape_started == 3);
  164. if (!m_first)
  165. return;
  166. /* simple point */
  167. if (m_first == m_prev)
  168. {
  169. m_first->right= m_first->left= NULL;
  170. return;
  171. }
  172. /* line */
  173. if (m_shape_started == 1)
  174. {
  175. m_first->right= NULL;
  176. m_prev->left= m_prev->right;
  177. m_prev->right= NULL;
  178. return;
  179. }
  180. DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y);
  181. /* polygon */
  182. m_first->right= m_prev;
  183. m_prev->left= m_first;
  184. }
  185. inline int GET_DX_DY(double *dxdy,
  186. const Gcalc_heap::Info *p0, const Gcalc_heap::Info *p1)
  187. {
  188. double dy= p1->y - p0->y;
  189. *dxdy= p1->x - p0->x;
  190. return (dy == 0.0) ||
  191. (*dxdy/= dy)>DBL_MAX ||
  192. (*dxdy)<-DBL_MAX;
  193. }
  194. Gcalc_scan_iterator::Gcalc_scan_iterator(size_t blk_size) :
  195. Gcalc_dyn_list(blk_size,
  196. (sizeof(point) > sizeof(intersection)) ?
  197. sizeof(point) : sizeof(intersection))
  198. {}
  199. Gcalc_scan_iterator::point
  200. *Gcalc_scan_iterator::new_slice(Gcalc_scan_iterator::point *example)
  201. {
  202. point *result= NULL;
  203. Gcalc_dyn_list::Item **result_hook= (Gcalc_dyn_list::Item **) &result;
  204. while (example)
  205. {
  206. *result_hook= new_slice_point();
  207. result_hook= &(*result_hook)->next;
  208. example= example->get_next();
  209. }
  210. *result_hook= NULL;
  211. return result;
  212. }
  213. void Gcalc_scan_iterator::init(Gcalc_heap *points)
  214. {
  215. DBUG_ASSERT(points->ready());
  216. DBUG_ASSERT(!state0.slice && !state1.slice);
  217. if (!(m_cur_pi= points->get_first()))
  218. return;
  219. m_cur_thread= 0;
  220. m_intersections= NULL;
  221. m_next_is_top_point= true;
  222. m_events= NULL;
  223. current_state= &state0;
  224. next_state= &state1;
  225. saved_state= &state_s;
  226. next_state->y= m_cur_pi->y;
  227. }
  228. void Gcalc_scan_iterator::reset()
  229. {
  230. state0.slice= state1.slice= m_events= state_s.slice= NULL;
  231. m_intersections= NULL;
  232. Gcalc_dyn_list::reset();
  233. }
  234. void Gcalc_scan_iterator::point::copy_core(point *from)
  235. {
  236. dx_dy= from->dx_dy;
  237. horiz_dir= from->horiz_dir;
  238. pi= from->pi;
  239. next_pi= from->next_pi;
  240. thread= from->thread;
  241. #ifdef TO_REMOVE
  242. from->next_link= this;
  243. #endif /*TO_REMOVE*/
  244. }
  245. int Gcalc_scan_iterator::point::compare_dx_dy(int horiz_dir_a, double dx_dy_a,
  246. int horiz_dir_b, double dx_dy_b)
  247. {
  248. if (!horiz_dir_a && !horiz_dir_b)
  249. {
  250. if (coord_eq(dx_dy_a, dx_dy_b))
  251. return 0;
  252. return dx_dy_a < dx_dy_b ? -1 : 1;
  253. }
  254. if (!horiz_dir_a)
  255. return -1;
  256. if (!horiz_dir_b)
  257. return 1;
  258. return 0;
  259. }
  260. int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const
  261. {
  262. if (is_bottom())
  263. return p->is_bottom() ? 0 : -1;
  264. if (p->is_bottom())
  265. return 1;
  266. return compare_dx_dy(horiz_dir, dx_dy, p->horiz_dir, p->dx_dy);
  267. }
  268. void Gcalc_scan_iterator::mark_event_position1(
  269. point *ep, Gcalc_dyn_list::Item **ep_hook)
  270. {
  271. if (!next_state->event_position)
  272. {
  273. next_state->event_position= ep;
  274. next_state->event_position_hook= ep_hook;
  275. }
  276. next_state->event_end_hook= &ep->next;
  277. }
  278. static int compare_events(const void *e0, const void *e1)
  279. {
  280. const Gcalc_scan_iterator::point *p0= (const Gcalc_scan_iterator::point *)e0;
  281. const Gcalc_scan_iterator::point *p1= (const Gcalc_scan_iterator::point *)e1;
  282. return p0->cmp_dx_dy(p1) > 0;
  283. }
  284. int Gcalc_scan_iterator::arrange_event()
  285. {
  286. int ev_counter;
  287. point *sp, *new_sp;
  288. point *after_event;
  289. Gcalc_dyn_list::Item **ae_hook= (Gcalc_dyn_list::Item **) &after_event;
  290. if (m_events)
  291. free_list(m_events);
  292. ev_counter= 0;
  293. DBUG_ASSERT(current_state->event_position ==
  294. *current_state->event_position_hook);
  295. for (sp= current_state->event_position;
  296. sp != *current_state->event_end_hook; sp= sp->get_next())
  297. {
  298. if (sp->is_bottom())
  299. continue;
  300. if (!(new_sp= new_slice_point()))
  301. return 1;
  302. *new_sp= *sp;
  303. *ae_hook= new_sp;
  304. ae_hook= &new_sp->next;
  305. #ifdef TO_REMOVE
  306. sp->intersection_link= new_sp;
  307. #endif /*TO_REMOVE*/
  308. ev_counter++;
  309. }
  310. *ae_hook= NULL;
  311. m_events= current_state->event_position;
  312. if (after_event)
  313. {
  314. if (after_event->get_next())
  315. {
  316. point *cur_p;
  317. after_event= (point *) sort_list(compare_events, after_event, ev_counter);
  318. /* Find last item in the list, ae_hook can change after the sorting */
  319. for (cur_p= after_event->get_next(); cur_p->get_next();
  320. cur_p= cur_p->get_next());
  321. ae_hook= &cur_p->next;
  322. }
  323. *ae_hook= *current_state->event_end_hook;
  324. *current_state->event_end_hook= NULL;
  325. *current_state->event_position_hook= after_event;
  326. current_state->event_end_hook= ae_hook;
  327. current_state->event_position= after_event;
  328. }
  329. else
  330. {
  331. *current_state->event_position_hook= *current_state->event_end_hook;
  332. *current_state->event_end_hook= NULL;
  333. current_state->event_position= sp;
  334. current_state->event_end_hook= current_state->event_position_hook;
  335. }
  336. return 0;
  337. }
  338. int Gcalc_scan_iterator::insert_top_point()
  339. {
  340. point *sp= next_state->slice;
  341. Gcalc_dyn_list::Item **prev_hook=
  342. (Gcalc_dyn_list::Item **) &next_state->slice;
  343. point *sp1;
  344. point *sp0= new_slice_point();
  345. point *sp_inc;
  346. if (!sp0)
  347. return 1;
  348. sp0->pi= m_cur_pi;
  349. sp0->next_pi= m_cur_pi->left;
  350. sp0->thread= m_cur_thread++;
  351. sp0->x= coord_to_float(m_cur_pi->x);
  352. if (m_cur_pi->left)
  353. {
  354. sp0->horiz_dir= GET_DX_DY(&sp0->dx_dy, m_cur_pi, m_cur_pi->left);
  355. sp0->event= scev_thread;
  356. /*Now just to increase the size of m_slice0 to be same*/
  357. if (!(sp_inc= new_slice_point()))
  358. return 1;
  359. sp_inc->next= current_state->slice;
  360. current_state->slice= sp_inc;
  361. if (m_cur_pi->right)
  362. {
  363. if (!(sp1= new_slice_point()))
  364. return 1;
  365. sp1->event= sp0->event= scev_two_threads;
  366. #ifdef TO_REMOVE
  367. sp1->event_pair= sp0;
  368. sp0->event_pair= sp1;
  369. #endif /*TO_REMOVE*/
  370. sp1->pi= m_cur_pi;
  371. sp1->next_pi= m_cur_pi->right;
  372. sp1->thread= m_cur_thread++;
  373. sp1->x= sp0->x;
  374. sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->right);
  375. /* We have two threads so should decide which one will be first */
  376. if (sp0->cmp_dx_dy(sp1)>0)
  377. {
  378. point *tmp= sp0;
  379. sp0= sp1;
  380. sp1= tmp;
  381. }
  382. /*Now just to increase the size of m_slice0 to be same*/
  383. if (!(sp_inc= new_slice_point()))
  384. return 1;
  385. sp_inc->next= current_state->slice;
  386. current_state->slice= sp_inc;
  387. }
  388. }
  389. else
  390. {
  391. sp0->event= scev_single_point;
  392. sp0->horiz_dir= 0;
  393. sp0->dx_dy= 0.0;
  394. }
  395. /* We need to find the place to insert. */
  396. for (; sp && (sp->x < sp0->x); prev_hook= &sp->next, sp=sp->get_next())
  397. {}
  398. next_state->event_position_hook= prev_hook;
  399. if (sp && coord_eq(sp->x, sp0->x))
  400. {
  401. next_state->event_position= sp;
  402. do
  403. {
  404. if (!sp->event)
  405. sp->event= scev_intersection;
  406. prev_hook= &sp->next;
  407. sp= sp->get_next();
  408. } while (sp && coord_eq(sp->x, sp0->x));
  409. }
  410. else
  411. next_state->event_position= sp0;
  412. *prev_hook= sp0;
  413. if (sp0->event == scev_two_threads)
  414. {
  415. sp1->next= sp;
  416. sp0->next= sp1;
  417. next_state->event_end_hook= &sp1->next;
  418. }
  419. else
  420. {
  421. sp0->next= sp;
  422. next_state->event_end_hook= &sp0->next;
  423. }
  424. return 0;
  425. }
  426. int Gcalc_scan_iterator::normal_scan()
  427. {
  428. point *sp;
  429. Gcalc_dyn_list::Item **sp_hook;
  430. Gcalc_heap::Info *next_pi;
  431. point *first_bottom_point= NULL;
  432. if (m_next_is_top_point && insert_top_point())
  433. return 1;
  434. for (next_pi= m_cur_pi->get_next();
  435. next_pi &&
  436. coord_eq(m_cur_pi->x, next_pi->x) &&
  437. coord_eq(m_cur_pi->y, next_pi->y);
  438. next_pi= next_pi->get_next())
  439. {
  440. DBUG_ASSERT(coord_eq(next_state->event_position->x, next_pi->x));
  441. next_state->clear_event_position();
  442. m_next_is_top_point= true;
  443. for (sp= next_state->slice,
  444. sp_hook= (Gcalc_dyn_list::Item **) &next_state->slice; sp;
  445. sp_hook= &sp->next, sp= sp->get_next())
  446. {
  447. if (sp->next_pi == next_pi) /* End of the segment */
  448. {
  449. sp->x= coord_to_float(next_pi->x);
  450. sp->pi= next_pi;
  451. sp->next_pi= next_pi->left;
  452. m_next_is_top_point= false;
  453. if (next_pi->is_bottom())
  454. {
  455. if (first_bottom_point)
  456. {
  457. first_bottom_point->event= sp->event= scev_two_ends;
  458. #ifdef TO_REMOVE
  459. first_bottom_point->event_pair= sp;
  460. sp->event_pair= first_bottom_point;
  461. #endif /*TO_REMOVE*/
  462. }
  463. else
  464. {
  465. first_bottom_point= sp;
  466. sp->event= scev_end;
  467. }
  468. }
  469. else
  470. {
  471. sp->event= scev_point;
  472. sp->horiz_dir= GET_DX_DY(&sp->dx_dy, next_pi, next_pi->left);
  473. }
  474. mark_event_position1(sp, sp_hook);
  475. }
  476. else if (coord_eq(sp->x, next_pi->x))
  477. {
  478. if (!sp->event)
  479. sp->event= scev_intersection;
  480. mark_event_position1(sp, sp_hook);
  481. }
  482. }
  483. m_cur_pi= next_pi;
  484. if (m_next_is_top_point && insert_top_point())
  485. return 1;
  486. }
  487. /* Swap current <-> next */
  488. {
  489. slice_state *tmp= current_state;
  490. current_state= next_state;
  491. next_state= tmp;
  492. }
  493. if (arrange_event())
  494. return 1;
  495. point *sp0= current_state->slice;
  496. point *sp1= next_state->slice;
  497. point *prev_sp1= NULL;
  498. if (!(m_cur_pi= next_pi))
  499. {
  500. free_list(sp1);
  501. next_state->slice= NULL;
  502. #ifdef TO_REMOVE
  503. for (; sp0; sp0= sp0->get_next())
  504. sp0->next_link= NULL;
  505. #endif /*TO_REMOVE*/
  506. return 0;
  507. }
  508. Gcalc_heap::Info *cur_pi= m_cur_pi;
  509. next_state->y= coord_to_float(cur_pi->y);
  510. first_bottom_point= NULL;
  511. m_next_is_top_point= true;
  512. bool intersections_found= false;
  513. next_state->clear_event_position();
  514. for (; sp0; sp0= sp0->get_next())
  515. {
  516. if (sp0->next_pi == cur_pi) /* End of the segment */
  517. {
  518. sp1->x= coord_to_float(cur_pi->x);
  519. sp1->pi= cur_pi;
  520. sp1->thread= sp0->thread;
  521. sp1->next_pi= cur_pi->left;
  522. #ifdef TO_REMOVE
  523. sp0->next_link= sp1;
  524. #endif /*TO_REMOVE*/
  525. m_next_is_top_point= false;
  526. if (sp1->is_bottom())
  527. {
  528. if (!first_bottom_point)
  529. {
  530. sp1->event= scev_end;
  531. first_bottom_point= sp1;
  532. }
  533. else
  534. {
  535. first_bottom_point->event= sp1->event= scev_two_ends;
  536. #ifdef TO_REMOVE
  537. sp1->event_pair= first_bottom_point;
  538. first_bottom_point->event_pair= sp1;
  539. #endif /*TO_REMOVE*/
  540. }
  541. }
  542. else
  543. {
  544. sp1->event= scev_point;
  545. sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->left);
  546. }
  547. mark_event_position1(sp1,
  548. prev_sp1 ? &prev_sp1->next :
  549. (Gcalc_dyn_list::Item **) &next_state->slice);
  550. }
  551. else
  552. {
  553. /* Cut current string with the height of the new point*/
  554. sp1->copy_core(sp0);
  555. sp1->x= sp1->horiz_dir ? coord_to_float(cur_pi->x) :
  556. (coord_to_float(sp1->pi->x) +
  557. (next_state->y-coord_to_float(sp1->pi->y)) * sp1->dx_dy);
  558. if (coord_eq(sp1->x, cur_pi->x))
  559. {
  560. mark_event_position1(sp1,
  561. prev_sp1 ? &prev_sp1->next :
  562. (Gcalc_dyn_list::Item **) &next_state->slice);
  563. sp1->event= scev_intersection;
  564. }
  565. else
  566. sp1->event= scev_none;
  567. }
  568. intersections_found= intersections_found ||
  569. (prev_sp1 && prev_sp1->x > sp1->x);
  570. prev_sp1= sp1;
  571. sp1= sp1->get_next();
  572. }
  573. if (sp1)
  574. {
  575. if (prev_sp1)
  576. prev_sp1->next= NULL;
  577. else
  578. next_state->slice= NULL;
  579. free_list(sp1);
  580. }
  581. if (intersections_found)
  582. return handle_intersections();
  583. return 0;
  584. }
  585. #define INTERSECTION_ZERO 0.000000000001
  586. int Gcalc_scan_iterator::add_intersection(const point *a, const point *b,
  587. Gcalc_dyn_list::Item ***p_hook)
  588. {
  589. intersection *isc= new_intersection();
  590. if (!isc)
  591. return 1;
  592. m_n_intersections++;
  593. **p_hook= isc;
  594. *p_hook= &isc->next;
  595. isc->thread_a= a->thread;
  596. isc->thread_b= b->thread;
  597. /* intersection_normal */
  598. const point *a0= a->intersection_link;
  599. const point *b0= b->intersection_link;
  600. DBUG_ASSERT(!a0->horiz_dir || !b0->horiz_dir);
  601. if (!a0->horiz_dir && !b0->horiz_dir)
  602. {
  603. double dk= a0->dx_dy - b0->dx_dy;
  604. double dy= (b0->x - a0->x)/dk;
  605. if (fabs(dk) < INTERSECTION_ZERO)
  606. dy= 0.0;
  607. isc->y= current_state->y + dy;
  608. isc->x= a0->x + dy*a0->dx_dy;
  609. return 0;
  610. }
  611. isc->y= next_state->y;
  612. isc->x= a0->horiz_dir ? b->x : a->x;
  613. return 0;
  614. }
  615. int Gcalc_scan_iterator::find_intersections()
  616. {
  617. point *sp1= next_state->slice;
  618. Gcalc_dyn_list::Item **hook;
  619. m_n_intersections= 0;
  620. {
  621. /* Set links between slicepoints */
  622. point *sp0= current_state->slice;
  623. for (; sp1; sp0= sp0->get_next(),sp1= sp1->get_next())
  624. {
  625. DBUG_ASSERT(!sp0->is_bottom());
  626. DBUG_ASSERT(sp0->thread == sp1->thread);
  627. sp1->intersection_link= sp0;
  628. }
  629. }
  630. hook= (Gcalc_dyn_list::Item **)&m_intersections;
  631. bool intersections_found;
  632. point *last_possible_isc= NULL;
  633. do
  634. {
  635. point **pprev_s1= &next_state->slice;
  636. intersections_found= false;
  637. sp1= next_state->slice->get_next();
  638. point *cur_possible_isc= NULL;
  639. for (; sp1 != last_possible_isc;
  640. pprev_s1= (point **)(&(*pprev_s1)->next), sp1= sp1->get_next())
  641. {
  642. point *prev_s1= *pprev_s1;
  643. if (prev_s1->x <= sp1->x)
  644. continue;
  645. intersections_found= true;
  646. if (add_intersection(prev_s1, sp1, &hook))
  647. return 1;
  648. *pprev_s1= sp1;
  649. prev_s1->next= sp1->next;
  650. sp1->next= prev_s1;
  651. sp1= prev_s1;
  652. cur_possible_isc= sp1;
  653. }
  654. last_possible_isc= cur_possible_isc;
  655. } while (intersections_found);
  656. *hook= NULL;
  657. return 0;
  658. }
  659. static int compare_intersections(const void *e0, const void *e1)
  660. {
  661. Gcalc_scan_iterator::intersection *i0= (Gcalc_scan_iterator::intersection *)e0;
  662. Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1;
  663. if (i0->y != i1->y)
  664. return i0->y > i1->y;
  665. return i0->x > i1->x;
  666. }
  667. inline void Gcalc_scan_iterator::sort_intersections()
  668. {
  669. m_intersections= (intersection *)sort_list(compare_intersections,
  670. m_intersections,m_n_intersections);
  671. }
  672. int Gcalc_scan_iterator::handle_intersections()
  673. {
  674. DBUG_ASSERT(next_state->slice->next);
  675. if (find_intersections())
  676. return 1;
  677. sort_intersections();
  678. /* Swap saved <-> next */
  679. {
  680. slice_state *tmp= next_state;
  681. next_state= saved_state;
  682. saved_state= tmp;
  683. }
  684. /* We need the next slice to be just equal */
  685. next_state->slice= new_slice(saved_state->slice);
  686. m_cur_intersection= m_intersections;
  687. return intersection_scan();
  688. }
  689. int Gcalc_scan_iterator::intersection_scan()
  690. {
  691. point *sp0, *sp1;
  692. Gcalc_dyn_list::Item **hook;
  693. intersection *next_intersection;
  694. if (m_cur_intersection != m_intersections)
  695. {
  696. /* Swap current <-> next */
  697. {
  698. slice_state *tmp= current_state;
  699. current_state= next_state;
  700. next_state= tmp;
  701. }
  702. if (arrange_event())
  703. return 1;
  704. if (!m_cur_intersection)
  705. {
  706. saved_state->event_position_hook=
  707. (Gcalc_dyn_list::Item **) &saved_state->slice;
  708. #ifdef TO_REMOVE
  709. for (sp0= current_state->slice, sp1= saved_state->slice;
  710. sp0;
  711. sp0= sp0->get_next(), sp1= sp1->get_next())
  712. {
  713. sp0->next_link= sp1;
  714. if (sp1->get_next() == saved_state->event_position)
  715. saved_state->event_position_hook= &sp1->next;
  716. }
  717. #endif /*TO_REMOVE*/
  718. for (sp1= saved_state->slice; sp1; sp1= sp1->get_next())
  719. {
  720. if (sp1->get_next() == saved_state->event_position)
  721. saved_state->event_position_hook= &sp1->next;
  722. }
  723. /* Swap saved <-> next */
  724. {
  725. slice_state *tmp= next_state;
  726. next_state= saved_state;
  727. saved_state= tmp;
  728. }
  729. free_list(saved_state->slice);
  730. saved_state->slice= NULL;
  731. free_list(m_intersections);
  732. m_intersections= NULL;
  733. return 0;
  734. }
  735. }
  736. next_state->y= m_cur_intersection->y;
  737. found_equal_intersection:
  738. sp0= current_state->slice;
  739. hook= (Gcalc_dyn_list::Item **) &next_state->slice;
  740. sp1= next_state->slice;
  741. next_state->clear_event_position();
  742. for (; sp0;
  743. hook= &sp1->next, sp1= sp1->get_next(), sp0= sp0->get_next())
  744. {
  745. if (sp0->thread == m_cur_intersection->thread_a ||
  746. sp0->thread == m_cur_intersection->thread_b)
  747. {
  748. sp1->copy_core(sp0);
  749. sp1->x= m_cur_intersection->x;
  750. sp1->event= scev_intersection;
  751. mark_event_position1(sp1, hook);
  752. }
  753. else
  754. {
  755. sp1->copy_core(sp0);
  756. sp1->x= sp1->horiz_dir ?
  757. m_cur_intersection->x :
  758. coord_to_float(sp1->pi->x) +
  759. (next_state->y-coord_to_float(sp1->pi->y)) * sp1->dx_dy;
  760. if (coord_eq(sp1->x, m_cur_intersection->x))
  761. {
  762. sp1->event= scev_intersection;
  763. mark_event_position1(sp1, hook);
  764. }
  765. else
  766. sp1->event= scev_none;
  767. }
  768. }
  769. if (sp1)
  770. {
  771. free_list(sp1);
  772. *hook= NULL;
  773. }
  774. next_intersection= m_cur_intersection->get_next();
  775. if (next_intersection &&
  776. coord_eq(next_intersection->x, m_cur_intersection->x) &&
  777. coord_eq(next_intersection->y, m_cur_intersection->y))
  778. {
  779. m_cur_intersection= next_intersection;
  780. goto found_equal_intersection;
  781. }
  782. m_cur_intersection= next_intersection;
  783. return 0;
  784. }
  785. #endif /* HAVE_SPATIAL */