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