17 #include "sql_string.h"
21 #include "gcalc_slicescan.h"
24 #define PH_DATA_OFFSET 8
25 #define coord_to_float(d) ((double) d)
27 typedef int (*sc_compare_func)(
const void*,
const void*);
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"
41 Gcalc_dyn_list::Gcalc_dyn_list(
size_t blk_size,
size_t sizeof_item):
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),
54 void Gcalc_dyn_list::format_blk(
void*
block)
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);
61 cur_pi= cur_pi->
next= ptr_add(cur_pi, 1);
62 }
while (cur_pi<pi_end);
68 bool Gcalc_dyn_list::alloc_new_blk()
70 void *new_block= my_malloc(m_blk_size, MYF(MY_WME));
73 *m_blk_hook= new_block;
74 m_blk_hook= (
void**)new_block;
75 format_blk(new_block);
80 static void free_blk_list(
void *list)
85 next_blk= *((
void **)list);
92 void Gcalc_dyn_list::cleanup()
95 free_blk_list(m_first_blk);
97 m_blk_hook= &m_first_blk;
102 Gcalc_dyn_list::~Gcalc_dyn_list()
108 void Gcalc_dyn_list::reset()
113 free_blk_list(*((
void **)m_first_blk));
114 m_blk_hook= (
void**)m_first_blk;
116 format_blk(m_first_blk);
125 DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node));
126 if (node->left == prev_node)
127 node->left= node->right;
134 if (p->left && (p->left->y != p->y))
136 if (p->right && (p->right->y != p->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;
147 static int compare_point_info(
const void *e0,
const void *e1)
152 return i0->y > i1->y;
153 double i0_fd= find_first_different(i0);
154 double i1_fd= find_first_different(i1);
156 return i0_fd > i1_fd;
157 return i0->x > i1->x;
162 void Gcalc_heap::Info::dbug_print()
const
164 char left_str[64]=
"", right_str[64]=
"";
166 my_snprintf(left_str,
sizeof(left_str),
167 "(%g,%g,#%u)", left->x, left->y, left->shape);
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));
177 void Gcalc_heap::prepare_operation()
179 DBUG_ENTER(
"Gcalc_heap::prepare_operation");
180 DBUG_PRINT(
"info", (
"m_n_points=%d", m_n_points));
183 m_first= sort_list(compare_point_info, m_first, m_n_points);
186 DBUG_PRINT(
"info", (
"after sort_list:"));
188 for (Info *cur= get_first(); cur; cur= cur->get_next())
190 trim_node(cur->left, cur);
191 trim_node(cur->right, cur);
200 void Gcalc_heap::reset()
205 for (; *m_hook; m_hook= &(*m_hook)->next)
215 int Gcalc_shape_transporter::int_single_point(gcalc_shape_info Info,
221 point->left= point->right= 0;
226 int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info,
230 if (!(point= m_heap->new_point_info(x, y, Info)))
235 point->right= m_prev;
244 void Gcalc_shape_transporter::int_complete()
246 DBUG_ASSERT(m_shape_started == 1 || m_shape_started == 3);
252 if (m_first == m_prev)
254 m_first->right= m_first->left= NULL;
259 if (m_shape_started == 1)
261 m_first->right= NULL;
262 m_prev->left= m_prev->right;
268 m_first->right= m_prev;
269 m_prev->left= m_first;
273 inline int GET_DX_DY(
double *dxdy,
276 double dy= p1->y - p0->y;
277 *dxdy= p1->x - p0->x;
278 return (dy == 0.0) ||
279 (*dxdy/= dy)>DBL_MAX ||
283 Gcalc_scan_iterator::Gcalc_scan_iterator(
size_t blk_size) :
285 (sizeof(point) > sizeof(intersection)) ?
286 sizeof(point) : sizeof(intersection)),
287 m_slice0(NULL), m_slice1(NULL)
297 *result_hook= new_slice_point();
298 result_hook= &(*result_hook)->next;
299 example= example->get_next();
302 point *result=
static_cast<point*
>(item_result);
307 void Gcalc_scan_iterator::init(
Gcalc_heap *points)
309 DBUG_ASSERT(points->ready());
310 DBUG_ASSERT(!m_slice0 && !m_slice1);
312 if (!(m_cur_pi= points->get_first()))
316 m_intersections= NULL;
317 m_cur_intersection= NULL;
319 m_next_is_top_point=
true;
320 m_bottom_points_count= 0;
323 void Gcalc_scan_iterator::reset()
329 m_slice0= m_slice1= NULL;
330 Gcalc_dyn_list::reset();
336 if (p0->horiz_dir == p1->horiz_dir)
337 return p0->dx_dy <= p1->dx_dy;
339 return p0->dx_dy < 0;
340 return p1->dx_dy > 0;
348 return p0->x < p1->x;
349 return slice_first_equal_x(p0, p1);
353 int Gcalc_scan_iterator::insert_top_point()
355 point *sp0= new_slice_point();
360 sp0->next_pi= m_cur_pi->left;
361 sp0->thread= m_cur_thread++;
362 sp0->x= coord_to_float(m_cur_pi->x);
365 sp0->horiz_dir= GET_DX_DY(&sp0->dx_dy, m_cur_pi, m_cur_pi->left);
366 m_event1= scev_thread;
369 point *sp1= new_slice_point();
377 m_event1= scev_single_point;
387 point **prev_hook= &m_slice1;
388 for (; sp && slice_first(sp, sp0); sp=sp->get_next())
390 prev_hook=
reinterpret_cast<point**
>(&(sp->next));
395 m_event1= scev_two_threads;
397 point *sp1= new_slice_point();
401 sp1->next_pi= m_cur_pi->right;
402 sp1->thread= m_cur_thread++;
404 sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->right);
406 if (slice_first_equal_x(sp1, sp0))
416 if (!(sp1= new_slice_point()))
425 m_event_position1= sp0;
432 intersection_normal= 1,
433 intersection_forced= 2
439 unsigned int bottom_points_count)
442 return intersection_normal;
443 if (sp1->is_bottom() && !sp0->is_bottom() &&
444 (bottom_points_count > 1))
445 return intersection_forced;
451 const char *Gcalc_scan_event_name(
enum Gcalc_scan_events
event)
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";
463 return "scev_unknown";
467 void Gcalc_scan_iterator::point::dbug_print_slice(
double y,
468 enum Gcalc_scan_events event)
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())
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));
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));
489 int Gcalc_scan_iterator::normal_scan()
491 if (m_next_is_top_point)
492 if (insert_top_point())
496 m_slice1->dbug_print_slice(m_y1, m_event1);
499 point *tmp= m_slice0;
503 m_event_position0= m_event_position1;
506 if (!(m_cur_pi= m_cur_pi->get_next()))
514 m_y1= coord_to_float(cur_pi->y);
517 point *sp0= m_slice0;
518 point *sp1= m_slice1;
519 point *prev_sp1= NULL;
521 m_bottom_points_count= 0;
522 m_next_is_top_point=
true;
523 bool intersections_found=
false;
525 for (; sp0; sp0= sp0->get_next())
527 if (sp0->next_pi == cur_pi)
529 sp1->x= coord_to_float(cur_pi->x);
531 sp1->thread= sp0->thread;
532 sp1->next_pi= cur_pi->left;
534 sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->left);
536 m_next_is_top_point=
false;
538 if (sp1->is_bottom())
540 ++m_bottom_points_count;
541 if (m_bottom_points_count == 1)
544 m_event_position1= sp1;
547 m_event1= scev_two_ends;
551 m_event1= scev_point;
552 m_event_position1= sp1;
555 else if (!sp0->is_bottom())
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);
566 intersections_found= intersections_found ||
567 (prev_sp1 && intersection_found(prev_sp1, sp1, m_bottom_points_count));
570 sp1= sp1->get_next();
576 prev_sp1->next= NULL;
582 if (intersections_found)
583 return handle_intersections();
589 int Gcalc_scan_iterator::add_intersection(
const point *a,
const point *b,
592 intersection *isc= new_intersection();
599 isc->thread_a= a->thread;
600 isc->thread_b= b->thread;
601 if (isc_kind == intersection_forced)
609 const point *a0= a->precursor;
610 const point *b0= b->precursor;
611 if (!a0->horiz_dir && !b0->horiz_dir)
613 double dk= a0->dx_dy - b0->dx_dy;
614 double dy= (b0->x - a0->x)/dk;
616 isc->x= a0->x + dy*a0->dx_dy;
620 isc->x= a0->horiz_dir ? b->x : a->x;
625 int Gcalc_scan_iterator::find_intersections()
627 point *sp1= m_slice1;
629 m_n_intersections= 0;
632 point *sp0= m_slice0;
633 for (; sp1; sp0= sp0->get_next(),sp1= sp1->get_next())
635 while (sp0->is_bottom())
636 sp0= sp0->get_next();
637 DBUG_ASSERT(sp0->thread == sp1->thread);
644 bool intersections_found;
646 point *last_possible_isc= NULL;
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();
655 point *cur_possible_isc= NULL;
656 for (; sp1 != last_possible_isc;
657 pprev_s1= (point **)(&(*pprev_s1)->next), sp1= sp1->get_next())
659 if (sp1->is_bottom())
660 ++bottom_points_count;
661 if (!(isc_kind=intersection_found(*pprev_s1, sp1, bottom_points_count)))
663 point *prev_s1= *pprev_s1;
664 intersections_found=
true;
665 if (add_intersection(prev_s1, sp1, isc_kind, &hook))
668 prev_s1->next= sp1->next;
671 cur_possible_isc= sp1;
673 last_possible_isc= cur_possible_isc;
674 }
while (intersections_found);
681 static int compare_intersections(
const void *e0,
const void *e1)
685 return i0->y > i1->y;
689 inline void Gcalc_scan_iterator::sort_intersections()
691 m_intersections= (intersection *)sort_list(compare_intersections,
692 m_intersections,m_n_intersections);
696 int Gcalc_scan_iterator::handle_intersections()
698 DBUG_ASSERT(m_slice1->next);
700 if (find_intersections())
702 sort_intersections();
704 m_sav_slice= m_slice1;
706 m_slice1= new_slice(m_sav_slice);
708 m_cur_intersection= m_intersections;
709 m_pre_intersection_hook= NULL;
710 return intersection_scan();
714 void Gcalc_scan_iterator::pop_suitable_intersection()
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())
720 point *prev_p= m_slice0;
721 point *sp= prev_p->get_next();
722 for (; sp; prev_p= sp, sp= sp->get_next())
724 if ((prev_p->thread == cur_i->thread_a) &&
725 (sp->thread == cur_i->thread_b))
728 if (prev_i == m_cur_intersection)
730 m_cur_intersection->next= cur_i->next;
731 cur_i->next= m_cur_intersection;
732 m_cur_intersection= cur_i;
737 m_cur_intersection->next= cur_i->next;
738 prev_i->next= m_cur_intersection;
739 m_cur_intersection= cur_i;
750 int Gcalc_scan_iterator::intersection_scan()
752 if (m_pre_intersection_hook)
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;
764 m_cur_intersection= m_cur_intersection->get_next();
765 if (!m_cur_intersection)
770 m_slice1= m_sav_slice;
771 free_list(m_intersections);
776 m_y1= m_cur_intersection->y;
785 for (; sp0; sp0= sp0->get_next())
788 if (sp0->thread == m_cur_intersection->thread_a)
793 next_s0= next_s0->get_next();
794 while(next_s0->is_bottom());
797 if (next_s0->thread != m_cur_intersection->thread_b)
803 pop_suitable_intersection();
806 m_pre_intersection_hook= psp1;
808 sp1->x= m_cur_intersection->x;
810 sp1= sp1->get_next();
812 sp1->x= m_cur_intersection->x;
813 psp1= (point **)&sp1->next;
816 if (!sp0->is_bottom())
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);
826 psp1= (point **)&sp1->next;