1 /* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
2    Copyright (C) 2011 Monty Program Ab.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
16 
17 
18 #include "mariadb.h"
19 #include <my_sys.h>
20 #include <m_string.h>
21 
22 #ifdef HAVE_SPATIAL
23 
24 #include "gcalc_slicescan.h"
25 
26 
27 #define PH_DATA_OFFSET 8
28 #define coord_to_float(d) ((double) d)
29 #define coord_eq(a, b) (a == b)
30 
31 typedef int (*sc_compare_func)(const void*, const void*);
32 
33 #define LS_LIST_ITEM Gcalc_dyn_list::Item
34 #define LS_COMPARE_FUNC_DECL sc_compare_func compare,
35 #define LS_COMPARE_FUNC_CALL(list_el1, list_el2) (*compare)(list_el1, list_el2)
36 #define LS_NEXT(A) (A)->next
37 #define LS_SET_NEXT(A,val) (A)->next= val
38 #define LS_P_NEXT(A) &(A)->next
39 #define LS_NAME sort_list
40 #define LS_SCOPE static
41 #define LS_STRUCT_NAME sort_list_stack_struct
42 #include "plistsort.c"
43 
44 
45 #define GCALC_COORD_MINUS     0x80000000
46 #define FIRST_DIGIT(d) ((d) & 0x7FFFFFFF)
47 #define GCALC_SIGN(d)  ((d) & 0x80000000)
48 
eq_sp(const Gcalc_heap::Info * pi)49 static Gcalc_scan_iterator::point *eq_sp(const Gcalc_heap::Info *pi)
50 {
51   GCALC_DBUG_ASSERT(pi->type == Gcalc_heap::nt_eq_node);
52   return (Gcalc_scan_iterator::point *) pi->node.eq.data;
53 }
54 
55 
i_data(const Gcalc_heap::Info * pi)56 static Gcalc_scan_iterator::intersection_info *i_data(const Gcalc_heap::Info *pi)
57 {
58   GCALC_DBUG_ASSERT(pi->type == Gcalc_heap::nt_intersection);
59   return (Gcalc_scan_iterator::intersection_info *) pi->node.intersection.data;
60 }
61 
62 
63 #ifndef GCALC_DBUG_OFF
64 
65 int gcalc_step_counter= 0;
66 
GCALC_DBUG_CHECK_COUNTER()67 void GCALC_DBUG_CHECK_COUNTER()
68 {
69   if (++gcalc_step_counter == 0)
70     GCALC_DBUG_PRINT(("step_counter_0"));
71   else
72     GCALC_DBUG_PRINT(("%d step_counter", gcalc_step_counter));
73 }
74 
75 
gcalc_ev_name(int ev)76 const char *gcalc_ev_name(int ev)
77 {
78   switch (ev)
79   {
80     case scev_none:
81       return "n";
82     case scev_thread:
83       return "t";
84     case scev_two_threads:
85       return "tt";
86     case scev_end:
87       return "e";
88     case scev_two_ends:
89       return "ee";
90     case scev_intersection:
91       return "i";
92     case scev_point:
93       return "p";
94     case scev_single_point:
95       return "sp";
96     default:;
97   };
98   GCALC_DBUG_ASSERT(0);
99   return "unk";
100 }
101 
102 
gcalc_pi_str(char * str,const Gcalc_heap::Info * pi,const char * postfix)103 static int gcalc_pi_str(char *str, const Gcalc_heap::Info *pi, const char *postfix)
104 {
105   return sprintf(str, "%s %d %d | %s %d %d%s",
106                      GCALC_SIGN(pi->node.shape.ix[0]) ? "-":"", FIRST_DIGIT(pi->node.shape.ix[0]),pi->node.shape.ix[1],
107                      GCALC_SIGN(pi->node.shape.iy[0]) ? "-":"", FIRST_DIGIT(pi->node.shape.iy[0]),pi->node.shape.iy[1],
108                      postfix);
109 
110 }
111 
112 
GCALC_DBUG_PRINT_PI(const Gcalc_heap::Info * pi)113 static void GCALC_DBUG_PRINT_PI(const Gcalc_heap::Info *pi)
114 {
115   char buf[128];
116   int n_buf;
117   if (pi->type == Gcalc_heap::nt_intersection)
118   {
119     const Gcalc_scan_iterator::intersection_info *ic= i_data(pi);
120 
121     GCALC_DBUG_PRINT(("intersection point %d %d",
122                       ic->edge_a->thread, ic->edge_b->thread));
123     return;
124   }
125   if (pi->type == Gcalc_heap::nt_eq_node)
126   {
127     const Gcalc_scan_iterator::point *e= eq_sp(pi);
128     GCALC_DBUG_PRINT(("eq point %d", e->thread));
129     return;
130   }
131   n_buf= gcalc_pi_str(buf, pi, "");
132   buf[n_buf]= 0;
133   GCALC_DBUG_PRINT(("%s", buf));
134 }
135 
136 
GCALC_DBUG_PRINT_SLICE(const char * header,const Gcalc_scan_iterator::point * slice)137 static void GCALC_DBUG_PRINT_SLICE(const char *header,
138                                    const Gcalc_scan_iterator::point *slice)
139 {
140   size_t nbuf;
141   char buf[1024];
142   nbuf= strlen(header);
143   strcpy(buf, header);
144   for (; slice; slice= slice->get_next())
145   {
146     size_t lnbuf= nbuf;
147     lnbuf+= sprintf(buf + lnbuf, "%d\t", slice->thread);
148     lnbuf+= sprintf(buf + lnbuf, "%s\t", gcalc_ev_name(slice->event));
149 
150     lnbuf+= gcalc_pi_str(buf + lnbuf, slice->pi, "\t");
151     if (slice->is_bottom())
152       lnbuf+= sprintf(buf+lnbuf, "bt\t");
153     else
154       lnbuf+= gcalc_pi_str(buf+lnbuf, slice->next_pi, "\t");
155     buf[lnbuf]= 0;
156     GCALC_DBUG_PRINT(("%s", buf));
157   }
158 }
159 
160 
161 #else
162 #define GCALC_DBUG_CHECK_COUNTER()              do { } while(0)
163 #define GCALC_DBUG_PRINT_PI(pi)                 do { } while(0)
164 #define GCALC_DBUG_PRINT_SLICE(a, b)            do { } while(0)
165 #define GCALC_DBUG_PRINT_INTERSECTIONS(a)       do { } while(0)
166 #define GCALC_DBUG_PRINT_STATE(a)               do { } while(0)
167 #endif /*GCALC_DBUG_OFF*/
168 
169 
Gcalc_dyn_list(size_t blk_size,size_t sizeof_item)170 Gcalc_dyn_list::Gcalc_dyn_list(size_t blk_size, size_t sizeof_item):
171   m_blk_size(blk_size - ALLOC_ROOT_MIN_BLOCK_SIZE),
172   m_sizeof_item(ALIGN_SIZE(sizeof_item)),
173   m_points_per_blk((uint)((m_blk_size - PH_DATA_OFFSET) / m_sizeof_item)),
174   m_blk_hook(&m_first_blk),
175   m_free(NULL),
176   m_keep(NULL)
177 {}
178 
179 
Gcalc_dyn_list(const Gcalc_dyn_list & dl)180 Gcalc_dyn_list::Gcalc_dyn_list(const Gcalc_dyn_list &dl)
181 {
182   m_blk_size= dl.m_blk_size;
183   m_sizeof_item= dl.m_sizeof_item;
184   m_points_per_blk= dl.m_points_per_blk;
185   m_blk_hook= &m_first_blk;
186   m_free= NULL;
187   m_keep= NULL;
188 }
189 
190 
format_blk(void * block)191 void Gcalc_dyn_list::format_blk(void* block)
192 {
193   Item *pi_end, *cur_pi, *first_pi;
194   GCALC_DBUG_ASSERT(m_free == NULL);
195   first_pi= cur_pi= (Item *)(((char *)block) + PH_DATA_OFFSET);
196   pi_end= ptr_add(first_pi, m_points_per_blk - 1);
197   do {
198     cur_pi= cur_pi->next= ptr_add(cur_pi, 1);
199   } while (cur_pi<pi_end);
200   cur_pi->next= m_free;
201   m_free= first_pi;
202 }
203 
204 
alloc_new_blk()205 Gcalc_dyn_list::Item *Gcalc_dyn_list::alloc_new_blk()
206 {
207   void *new_block= my_malloc(PSI_INSTRUMENT_ME, m_blk_size, MYF(MY_WME));
208   if (!new_block)
209     return NULL;
210   *m_blk_hook= new_block;
211   m_blk_hook= (void**)new_block;
212   format_blk(new_block);
213   return new_item();
214 }
215 
216 
free_blk_list(void * list)217 static void free_blk_list(void *list)
218 {
219   void *next_blk;
220   while (list)
221   {
222     next_blk= *((void **)list);
223     my_free(list);
224     list= next_blk;
225   }
226 }
227 
228 
cleanup()229 void Gcalc_dyn_list::cleanup()
230 {
231   *m_blk_hook= NULL;
232   free_blk_list(m_first_blk);
233   m_first_blk= NULL;
234   m_blk_hook= &m_first_blk;
235   m_free= NULL;
236 }
237 
238 
~Gcalc_dyn_list()239 Gcalc_dyn_list::~Gcalc_dyn_list()
240 {
241   cleanup();
242 }
243 
244 
reset()245 void Gcalc_dyn_list::reset()
246 {
247   *m_blk_hook= NULL;
248   if (m_first_blk)
249   {
250     free_blk_list(*((void **)m_first_blk));
251     m_blk_hook= (void**)m_first_blk;
252     m_free= NULL;
253     format_blk(m_first_blk);
254   }
255 }
256 
257 
258 /* Internal coordinate operations implementations */
259 
gcalc_set_zero(Gcalc_internal_coord * d,int d_len)260 void gcalc_set_zero(Gcalc_internal_coord *d, int d_len)
261 {
262   do
263   {
264     d[--d_len]= 0;
265   } while (d_len);
266 }
267 
268 
gcalc_is_zero(const Gcalc_internal_coord * d,int d_len)269 int gcalc_is_zero(const Gcalc_internal_coord *d, int d_len)
270 {
271   do
272   {
273     if (d[--d_len] != 0)
274       return 0;
275   } while (d_len);
276   return 1;
277 }
278 
279 
280 #ifdef GCALC_CHECK_WITH_FLOAT
281 static double *gcalc_coord_extent= NULL;
282 
gcalc_get_double(const Gcalc_internal_coord * d,int d_len)283 long double gcalc_get_double(const Gcalc_internal_coord *d, int d_len)
284 {
285   int n= 1;
286   long double res= (long double) FIRST_DIGIT(d[0]);
287   do
288   {
289     res*= (long double) GCALC_DIG_BASE;
290     res+= (long double) d[n];
291   } while(++n < d_len);
292 
293   n= 0;
294   do
295   {
296     if ((n & 1) && gcalc_coord_extent)
297       res/= *gcalc_coord_extent;
298   } while(++n < d_len);
299 
300   if (GCALC_SIGN(d[0]))
301     res*= -1.0;
302   return res;
303 }
304 #endif /*GCALC_CHECK_WITH_FLOAT*/
305 
306 
do_add(Gcalc_internal_coord * result,int result_len,const Gcalc_internal_coord * a,const Gcalc_internal_coord * b)307 static void do_add(Gcalc_internal_coord *result, int result_len,
308                    const Gcalc_internal_coord *a,
309                    const Gcalc_internal_coord *b)
310 {
311   int n_digit= result_len-1;
312   gcalc_digit_t carry= 0;
313 
314   do
315   {
316     if ((result[n_digit]=
317           a[n_digit] + b[n_digit] + carry) >= GCALC_DIG_BASE)
318     {
319       carry= 1;
320       result[n_digit]-= GCALC_DIG_BASE;
321     }
322     else
323       carry= 0;
324   } while (--n_digit);
325 
326   result[0]= (a[0] + FIRST_DIGIT(b[0]) + carry);
327 
328   GCALC_DBUG_ASSERT(FIRST_DIGIT(result[0]) < GCALC_DIG_BASE);
329 }
330 
331 
do_sub(Gcalc_internal_coord * result,int result_len,const Gcalc_internal_coord * a,const Gcalc_internal_coord * b)332 static void do_sub(Gcalc_internal_coord *result, int result_len,
333                    const Gcalc_internal_coord *a,
334                    const Gcalc_internal_coord *b)
335 {
336   int n_digit= result_len-1;
337   gcalc_digit_t carry= 0;
338   gcalc_digit_t cur_b, cur_a;
339 
340   do
341   {
342     cur_b= b[n_digit] + carry;
343     cur_a= a[n_digit];
344     if (cur_a < cur_b)
345     {
346       carry= 1;
347       result[n_digit]= (GCALC_DIG_BASE - cur_b) + cur_a;
348     }
349     else
350     {
351       carry= 0;
352       result[n_digit]= cur_a - cur_b;
353     }
354   } while (--n_digit);
355 
356 
357   result[0]= a[0] - FIRST_DIGIT(b[0]) - carry;
358 
359   GCALC_DBUG_ASSERT(FIRST_DIGIT(a[0]) >= FIRST_DIGIT(b[0]) + carry);
360   GCALC_DBUG_ASSERT(!gcalc_is_zero(result, result_len));
361 }
362 /*
363 static void do_sub(Gcalc_internal_coord *result, int result_len,
364                    const Gcalc_internal_coord *a,
365                    const Gcalc_internal_coord *b)
366 {
367   int n_digit= result_len-1;
368   gcalc_digit_t carry= 0;
369 
370   do
371   {
372     if ((result[n_digit]= a[n_digit] - b[n_digit] - carry) < 0)
373     {
374       carry= 1;
375       result[n_digit]+= GCALC_DIG_BASE;
376     }
377     else
378       carry= 0;
379   } while (--n_digit);
380 
381 
382   result[0]= a[0] - FIRST_DIGIT(b[0]) - carry;
383 
384   GCALC_DBUG_ASSERT(FIRST_DIGIT(a[0]) - FIRST_DIGIT(b[0]) - carry >= 0);
385   GCALC_DBUG_ASSERT(!gcalc_is_zero(result, result_len));
386 }
387 */
388 
do_cmp(const Gcalc_internal_coord * a,const Gcalc_internal_coord * b,int len)389 static int do_cmp(const Gcalc_internal_coord *a,
390                   const Gcalc_internal_coord *b, int len)
391 {
392   int n_digit= 1;
393 
394   if ((FIRST_DIGIT(a[0]) != FIRST_DIGIT(b[0])))
395     return FIRST_DIGIT(a[0]) > FIRST_DIGIT(b[0]) ? 1 : -1;
396 
397   do
398   {
399     if ((a[n_digit] != b[n_digit]))
400       return a[n_digit] > b[n_digit] ? 1 : -1;
401   } while (++n_digit < len);
402 
403   return 0;
404 }
405 
406 
407 #ifdef GCALC_CHECK_WITH_FLOAT
de_weak_check(long double a,long double b,long double ex)408 static int de_weak_check(long double a, long double b, long double ex)
409 {
410   long double d= a - b;
411   if (d < ex && d > -ex)
412     return 1;
413 
414   d/= fabsl(a) + fabsl(b);
415   if (d < ex && d > -ex)
416     return 1;
417   return 0;
418 }
419 
de_check(long double a,long double b)420 static int de_check(long double a, long double b)
421 {
422   return de_weak_check(a, b, (long double) 1e-9);
423 }
424 #endif /*GCALC_CHECK_WITH_FLOAT*/
425 
426 
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)427 void gcalc_mul_coord(Gcalc_internal_coord *result, int result_len,
428                      const Gcalc_internal_coord *a, int a_len,
429                      const Gcalc_internal_coord *b, int b_len)
430 {
431   GCALC_DBUG_ASSERT(result_len == a_len + b_len);
432   GCALC_DBUG_ASSERT(a_len >= b_len);
433   int n_a, n_b, n_res;
434   gcalc_digit_t carry= 0;
435 
436   gcalc_set_zero(result, result_len);
437 
438   n_a= a_len - 1;
439   do
440   {
441     gcalc_coord2 cur_a= n_a ? a[n_a] : FIRST_DIGIT(a[0]);
442     n_b= b_len - 1;
443     do
444     {
445       gcalc_coord2 cur_b= n_b ? b[n_b] : FIRST_DIGIT(b[0]);
446       gcalc_coord2 mul= cur_a * cur_b + carry + result[n_a + n_b + 1];
447       result[n_a + n_b + 1]= mul % GCALC_DIG_BASE;
448       carry= (gcalc_digit_t) (mul / (gcalc_coord2) GCALC_DIG_BASE);
449     } while (n_b--);
450     if (carry)
451     {
452       for (n_res= n_a; (result[n_res]+= carry) >= GCALC_DIG_BASE;
453            n_res--)
454       {
455         result[n_res]-= GCALC_DIG_BASE;
456         carry= 1;
457       }
458       carry= 0;
459     }
460   } while (n_a--);
461   if (!gcalc_is_zero(result, result_len))
462     result[0]|= GCALC_SIGN(a[0] ^ b[0]);
463 #ifdef GCALC_CHECK_WITH_FLOAT
464   GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, a_len) *
465                                gcalc_get_double(b, b_len),
466                        gcalc_get_double(result, result_len)));
467 #endif /*GCALC_CHECK_WITH_FLOAT*/
468 }
469 
470 
gcalc_mul_coord1(Gcalc_coord1 result,const Gcalc_coord1 a,const Gcalc_coord1 b)471 inline void gcalc_mul_coord1(Gcalc_coord1 result,
472                              const Gcalc_coord1 a, const Gcalc_coord1 b)
473 {
474   return gcalc_mul_coord(result, GCALC_COORD_BASE2,
475                          a, GCALC_COORD_BASE, b, GCALC_COORD_BASE);
476 }
477 
478 
gcalc_add_coord(Gcalc_internal_coord * result,int result_len,const Gcalc_internal_coord * a,const Gcalc_internal_coord * b)479 void gcalc_add_coord(Gcalc_internal_coord *result, int result_len,
480                      const Gcalc_internal_coord *a,
481                      const Gcalc_internal_coord *b)
482 {
483   if (GCALC_SIGN(a[0]) == GCALC_SIGN(b[0]))
484     do_add(result, result_len, a, b);
485   else
486   {
487     int cmp_res= do_cmp(a, b, result_len);
488     if (cmp_res == 0)
489       gcalc_set_zero(result, result_len);
490     else if (cmp_res > 0)
491       do_sub(result, result_len, a, b);
492     else
493       do_sub(result, result_len, b, a);
494   }
495 #ifdef GCALC_CHECK_WITH_FLOAT
496   GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, result_len) +
497                                gcalc_get_double(b, result_len),
498                        gcalc_get_double(result, result_len)));
499 #endif /*GCALC_CHECK_WITH_FLOAT*/
500 }
501 
502 
gcalc_sub_coord(Gcalc_internal_coord * result,int result_len,const Gcalc_internal_coord * a,const Gcalc_internal_coord * b)503 void gcalc_sub_coord(Gcalc_internal_coord *result, int result_len,
504                      const Gcalc_internal_coord *a,
505                      const Gcalc_internal_coord *b)
506 {
507   if (GCALC_SIGN(a[0] ^ b[0]))
508     do_add(result, result_len, a, b);
509   else
510   {
511     int cmp_res= do_cmp(a, b, result_len);
512     if (cmp_res == 0)
513       gcalc_set_zero(result, result_len);
514     else if (cmp_res > 0)
515       do_sub(result, result_len, a, b);
516     else
517     {
518       do_sub(result, result_len, b, a);
519       result[0]^= GCALC_COORD_MINUS;
520     }
521   }
522 #ifdef GCALC_CHECK_WITH_FLOAT
523   GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, result_len) -
524                                gcalc_get_double(b, result_len),
525                        gcalc_get_double(result, result_len)));
526 #endif /*GCALC_CHECK_WITH_FLOAT*/
527 }
528 
529 
gcalc_sub_coord1(Gcalc_coord1 result,const Gcalc_coord1 a,const Gcalc_coord1 b)530 inline void gcalc_sub_coord1(Gcalc_coord1 result,
531                              const Gcalc_coord1 a, const Gcalc_coord1 b)
532 {
533   return gcalc_sub_coord(result, GCALC_COORD_BASE, a, b);
534 }
535 
536 
gcalc_cmp_coord(const Gcalc_internal_coord * a,const Gcalc_internal_coord * b,int len)537 int gcalc_cmp_coord(const Gcalc_internal_coord *a,
538                     const Gcalc_internal_coord *b, int len)
539 {
540   int n_digit= 0;
541   int result= 0;
542 
543   do
544   {
545     if (a[n_digit] == b[n_digit])
546     {
547       n_digit++;
548       continue;
549     }
550     if (a[n_digit] > b[n_digit])
551       result= GCALC_SIGN(a[0]) ? -1 : 1;
552     else
553       result= GCALC_SIGN(b[0]) ? 1 : -1;
554     break;
555 
556   } while (n_digit < len);
557 
558 #ifdef GCALC_CHECK_WITH_FLOAT
559   if (result == 0)
560     GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, len),
561                                  gcalc_get_double(b, len)));
562   else if (result == 1)
563     GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, len),
564                                  gcalc_get_double(b, len)) ||
565                 gcalc_get_double(a, len) > gcalc_get_double(b, len));
566   else
567     GCALC_DBUG_ASSERT(de_check(gcalc_get_double(a, len),
568                                  gcalc_get_double(b, len)) ||
569                 gcalc_get_double(a, len) < gcalc_get_double(b, len));
570 #endif /*GCALC_CHECK_WITH_FLOAT*/
571   return result;
572 }
573 
574 
575 #define gcalc_cmp_coord1(a, b) gcalc_cmp_coord(a, b, GCALC_COORD_BASE)
576 
gcalc_set_double(Gcalc_internal_coord * c,double d,double ext)577 int gcalc_set_double(Gcalc_internal_coord *c, double d, double ext)
578 {
579   int sign;
580   double ds= d * ext;
581   if ((sign= ds < 0))
582     ds= -ds;
583   c[0]= (gcalc_digit_t) (ds / (double) GCALC_DIG_BASE);
584   c[1]= (gcalc_digit_t) (ds - ((double) c[0]) * (double) GCALC_DIG_BASE);
585   if (c[1] >= GCALC_DIG_BASE)
586   {
587     c[1]= 0;
588     c[0]++;
589   }
590   if (sign && (c[0] | c[1]))
591     c[0]|= GCALC_COORD_MINUS;
592 #ifdef GCALC_CHECK_WITH_FLOAT
593   GCALC_DBUG_ASSERT(de_check(d, gcalc_get_double(c, 2)));
594 #endif /*GCALC_CHECK_WITH_FLOAT*/
595   return 0;
596 }
597 
598 
599 typedef gcalc_digit_t Gcalc_coord4[GCALC_COORD_BASE*4];
600 typedef gcalc_digit_t Gcalc_coord5[GCALC_COORD_BASE*5];
601 
602 
do_calc_t()603 void Gcalc_scan_iterator::intersection_info::do_calc_t()
604 {
605   Gcalc_coord1 a2_a1x, a2_a1y;
606   Gcalc_coord2 x1y2, x2y1;
607 
608   gcalc_sub_coord1(a2_a1x, edge_b->pi->node.shape.ix, edge_a->pi->node.shape.ix);
609   gcalc_sub_coord1(a2_a1y, edge_b->pi->node.shape.iy, edge_a->pi->node.shape.iy);
610 
611   GCALC_DBUG_ASSERT(!gcalc_is_zero(edge_a->dy, GCALC_COORD_BASE) ||
612                     !gcalc_is_zero(edge_b->dy, GCALC_COORD_BASE));
613 
614   gcalc_mul_coord1(x1y2, edge_a->dx, edge_b->dy);
615   gcalc_mul_coord1(x2y1, edge_a->dy, edge_b->dx);
616   gcalc_sub_coord(t_b, GCALC_COORD_BASE2, x1y2, x2y1);
617 
618 
619   gcalc_mul_coord1(x1y2, a2_a1x, edge_b->dy);
620   gcalc_mul_coord1(x2y1, a2_a1y, edge_b->dx);
621   gcalc_sub_coord(t_a, GCALC_COORD_BASE2, x1y2, x2y1);
622   t_calculated= 1;
623 }
624 
625 
do_calc_y()626 void Gcalc_scan_iterator::intersection_info::do_calc_y()
627 {
628   GCALC_DBUG_ASSERT(t_calculated);
629 
630   Gcalc_coord3 a_tb, b_ta;
631 
632   gcalc_mul_coord(a_tb, GCALC_COORD_BASE3,
633                   t_b, GCALC_COORD_BASE2, edge_a->pi->node.shape.iy, GCALC_COORD_BASE);
634   gcalc_mul_coord(b_ta, GCALC_COORD_BASE3,
635                   t_a, GCALC_COORD_BASE2, edge_a->dy, GCALC_COORD_BASE);
636 
637   gcalc_add_coord(y_exp, GCALC_COORD_BASE3, a_tb, b_ta);
638   y_calculated= 1;
639 }
640 
641 
do_calc_x()642 void Gcalc_scan_iterator::intersection_info::do_calc_x()
643 {
644   GCALC_DBUG_ASSERT(t_calculated);
645 
646   Gcalc_coord3 a_tb, b_ta;
647 
648   gcalc_mul_coord(a_tb, GCALC_COORD_BASE3,
649                   t_b, GCALC_COORD_BASE2, edge_a->pi->node.shape.ix, GCALC_COORD_BASE);
650   gcalc_mul_coord(b_ta, GCALC_COORD_BASE3,
651                   t_a, GCALC_COORD_BASE2, edge_a->dx, GCALC_COORD_BASE);
652 
653   gcalc_add_coord(x_exp, GCALC_COORD_BASE3, a_tb, b_ta);
654   x_calculated= 1;
655 }
656 
657 
cmp_node_isc(const Gcalc_heap::Info * node,const Gcalc_heap::Info * isc)658 static int cmp_node_isc(const Gcalc_heap::Info *node,
659                         const Gcalc_heap::Info *isc)
660 {
661   GCALC_DBUG_ASSERT(node->type == Gcalc_heap::nt_shape_node);
662   Gcalc_scan_iterator::intersection_info *inf= i_data(isc);
663   Gcalc_coord3 exp;
664   int result;
665 
666   inf->calc_t();
667   inf->calc_y_exp();
668 
669   gcalc_mul_coord(exp, GCALC_COORD_BASE3,
670                   inf->t_b, GCALC_COORD_BASE2, node->node.shape.iy, GCALC_COORD_BASE);
671 
672   result= gcalc_cmp_coord(exp, inf->y_exp, GCALC_COORD_BASE3);
673 #ifdef GCALC_CHECK_WITH_FLOAT
674   long double int_x, int_y;
675   isc->calc_xy_ld(&int_x, &int_y);
676   if (result < 0)
677   {
678     if (!de_check(int_y, node->node.shape.y) && node->node.shape.y > int_y)
679       GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g < %LG", node->node.shape.y, int_y));
680   }
681   else if (result > 0)
682   {
683     if (!de_check(int_y, node->node.shape.y) && node->node.shape.y < int_y)
684       GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g > %LG", node->node.shape.y, int_y));
685   }
686   else
687   {
688     if (!de_check(int_y, node->node.shape.y))
689       GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscy %g == %LG", node->node.shape.y, int_y));
690   }
691 #endif /*GCALC_CHECK_WITH_FLOAT*/
692   if (result)
693     goto exit;
694 
695 
696   inf->calc_x_exp();
697   gcalc_mul_coord(exp, GCALC_COORD_BASE3,
698                   inf->t_b, GCALC_COORD_BASE2, node->node.shape.ix, GCALC_COORD_BASE);
699 
700   result= gcalc_cmp_coord(exp, inf->x_exp, GCALC_COORD_BASE3);
701 #ifdef GCALC_CHECK_WITH_FLOAT
702   if (result < 0)
703   {
704     if (!de_check(int_x, node->node.shape.x) && node->node.shape.x > int_x)
705       GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g < %LG",
706                          node->node.shape.x, int_x));
707   }
708   else if (result > 0)
709   {
710     if (!de_check(int_x, node->node.shape.x) && node->node.shape.x < int_x)
711       GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g > %LG",
712                         node->node.shape.x, int_x));
713   }
714   else
715   {
716     if (!de_check(int_x, node->node.shape.x))
717       GCALC_DBUG_PRINT(("floatcheck cmp_nod_iscx failed %g == %LG",
718                         node->node.shape.x, int_x));
719   }
720 #endif /*GCALC_CHECK_WITH_FLOAT*/
721 exit:
722   return result;
723 }
724 
725 
cmp_intersections(const Gcalc_heap::Info * i1,const Gcalc_heap::Info * i2)726 static int cmp_intersections(const Gcalc_heap::Info *i1,
727                              const Gcalc_heap::Info *i2)
728 {
729   Gcalc_scan_iterator::intersection_info *inf1= i_data(i1);
730   Gcalc_scan_iterator::intersection_info *inf2= i_data(i2);
731   Gcalc_coord5 exp_a, exp_b;
732   int result;
733 
734   inf1->calc_t();
735   inf2->calc_t();
736 
737   inf1->calc_y_exp();
738   inf2->calc_y_exp();
739 
740   gcalc_mul_coord(exp_a, GCALC_COORD_BASE5,
741                   inf1->y_exp, GCALC_COORD_BASE3, inf2->t_b, GCALC_COORD_BASE2);
742   gcalc_mul_coord(exp_b, GCALC_COORD_BASE5,
743                   inf2->y_exp, GCALC_COORD_BASE3, inf1->t_b, GCALC_COORD_BASE2);
744 
745   result= gcalc_cmp_coord(exp_a, exp_b, GCALC_COORD_BASE5);
746 #ifdef GCALC_CHECK_WITH_FLOAT
747   long double x1, y1, x2, y2;
748   i1->calc_xy_ld(&x1, &y1);
749   i2->calc_xy_ld(&x2, &y2);
750 
751   if (result < 0)
752   {
753     if (!de_check(y1, y2) && y2 > y1)
754       GCALC_DBUG_PRINT(("floatcheck cmp_intersections_y failed %LG < %LG",
755                         y2, y1));
756   }
757   else if (result > 0)
758   {
759     if (!de_check(y1, y2) && y2 < y1)
760       GCALC_DBUG_PRINT(("floatcheck cmp_intersections_y failed %LG > %LG",
761                         y2, y1));
762   }
763   else
764   {
765     if (!de_check(y1, y2))
766       GCALC_DBUG_PRINT(("floatcheck cmp_intersections_y failed %LG == %LG",
767                         y2, y1));
768   }
769 #endif /*GCALC_CHECK_WITH_FLOAT*/
770 
771   if (result != 0)
772     return result;
773 
774 
775   inf1->calc_x_exp();
776   inf2->calc_x_exp();
777   gcalc_mul_coord(exp_a, GCALC_COORD_BASE5,
778                   inf1->x_exp, GCALC_COORD_BASE3, inf2->t_b, GCALC_COORD_BASE2);
779   gcalc_mul_coord(exp_b, GCALC_COORD_BASE5,
780                   inf2->x_exp, GCALC_COORD_BASE3, inf1->t_b, GCALC_COORD_BASE2);
781 
782   result= gcalc_cmp_coord(exp_a, exp_b, GCALC_COORD_BASE5);
783 #ifdef GCALC_CHECK_WITH_FLOAT
784   if (result < 0)
785   {
786     if (!de_check(x1, x2) && x2 > x1)
787       GCALC_DBUG_PRINT(("floatcheck cmp_intersectionsx failed %LG < %LG",
788                         x2, x1));
789   }
790   else if (result > 0)
791   {
792     if (!de_check(x1, x2) && x2 < x1)
793       GCALC_DBUG_PRINT(("floatcheck cmp_intersectionsx failed %LG > %LG",
794                         x2, x1));
795   }
796   else
797   {
798     if (!de_check(x1, x2))
799       GCALC_DBUG_PRINT(("floatcheck cmp_intersectionsx failed %LG == %LG",
800                         x2, x1));
801   }
802 #endif /*GCALC_CHECK_WITH_FLOAT*/
803   return result;
804 }
805 /* Internal coordinates implementation end */
806 
807 
808 #define GCALC_SCALE_1 1e18
809 
find_scale(double extent)810 static double find_scale(double extent)
811 {
812   double scale= 1e-2;
813   while (scale < extent)
814     scale*= (double ) 10;
815   return GCALC_SCALE_1 / scale / 10;
816 }
817 
818 
set_extent(double xmin,double xmax,double ymin,double ymax)819 void Gcalc_heap::set_extent(double xmin, double xmax, double ymin, double ymax)
820 {
821   xmin= fabs(xmin);
822   xmax= fabs(xmax);
823   ymin= fabs(ymin);
824   ymax= fabs(ymax);
825 
826   if (xmax < xmin)
827     xmax= xmin;
828   if (ymax < ymin)
829     ymax= ymin;
830 
831   coord_extent= xmax > ymax ? xmax : ymax;
832   coord_extent= find_scale(coord_extent);
833 #ifdef GCALC_CHECK_WITH_FLOAT
834   gcalc_coord_extent= &coord_extent;
835 #endif /*GCALC_CHECK_WITH_FLOAT*/
836 }
837 
838 
free_point_info(Gcalc_heap::Info * i,Gcalc_dyn_list::Item ** i_hook)839 void Gcalc_heap::free_point_info(Gcalc_heap::Info *i,
840                                  Gcalc_dyn_list::Item **i_hook)
841 {
842   if (m_hook == &i->next)
843     m_hook= i_hook;
844   *i_hook= i->next;
845   free_item(i);
846   m_n_points--;
847 }
848 
849 
new_point_info(double x,double y,gcalc_shape_info shape)850 Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y,
851                                              gcalc_shape_info shape)
852 {
853   Info *result= (Info *)new_item();
854   if (!result)
855     return NULL;
856   *m_hook= result;
857   m_hook= &result->next;
858   result->node.shape.x= x;
859   result->node.shape.y= y;
860   result->node.shape.shape= shape;
861   result->node.shape.top_node= 1;
862   result->type= nt_shape_node;
863   gcalc_set_double(result->node.shape.ix, x, coord_extent);
864   gcalc_set_double(result->node.shape.iy, y, coord_extent);
865 
866   m_n_points++;
867   return result;
868 }
869 
870 
new_intersection(Gcalc_heap * heap,Gcalc_scan_iterator::intersection_info * ii)871 static Gcalc_heap::Info *new_intersection(
872     Gcalc_heap *heap, Gcalc_scan_iterator::intersection_info *ii)
873 {
874   Gcalc_heap::Info *isc= (Gcalc_heap::Info *)heap->new_item();
875   if (!isc)
876     return 0;
877   isc->type= Gcalc_heap::nt_intersection;
878   isc->node.intersection.p1= ii->edge_a->pi;
879   isc->node.intersection.p2= ii->edge_a->next_pi;
880   isc->node.intersection.p3= ii->edge_b->pi;
881   isc->node.intersection.p4= ii->edge_b->next_pi;
882   isc->node.intersection.data= ii;
883   return isc;
884 }
885 
886 
new_eq_point(Gcalc_heap * heap,const Gcalc_heap::Info * p,Gcalc_scan_iterator::point * edge)887 static Gcalc_heap::Info *new_eq_point(
888     Gcalc_heap *heap, const Gcalc_heap::Info *p,
889     Gcalc_scan_iterator::point *edge)
890 {
891   Gcalc_heap::Info *eqp= (Gcalc_heap::Info *)heap->new_item();
892   if (!eqp)
893     return 0;
894   eqp->type= Gcalc_heap::nt_eq_node;
895   eqp->node.eq.node= p;
896   eqp->node.eq.data= edge;
897   return eqp;
898 }
899 
900 
calc_xy(double * x,double * y) const901 void Gcalc_heap::Info::calc_xy(double *x, double *y) const
902 {
903   double b0_x= node.intersection.p2->node.shape.x - node.intersection.p1->node.shape.x;
904   double b0_y= node.intersection.p2->node.shape.y - node.intersection.p1->node.shape.y;
905   double b1_x= node.intersection.p4->node.shape.x - node.intersection.p3->node.shape.x;
906   double b1_y= node.intersection.p4->node.shape.y - node.intersection.p3->node.shape.y;
907   double b0xb1= b0_x * b1_y - b0_y * b1_x;
908   double t= (node.intersection.p3->node.shape.x - node.intersection.p1->node.shape.x) * b1_y - (node.intersection.p3->node.shape.y - node.intersection.p1->node.shape.y) * b1_x;
909 
910   t/= b0xb1;
911 
912   *x= node.intersection.p1->node.shape.x + b0_x * t;
913   *y= node.intersection.p1->node.shape.y + b0_y * t;
914 }
915 
916 
917 #ifdef GCALC_CHECK_WITH_FLOAT
calc_xy_ld(long double * x,long double * y) const918 void Gcalc_heap::Info::calc_xy_ld(long double *x, long double *y) const
919 {
920   long double b0_x= ((long double) p2->node.shape.x) - p1->node.shape.x;
921   long double b0_y= ((long double) p2->node.shape.y) - p1->node.shape.y;
922   long double b1_x= ((long double) p4->node.shape.x) - p3->node.shape.x;
923   long double b1_y= ((long double) p4->node.shape.y) - p3->node.shape.y;
924   long double b0xb1= b0_x * b1_y - b0_y * b1_x;
925   long double ax=   ((long double) p3->node.shape.x) - p1->node.shape.x;
926   long double ay=   ((long double) p3->node.shape.y) - p1->node.shape.y;
927   long double t_a= ax * b1_y - ay * b1_x;
928   long double hx= (b0xb1 * (long double) p1->node.shape.x + b0_x * t_a);
929   long double hy= (b0xb1 * (long double) p1->node.shape.y + b0_y * t_a);
930 
931   if (fabs(b0xb1) < 1e-15)
932   {
933     *x= p1->node.shape.x;
934     *y= p1->node.shape.y;
935     return;
936   }
937 
938   *x= hx/b0xb1;
939   *y= hy/b0xb1;
940 }
941 #endif /*GCALC_CHECK_WITH_FLOAT*/
942 
943 
cmp_point_info(const Gcalc_heap::Info * i0,const Gcalc_heap::Info * i1)944 static int cmp_point_info(const Gcalc_heap::Info *i0,
945                           const Gcalc_heap::Info *i1)
946 {
947   int cmp_y= gcalc_cmp_coord1(i0->node.shape.iy, i1->node.shape.iy);
948   if (cmp_y)
949     return cmp_y;
950   return gcalc_cmp_coord1(i0->node.shape.ix, i1->node.shape.ix);
951 }
952 
953 
trim_node(Gcalc_heap::Info * node,Gcalc_heap::Info * prev_node)954 static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node)
955 {
956   if (!node)
957     return;
958   node->node.shape.top_node= 0;
959   GCALC_DBUG_ASSERT((node->node.shape.left == prev_node) || (node->node.shape.right == prev_node));
960   if (node->node.shape.left == prev_node)
961     node->node.shape.left= node->node.shape.right;
962   node->node.shape.right= NULL;
963   GCALC_DBUG_ASSERT(cmp_point_info(node, prev_node));
964 }
965 
966 
compare_point_info(const void * e0,const void * e1)967 static int compare_point_info(const void *e0, const void *e1)
968 {
969   const Gcalc_heap::Info *i0= (const Gcalc_heap::Info *)e0;
970   const Gcalc_heap::Info *i1= (const Gcalc_heap::Info *)e1;
971   return cmp_point_info(i0, i1) > 0;
972 }
973 
974 
prepare_operation()975 void Gcalc_heap::prepare_operation()
976 {
977   Info *cur;
978   GCALC_DBUG_ASSERT(m_hook);
979   *m_hook= NULL;
980   m_hook= NULL; /* just to check it's not called twice */
981   m_first= sort_list(compare_point_info, m_first, m_n_points);
982 
983   /* TODO - move this to the 'normal_scan' loop */
984   for (cur= get_first(); cur; cur= cur->get_next())
985   {
986     trim_node(cur->node.shape.left, cur);
987     trim_node(cur->node.shape.right, cur);
988   }
989 }
990 
991 
reset()992 void Gcalc_heap::reset()
993 {
994   if (m_n_points)
995   {
996     if (m_hook)
997       *m_hook= NULL;
998     free_list(m_first);
999     m_n_points= 0;
1000   }
1001   m_hook= &m_first;
1002 }
1003 
1004 
int_single_point(gcalc_shape_info Info,double x,double y)1005 int Gcalc_shape_transporter::int_single_point(gcalc_shape_info Info,
1006                                               double x, double y)
1007 {
1008   Gcalc_heap::Info *point= m_heap->new_point_info(x, y, Info);
1009   if (!point)
1010     return 1;
1011   point->node.shape.left= point->node.shape.right= 0;
1012   return 0;
1013 }
1014 
1015 
int_add_point(gcalc_shape_info Info,double x,double y)1016 int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info,
1017                                            double x, double y)
1018 {
1019   Gcalc_heap::Info *point;
1020   Gcalc_dyn_list::Item **hook;
1021 
1022   hook= m_heap->get_cur_hook();
1023 
1024   if (!(point= m_heap->new_point_info(x, y, Info)))
1025     return 1;
1026   if (m_first)
1027   {
1028     if (cmp_point_info(m_prev, point) == 0)
1029     {
1030       /* Coinciding points, do nothing */
1031       m_heap->free_point_info(point, hook);
1032       return 0;
1033     }
1034     GCALC_DBUG_ASSERT(!m_prev || m_prev->node.shape.x != x || m_prev->node.shape.y != y);
1035     m_prev->node.shape.left= point;
1036     point->node.shape.right= m_prev;
1037   }
1038   else
1039     m_first= point;
1040   m_prev= point;
1041   m_prev_hook= hook;
1042   return 0;
1043 }
1044 
1045 
int_complete()1046 void Gcalc_shape_transporter::int_complete()
1047 {
1048   GCALC_DBUG_ASSERT(m_shape_started == 1 || m_shape_started == 3);
1049 
1050   if (!m_first)
1051     return;
1052 
1053   /* simple point */
1054   if (m_first == m_prev)
1055   {
1056     m_first->node.shape.right= m_first->node.shape.left= NULL;
1057     return;
1058   }
1059 
1060   /* line */
1061   if (m_shape_started == 1)
1062   {
1063     m_first->node.shape.right= NULL;
1064     m_prev->node.shape.left= m_prev->node.shape.right;
1065     m_prev->node.shape.right= NULL;
1066     return;
1067   }
1068 
1069   /* polygon */
1070   if (cmp_point_info(m_first, m_prev) == 0)
1071   {
1072     /* Coinciding points, remove the last one from the list */
1073     m_prev->node.shape.right->node.shape.left= m_first;
1074     m_first->node.shape.right= m_prev->node.shape.right;
1075     m_heap->free_point_info(m_prev, m_prev_hook);
1076   }
1077   else
1078   {
1079     GCALC_DBUG_ASSERT(m_prev->node.shape.x != m_first->node.shape.x || m_prev->node.shape.y != m_first->node.shape.y);
1080     m_first->node.shape.right= m_prev;
1081     m_prev->node.shape.left= m_first;
1082   }
1083 }
1084 
1085 
calc_dx_dy(Gcalc_scan_iterator::point * p)1086 inline void calc_dx_dy(Gcalc_scan_iterator::point *p)
1087 {
1088   gcalc_sub_coord1(p->dx, p->next_pi->node.shape.ix, p->pi->node.shape.ix);
1089   gcalc_sub_coord1(p->dy, p->next_pi->node.shape.iy, p->pi->node.shape.iy);
1090   if (GCALC_SIGN(p->dx[0]))
1091   {
1092     p->l_border= &p->next_pi->node.shape.ix;
1093     p->r_border= &p->pi->node.shape.ix;
1094   }
1095   else
1096   {
1097     p->r_border= &p->next_pi->node.shape.ix;
1098     p->l_border= &p->pi->node.shape.ix;
1099   }
1100 }
1101 
1102 
Gcalc_scan_iterator(size_t blk_size)1103 Gcalc_scan_iterator::Gcalc_scan_iterator(size_t blk_size) :
1104   Gcalc_dyn_list(blk_size, sizeof(point) > sizeof(intersection_info) ?
1105                              sizeof(point) :
1106                              sizeof(intersection_info))
1107 {
1108   state.slice= NULL;
1109   m_bottom_points= NULL;
1110   m_bottom_hook= &m_bottom_points;
1111 }
1112 
1113 
init(Gcalc_heap * points)1114 void Gcalc_scan_iterator::init(Gcalc_heap *points)
1115 {
1116   GCALC_DBUG_ASSERT(points->ready());
1117   GCALC_DBUG_ASSERT(!state.slice);
1118 
1119   if (!(m_cur_pi= points->get_first()))
1120     return;
1121   m_heap= points;
1122   state.event_position_hook= &state.slice;
1123   state.event_end= NULL;
1124 #ifndef GCALC_DBUG_OFF
1125   m_cur_thread= 0;
1126 #endif /*GCALC_DBUG_OFF*/
1127   GCALC_SET_TERMINATED(killed, 0);
1128 }
1129 
reset()1130 void Gcalc_scan_iterator::reset()
1131 {
1132   state.slice= NULL;
1133   m_bottom_points= NULL;
1134   m_bottom_hook= &m_bottom_points;
1135   Gcalc_dyn_list::reset();
1136 }
1137 
1138 
cmp_dx_dy(const Gcalc_coord1 dx_a,const Gcalc_coord1 dy_a,const Gcalc_coord1 dx_b,const Gcalc_coord1 dy_b)1139 int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_coord1 dx_a,
1140                                           const Gcalc_coord1 dy_a,
1141                                           const Gcalc_coord1 dx_b,
1142                                           const Gcalc_coord1 dy_b)
1143 {
1144   Gcalc_coord2 dx_a_dy_b;
1145   Gcalc_coord2 dy_a_dx_b;
1146   gcalc_mul_coord1(dx_a_dy_b, dx_a, dy_b);
1147   gcalc_mul_coord1(dy_a_dx_b, dy_a, dx_b);
1148 
1149   return gcalc_cmp_coord(dx_a_dy_b, dy_a_dx_b, GCALC_COORD_BASE2);
1150 }
1151 
1152 
cmp_dx_dy(const Gcalc_heap::Info * p1,const Gcalc_heap::Info * p2,const Gcalc_heap::Info * p3,const Gcalc_heap::Info * p4)1153 int Gcalc_scan_iterator::point::cmp_dx_dy(const Gcalc_heap::Info *p1,
1154                                           const Gcalc_heap::Info *p2,
1155                                           const Gcalc_heap::Info *p3,
1156                                           const Gcalc_heap::Info *p4)
1157 {
1158   Gcalc_coord1 dx_a, dy_a, dx_b, dy_b;
1159   gcalc_sub_coord1(dx_a, p2->node.shape.ix, p1->node.shape.ix);
1160   gcalc_sub_coord1(dy_a, p2->node.shape.iy, p1->node.shape.iy);
1161   gcalc_sub_coord1(dx_b, p4->node.shape.ix, p3->node.shape.ix);
1162   gcalc_sub_coord1(dy_b, p4->node.shape.iy, p3->node.shape.iy);
1163   return cmp_dx_dy(dx_a, dy_a, dx_b, dy_b);
1164 }
1165 
1166 
cmp_dx_dy(const point * p) const1167 int Gcalc_scan_iterator::point::cmp_dx_dy(const point *p) const
1168 {
1169   GCALC_DBUG_ASSERT(!is_bottom());
1170   return cmp_dx_dy(dx, dy, p->dx, p->dy);
1171 }
1172 
1173 
1174 #ifdef GCALC_CHECK_WITH_FLOAT
calc_x(long double * x,long double y,long double ix) const1175 void Gcalc_scan_iterator::point::calc_x(long double *x, long double y,
1176                                         long double ix) const
1177 {
1178   long double ddy= gcalc_get_double(dy, GCALC_COORD_BASE);
1179   if (fabsl(ddy) < (long double) 1e-20)
1180   {
1181     *x= ix;
1182   }
1183   else
1184     *x= (ddy * (long double) pi->node.shape.x + gcalc_get_double(dx, GCALC_COORD_BASE) *
1185           (y - pi->node.shape.y)) / ddy;
1186 }
1187 #endif /*GCALC_CHECK_WITH_FLOAT*/
1188 
1189 
compare_events(const void * e0,const void * e1)1190 static int compare_events(const void *e0, const void *e1)
1191 {
1192   const Gcalc_scan_iterator::point *p0= (const Gcalc_scan_iterator::point *)e0;
1193   const Gcalc_scan_iterator::point *p1= (const Gcalc_scan_iterator::point *)e1;
1194   return p0->cmp_dx_dy(p1) > 0;
1195 }
1196 
1197 
arrange_event(int do_sorting,int n_intersections)1198 int Gcalc_scan_iterator::arrange_event(int do_sorting, int n_intersections)
1199 {
1200   int ev_counter;
1201   point *sp;
1202   point **sp_hook;
1203 
1204   ev_counter= 0;
1205 
1206   *m_bottom_hook= NULL;
1207   for (sp= m_bottom_points; sp; sp= sp->get_next())
1208     sp->ev_next= sp->get_next();
1209 
1210   for (sp= state.slice, sp_hook= &state.slice;
1211        sp; sp_hook= sp->next_ptr(), sp= sp->get_next())
1212   {
1213     if (sp->event)
1214     {
1215       state.event_position_hook= sp_hook;
1216       break;
1217     }
1218   }
1219 
1220   for (sp= *(sp_hook= state.event_position_hook);
1221        sp && sp->event; sp_hook= sp->next_ptr(), sp= sp->get_next())
1222   {
1223     ev_counter++;
1224     if (sp->get_next() && sp->get_next()->event)
1225       sp->ev_next= sp->get_next();
1226     else
1227       sp->ev_next= m_bottom_points;
1228   }
1229 
1230 #ifndef GCALC_DBUG_OFF
1231   {
1232     point *cur_p= sp;
1233     for (; cur_p; cur_p= cur_p->get_next())
1234       GCALC_DBUG_ASSERT(!cur_p->event);
1235   }
1236 #endif /*GCALC_DBUG_OFF*/
1237 
1238   state.event_end= sp;
1239 
1240   if (ev_counter == 2 && n_intersections == 1)
1241   {
1242     /* If we had only intersection, just swap the two points. */
1243     sp= *state.event_position_hook;
1244     *state.event_position_hook= sp->get_next();
1245     sp->next= (*state.event_position_hook)->next;
1246     (*state.event_position_hook)->next= sp;
1247 
1248     /* The list of the events should be restored. */
1249     (*state.event_position_hook)->ev_next= sp;
1250     sp->ev_next= m_bottom_points;
1251   }
1252   else if (ev_counter == 2 && get_events()->event == scev_two_threads)
1253   {
1254     /* Do nothing. */
1255   }
1256   else if (ev_counter > 1 && do_sorting)
1257   {
1258     point *cur_p;
1259     *sp_hook= NULL;
1260     sp= (point *) sort_list(compare_events, *state.event_position_hook,
1261                             ev_counter);
1262     /* Find last item in the list, it's changed after the sorting. */
1263     for (cur_p= sp->get_next(); cur_p->get_next();
1264         cur_p= cur_p->get_next())
1265     {}
1266     cur_p->next= state.event_end;
1267     *state.event_position_hook= sp;
1268     /* The list of the events should be restored. */
1269     for (; sp && sp->event; sp= sp->get_next())
1270     {
1271       if (sp->get_next() && sp->get_next()->event)
1272         sp->ev_next= sp->get_next();
1273       else
1274         sp->ev_next= m_bottom_points;
1275     }
1276   }
1277 
1278 #ifndef GCALC_DBUG_OFF
1279   {
1280     const event_point *ev= get_events();
1281     for (; ev && ev->get_next(); ev= ev->get_next())
1282     {
1283       if (ev->is_bottom() || ev->get_next()->is_bottom())
1284         break;
1285       GCALC_DBUG_ASSERT(ev->cmp_dx_dy(ev->get_next()) <= 0);
1286     }
1287   }
1288 #endif /*GCALC_DBUG_OFF*/
1289   return 0;
1290 }
1291 
1292 
equal_pi(const Info * pi) const1293 int Gcalc_heap::Info::equal_pi(const Info *pi) const
1294 {
1295   if (type == nt_intersection)
1296     return node.intersection.equal;
1297   if (pi->type == nt_eq_node)
1298     return 1;
1299   if (type == nt_eq_node || pi->type == nt_intersection)
1300     return 0;
1301   return cmp_point_info(this, pi) == 0;
1302 }
1303 
step()1304 int Gcalc_scan_iterator::step()
1305 {
1306   int result= 0;
1307   int do_sorting= 0;
1308   int n_intersections= 0;
1309   point *sp;
1310   GCALC_DBUG_ENTER("Gcalc_scan_iterator::step");
1311   GCALC_DBUG_ASSERT(more_points());
1312 
1313   if (GCALC_TERMINATED(killed))
1314     GCALC_DBUG_RETURN(0xFFFF);
1315 
1316   /* Clear the old event marks. */
1317   if (m_bottom_points)
1318   {
1319     free_list((Gcalc_dyn_list::Item **) &m_bottom_points,
1320               (Gcalc_dyn_list::Item **) m_bottom_hook);
1321     m_bottom_points= NULL;
1322     m_bottom_hook= &m_bottom_points;
1323   }
1324   for (sp= *state.event_position_hook;
1325        sp != state.event_end; sp= sp->get_next())
1326     sp->event= scev_none;
1327 
1328 //#ifndef GCALC_DBUG_OFF
1329   state.event_position_hook= NULL;
1330   state.pi= NULL;
1331 //#endif /*GCALC_DBUG_OFF*/
1332 
1333   do
1334   {
1335 #ifndef GCALC_DBUG_OFF
1336     if (m_cur_pi->type == Gcalc_heap::nt_intersection &&
1337         m_cur_pi->get_next()->type == Gcalc_heap::nt_intersection &&
1338         m_cur_pi->node.intersection.equal)
1339       GCALC_DBUG_ASSERT(cmp_intersections(m_cur_pi, m_cur_pi->get_next()) == 0);
1340 #endif /*GCALC_DBUG_OFF*/
1341     GCALC_DBUG_CHECK_COUNTER();
1342     GCALC_DBUG_PRINT_SLICE("step:", state.slice);
1343     GCALC_DBUG_PRINT_PI(m_cur_pi);
1344     if (m_cur_pi->type == Gcalc_heap::nt_shape_node)
1345     {
1346       if (m_cur_pi->is_top())
1347       {
1348         result= insert_top_node();
1349         if (!m_cur_pi->is_bottom())
1350           do_sorting++;
1351       }
1352       else if (m_cur_pi->is_bottom())
1353         remove_bottom_node();
1354       else
1355       {
1356         do_sorting++;
1357         result= node_scan();
1358       }
1359       if (result)
1360         GCALC_DBUG_RETURN(result);
1361       state.pi= m_cur_pi;
1362     }
1363     else if (m_cur_pi->type == Gcalc_heap::nt_eq_node)
1364     {
1365       do_sorting++;
1366       eq_scan();
1367     }
1368     else
1369     {
1370       /* nt_intersection */
1371       do_sorting++;
1372       n_intersections++;
1373       intersection_scan();
1374       if (!state.pi || state.pi->type == Gcalc_heap::nt_intersection)
1375         state.pi= m_cur_pi;
1376     }
1377 
1378     m_cur_pi= m_cur_pi->get_next();
1379   } while (m_cur_pi && state.pi->equal_pi(m_cur_pi));
1380 
1381   GCALC_DBUG_RETURN(arrange_event(do_sorting, n_intersections));
1382 }
1383 
1384 
node_on_right(const Gcalc_heap::Info * node,const Gcalc_heap::Info * edge_a,const Gcalc_heap::Info * edge_b)1385 static int node_on_right(const Gcalc_heap::Info *node,
1386     const Gcalc_heap::Info *edge_a, const Gcalc_heap::Info *edge_b)
1387 {
1388   Gcalc_coord1 a_x, a_y;
1389   Gcalc_coord1 b_x, b_y;
1390   Gcalc_coord2 ax_by, ay_bx;
1391   int result;
1392 
1393   gcalc_sub_coord1(a_x, node->node.shape.ix, edge_a->node.shape.ix);
1394   gcalc_sub_coord1(a_y, node->node.shape.iy, edge_a->node.shape.iy);
1395   gcalc_sub_coord1(b_x, edge_b->node.shape.ix, edge_a->node.shape.ix);
1396   gcalc_sub_coord1(b_y, edge_b->node.shape.iy, edge_a->node.shape.iy);
1397   gcalc_mul_coord1(ax_by, a_x, b_y);
1398   gcalc_mul_coord1(ay_bx, a_y, b_x);
1399   result= gcalc_cmp_coord(ax_by, ay_bx, GCALC_COORD_BASE2);
1400 #ifdef GCALC_CHECK_WITH_FLOAT
1401   {
1402     long double dx= gcalc_get_double(edge_b->node.shape.ix, GCALC_COORD_BASE) -
1403                       gcalc_get_double(edge_a->node.shape.ix, GCALC_COORD_BASE);
1404     long double dy= gcalc_get_double(edge_b->node.shape.iy, GCALC_COORD_BASE) -
1405                       gcalc_get_double(edge_a->node.shape.iy, GCALC_COORD_BASE);
1406     long double ax= gcalc_get_double(node->node.shape.ix, GCALC_COORD_BASE) -
1407                       gcalc_get_double(edge_a->node.shape.ix, GCALC_COORD_BASE);
1408     long double ay= gcalc_get_double(node->node.shape.iy, GCALC_COORD_BASE) -
1409                       gcalc_get_double(edge_a->node.shape.iy, GCALC_COORD_BASE);
1410     long double d= ax * dy - ay * dx;
1411     if (result == 0)
1412       GCALC_DBUG_ASSERT(de_check(d, 0.0));
1413     else if (result < 0)
1414       GCALC_DBUG_ASSERT(de_check(d, 0.0) || d < 0);
1415     else
1416       GCALC_DBUG_ASSERT(de_check(d, 0.0) || d > 0);
1417   }
1418 #endif /*GCALC_CHECK_WITH_FLOAT*/
1419   return result;
1420 }
1421 
1422 
cmp_tops(const Gcalc_heap::Info * top_node,const Gcalc_heap::Info * edge_a,const Gcalc_heap::Info * edge_b)1423 static int cmp_tops(const Gcalc_heap::Info *top_node,
1424     const Gcalc_heap::Info *edge_a, const Gcalc_heap::Info *edge_b)
1425 {
1426   int cmp_res_a, cmp_res_b;
1427 
1428   cmp_res_a= gcalc_cmp_coord1(edge_a->node.shape.ix, top_node->node.shape.ix);
1429   cmp_res_b= gcalc_cmp_coord1(edge_b->node.shape.ix, top_node->node.shape.ix);
1430 
1431   if (cmp_res_a <= 0 && cmp_res_b > 0)
1432     return -1;
1433   if (cmp_res_b <= 0 && cmp_res_a > 0)
1434     return 1;
1435   if (cmp_res_a == 0 && cmp_res_b == 0)
1436     return 0;
1437 
1438   return node_on_right(edge_a, top_node, edge_b);
1439 }
1440 
1441 
insert_top_node()1442 int Gcalc_scan_iterator::insert_top_node()
1443 {
1444   point *sp= state.slice;
1445   point **prev_hook= &state.slice;
1446   point *sp1= NULL;
1447   point *sp0= new_slice_point();
1448   int cmp_res;
1449 
1450   GCALC_DBUG_ENTER("Gcalc_scan_iterator::insert_top_node");
1451   if (!sp0)
1452     GCALC_DBUG_RETURN(1);
1453   sp0->pi= m_cur_pi;
1454   sp0->next_pi= m_cur_pi->node.shape.left;
1455 #ifndef GCALC_DBUG_OFF
1456   sp0->thread= m_cur_thread++;
1457 #endif /*GCALC_DBUG_OFF*/
1458   if (m_cur_pi->node.shape.left)
1459   {
1460     calc_dx_dy(sp0);
1461     if (m_cur_pi->node.shape.right)
1462     {
1463       if (!(sp1= new_slice_point()))
1464         GCALC_DBUG_RETURN(1);
1465       sp1->event= sp0->event= scev_two_threads;
1466       sp1->pi= m_cur_pi;
1467       sp1->next_pi= m_cur_pi->node.shape.right;
1468 #ifndef GCALC_DBUG_OFF
1469       sp1->thread= m_cur_thread++;
1470 #endif /*GCALC_DBUG_OFF*/
1471       calc_dx_dy(sp1);
1472       /* We have two threads so should decide which one will be first */
1473       cmp_res= cmp_tops(m_cur_pi, m_cur_pi->node.shape.left, m_cur_pi->node.shape.right);
1474       if (cmp_res > 0)
1475       {
1476         point *tmp= sp0;
1477         sp0= sp1;
1478         sp1= tmp;
1479       }
1480       else if (cmp_res == 0)
1481       {
1482         /* Exactly same direction of the edges. */
1483         cmp_res= gcalc_cmp_coord1(m_cur_pi->node.shape.left->node.shape.iy, m_cur_pi->node.shape.right->node.shape.iy);
1484         if (cmp_res != 0)
1485         {
1486           if (cmp_res < 0)
1487           {
1488             if (add_eq_node(sp0->next_pi, sp1))
1489               GCALC_DBUG_RETURN(1);
1490           }
1491           else
1492           {
1493             if (add_eq_node(sp1->next_pi, sp0))
1494               GCALC_DBUG_RETURN(1);
1495           }
1496         }
1497         else
1498         {
1499           cmp_res= gcalc_cmp_coord1(m_cur_pi->node.shape.left->node.shape.ix, m_cur_pi->node.shape.right->node.shape.ix);
1500           if (cmp_res != 0)
1501           {
1502             if (cmp_res < 0)
1503             {
1504               if (add_eq_node(sp0->next_pi, sp1))
1505                 GCALC_DBUG_RETURN(1);
1506             }
1507             else
1508             {
1509               if (add_eq_node(sp1->next_pi, sp0))
1510                 GCALC_DBUG_RETURN(1);
1511             }
1512           }
1513         }
1514       }
1515     }
1516     else
1517       sp0->event= scev_thread;
1518   }
1519   else
1520     sp0->event= scev_single_point;
1521 
1522 
1523   /* Check if we already have an event - then we'll place the node there */
1524   for (; sp && !sp->event; prev_hook= sp->next_ptr(), sp=sp->get_next())
1525   {}
1526   if (!sp)
1527   {
1528     sp= state.slice;
1529     prev_hook= &state.slice;
1530     /* We need to find the place to insert. */
1531     for (; sp; prev_hook= sp->next_ptr(), sp=sp->get_next())
1532     {
1533       if (sp->event || gcalc_cmp_coord1(*sp->r_border, m_cur_pi->node.shape.ix) < 0)
1534         continue;
1535       cmp_res= node_on_right(m_cur_pi, sp->pi, sp->next_pi);
1536       if (cmp_res == 0)
1537       {
1538         /* The top node lies on the edge. */
1539         /* Nodes of that edge will be handled in other places. */
1540         sp->event= scev_intersection;
1541       }
1542       else if (cmp_res < 0)
1543         break;
1544     }
1545   }
1546 
1547   if (sp0->event == scev_single_point)
1548   {
1549     /* Add single point to the bottom list. */
1550     *m_bottom_hook= sp0;
1551     m_bottom_hook= sp0->next_ptr();
1552     state.event_position_hook= prev_hook;
1553   }
1554   else
1555   {
1556     *prev_hook= sp0;
1557     sp0->next= sp;
1558     if (add_events_for_node(sp0))
1559       GCALC_DBUG_RETURN(1);
1560 
1561     if (sp0->event == scev_two_threads)
1562     {
1563       *prev_hook= sp1;
1564       sp1->next= sp;
1565       if (add_events_for_node(sp1))
1566         GCALC_DBUG_RETURN(1);
1567 
1568       sp0->next= sp1;
1569       *prev_hook= sp0;
1570     }
1571   }
1572 
1573   GCALC_DBUG_RETURN(0);
1574 }
1575 
1576 
remove_bottom_node()1577 void Gcalc_scan_iterator::remove_bottom_node()
1578 {
1579   point *sp= state.slice;
1580   point **sp_hook= &state.slice;
1581   point *first_bottom_point= NULL;
1582 
1583   GCALC_DBUG_ENTER("Gcalc_scan_iterator::remove_bottom_node");
1584   for (; sp; sp= sp->get_next())
1585   {
1586     if (sp->next_pi == m_cur_pi)
1587     {
1588       *sp_hook= sp->get_next();
1589       sp->pi= m_cur_pi;
1590       sp->next_pi= NULL;
1591       if (first_bottom_point)
1592       {
1593         first_bottom_point->event= sp->event= scev_two_ends;
1594         break;
1595       }
1596       first_bottom_point= sp;
1597       sp->event= scev_end;
1598       state.event_position_hook= sp_hook;
1599     }
1600     else
1601       sp_hook= sp->next_ptr();
1602   }
1603   GCALC_DBUG_ASSERT(first_bottom_point);
1604   *m_bottom_hook= first_bottom_point;
1605   m_bottom_hook= first_bottom_point->next_ptr();
1606   if (sp)
1607   {
1608     *m_bottom_hook= sp;
1609     m_bottom_hook= sp->next_ptr();
1610   }
1611 
1612   GCALC_DBUG_VOID_RETURN;
1613 }
1614 
1615 
add_events_for_node(point * sp_node)1616 int Gcalc_scan_iterator::add_events_for_node(point *sp_node)
1617 {
1618   point *sp= state.slice;
1619   int cur_pi_r, sp_pi_r;
1620 
1621   GCALC_DBUG_ENTER("Gcalc_scan_iterator::add_events_for_node");
1622 
1623   /* Scan to the event point. */
1624   for (; sp != sp_node; sp= sp->get_next())
1625   {
1626     GCALC_DBUG_ASSERT(!sp->is_bottom());
1627     GCALC_DBUG_PRINT(("left cut_edge %d", sp->thread));
1628     if (sp->next_pi == sp_node->next_pi ||
1629         gcalc_cmp_coord1(*sp->r_border, *sp_node->l_border) < 0)
1630       continue;
1631     sp_pi_r= node_on_right(sp->next_pi, sp_node->pi, sp_node->next_pi);
1632     if (sp_pi_r < 0)
1633       continue;
1634     cur_pi_r= node_on_right(sp_node->next_pi, sp->pi, sp->next_pi);
1635     if (cur_pi_r > 0)
1636       continue;
1637     if (cur_pi_r == 0 && sp_pi_r == 0)
1638     {
1639       int cmp_res= cmp_point_info(sp->next_pi, sp_node->next_pi);
1640       if (cmp_res > 0)
1641       {
1642         if (add_eq_node(sp_node->next_pi, sp))
1643           GCALC_DBUG_RETURN(1);
1644       }
1645       else if (cmp_res < 0)
1646       {
1647         if (add_eq_node(sp->next_pi, sp_node))
1648           GCALC_DBUG_RETURN(1);
1649       }
1650       continue;
1651     }
1652 
1653     if (cur_pi_r == 0)
1654     {
1655       if (add_eq_node(sp_node->next_pi, sp))
1656         GCALC_DBUG_RETURN(1);
1657       continue;
1658     }
1659     else if (sp_pi_r == 0)
1660     {
1661       if (add_eq_node(sp->next_pi, sp_node))
1662         GCALC_DBUG_RETURN(1);
1663       continue;
1664     }
1665 
1666     if (sp->event)
1667     {
1668 #ifndef GCALC_DBUG_OFF
1669       cur_pi_r= node_on_right(sp_node->pi, sp->pi, sp->next_pi);
1670       GCALC_DBUG_ASSERT(cur_pi_r == 0);
1671 #endif /*GCALC_DBUG_OFF*/
1672       continue;
1673     }
1674     cur_pi_r= node_on_right(sp_node->pi, sp->pi, sp->next_pi);
1675     GCALC_DBUG_ASSERT(cur_pi_r >= 0);
1676     //GCALC_DBUG_ASSERT(cur_pi_r > 0); /* Is it ever violated? */
1677     if (cur_pi_r > 0 && add_intersection(sp, sp_node, m_cur_pi))
1678       GCALC_DBUG_RETURN(1);
1679   }
1680 
1681   /* Scan to the end of the slice */
1682   sp= sp->get_next();
1683 
1684   for (; sp; sp= sp->get_next())
1685   {
1686     GCALC_DBUG_ASSERT(!sp->is_bottom());
1687     GCALC_DBUG_PRINT(("right cut_edge %d", sp->thread));
1688     if (sp->next_pi == sp_node->next_pi ||
1689         gcalc_cmp_coord1(*sp_node->r_border, *sp->l_border) < 0)
1690       continue;
1691     sp_pi_r= node_on_right(sp->next_pi, sp_node->pi, sp_node->next_pi);
1692     if (sp_pi_r > 0)
1693       continue;
1694     cur_pi_r= node_on_right(sp_node->next_pi, sp->pi, sp->next_pi);
1695     if (cur_pi_r < 0)
1696       continue;
1697     if (cur_pi_r == 0 && sp_pi_r == 0)
1698     {
1699       int cmp_res= cmp_point_info(sp->next_pi, sp_node->next_pi);
1700       if (cmp_res > 0)
1701       {
1702         if (add_eq_node(sp_node->next_pi, sp))
1703           GCALC_DBUG_RETURN(1);
1704       }
1705       else if (cmp_res < 0)
1706       {
1707         if (add_eq_node(sp->next_pi, sp_node))
1708           GCALC_DBUG_RETURN(1);
1709       }
1710       continue;
1711     }
1712     if (cur_pi_r == 0)
1713     {
1714       if (add_eq_node(sp_node->next_pi, sp))
1715         GCALC_DBUG_RETURN(1);
1716       continue;
1717     }
1718     else if (sp_pi_r == 0)
1719     {
1720       if (add_eq_node(sp->next_pi, sp_node))
1721         GCALC_DBUG_RETURN(1);
1722       continue;
1723     }
1724 
1725     if (sp->event)
1726     {
1727 #ifndef GCALC_DBUG_OFF
1728       cur_pi_r= node_on_right(sp_node->pi, sp->pi, sp->next_pi);
1729       GCALC_DBUG_ASSERT(cur_pi_r == 0);
1730 #endif /*GCALC_DBUG_OFF*/
1731       continue;
1732     }
1733     cur_pi_r= node_on_right(sp_node->pi, sp->pi, sp->next_pi);
1734     GCALC_DBUG_ASSERT(cur_pi_r <= 0);
1735     //GCALC_DBUG_ASSERT(cur_pi_r < 0); /* Is it ever violated? */
1736     if (cur_pi_r < 0 && add_intersection(sp_node, sp, m_cur_pi))
1737       GCALC_DBUG_RETURN(1);
1738   }
1739 
1740   GCALC_DBUG_RETURN(0);
1741 }
1742 
1743 
node_scan()1744 int Gcalc_scan_iterator::node_scan()
1745 {
1746   point *sp= state.slice;
1747   Gcalc_heap::Info *cur_pi= m_cur_pi;
1748 
1749   GCALC_DBUG_ENTER("Gcalc_scan_iterator::node_scan");
1750 
1751   /* Scan to the event point.                             */
1752   /* Can be avoided if we add link to the sp to the Info. */
1753   for (; sp->next_pi != cur_pi; sp= sp->get_next())
1754   {}
1755 
1756   GCALC_DBUG_PRINT(("node for %d", sp->thread));
1757   /* Handle the point itself. */
1758   sp->pi= cur_pi;
1759   sp->next_pi= cur_pi->node.shape.left;
1760   sp->event= scev_point;
1761   calc_dx_dy(sp);
1762 
1763   GCALC_DBUG_RETURN(add_events_for_node(sp));
1764 }
1765 
1766 
eq_scan()1767 void Gcalc_scan_iterator::eq_scan()
1768 {
1769   point *sp= eq_sp(m_cur_pi);
1770   GCALC_DBUG_ENTER("Gcalc_scan_iterator::eq_scan");
1771 
1772 #ifndef GCALC_DBUG_OFF
1773   {
1774     point *cur_p= state.slice;
1775     for (; cur_p && cur_p != sp; cur_p= cur_p->get_next())
1776     {}
1777     GCALC_DBUG_ASSERT(cur_p);
1778   }
1779 #endif /*GCALC_DBUG_OFF*/
1780   if (!sp->event)
1781   {
1782     sp->event= scev_intersection;
1783     sp->ev_pi= m_cur_pi;
1784   }
1785 
1786   GCALC_DBUG_VOID_RETURN;
1787 }
1788 
1789 
intersection_scan()1790 void Gcalc_scan_iterator::intersection_scan()
1791 {
1792   intersection_info *ii= i_data(m_cur_pi);
1793   GCALC_DBUG_ENTER("Gcalc_scan_iterator::intersection_scan");
1794 
1795 #ifndef GCALC_DBUG_OFF
1796   {
1797     point *sp= state.slice;
1798     for (; sp && sp != ii->edge_a; sp= sp->get_next())
1799     {}
1800     GCALC_DBUG_ASSERT(sp);
1801     for (; sp && sp != ii->edge_b; sp= sp->get_next())
1802     {}
1803     GCALC_DBUG_ASSERT(sp);
1804   }
1805 #endif /*GCALC_DBUG_OFF*/
1806 
1807   ii->edge_a->event= ii->edge_b->event= scev_intersection;
1808   ii->edge_a->ev_pi= ii->edge_b->ev_pi= m_cur_pi;
1809   free_item(ii);
1810   m_cur_pi->node.intersection.data= NULL;
1811 
1812   GCALC_DBUG_VOID_RETURN;
1813 }
1814 
1815 
add_intersection(point * sp_a,point * sp_b,Gcalc_heap::Info * pi_from)1816 int Gcalc_scan_iterator::add_intersection(point *sp_a, point *sp_b,
1817                                           Gcalc_heap::Info *pi_from)
1818 {
1819   Gcalc_heap::Info *ii;
1820   intersection_info *i_calc;
1821   int cmp_res;
1822   int skip_next= 0;
1823 
1824   GCALC_DBUG_ENTER("Gcalc_scan_iterator::add_intersection");
1825   if (!(i_calc= new_intersection_info(sp_a, sp_b)) ||
1826       !(ii= new_intersection(m_heap, i_calc)))
1827     GCALC_DBUG_RETURN(1);
1828 
1829   ii->node.intersection.equal= 0;
1830 
1831   for (;
1832        pi_from->get_next() != sp_a->next_pi &&
1833          pi_from->get_next() != sp_b->next_pi;
1834        pi_from= pi_from->get_next())
1835   {
1836     Gcalc_heap::Info *cur= pi_from->get_next();
1837     if (skip_next)
1838     {
1839       if (cur->type == Gcalc_heap::nt_intersection)
1840         skip_next= cur->node.intersection.equal;
1841       else
1842         skip_next= 0;
1843       continue;
1844     }
1845     if (cur->type == Gcalc_heap::nt_intersection)
1846     {
1847       cmp_res= cmp_intersections(cur, ii);
1848       skip_next= cur->node.intersection.equal;
1849     }
1850     else if (cur->type == Gcalc_heap::nt_eq_node)
1851       continue;
1852     else
1853       cmp_res= cmp_node_isc(cur, ii);
1854     if (cmp_res == 0)
1855     {
1856       ii->node.intersection.equal= 1;
1857       break;
1858     }
1859     else if (cmp_res > 0)
1860       break;
1861   }
1862 
1863   /* Intersection inserted before the equal point. */
1864   ii->next= pi_from->get_next();
1865   pi_from->next= ii;
1866 
1867   GCALC_DBUG_RETURN(0);
1868 }
1869 
1870 
add_eq_node(Gcalc_heap::Info * node,point * sp)1871 int Gcalc_scan_iterator::add_eq_node(Gcalc_heap::Info *node, point *sp)
1872 {
1873   Gcalc_heap::Info *en;
1874 
1875   GCALC_DBUG_ENTER("Gcalc_scan_iterator::add_intersection");
1876   en= new_eq_point(m_heap, node, sp);
1877   if (!en)
1878     GCALC_DBUG_RETURN(1);
1879 
1880   /* eq_node inserted after the equal point. */
1881   en->next= node->get_next();
1882   node->next= en;
1883 
1884   GCALC_DBUG_RETURN(0);
1885 }
1886 
1887 
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)1888 void calc_t(Gcalc_coord2 t_a, Gcalc_coord2 t_b,
1889             Gcalc_coord1 dxa, Gcalc_coord1 dxb,
1890             const Gcalc_heap::Info *p1, const Gcalc_heap::Info *p2,
1891             const Gcalc_heap::Info *p3, const Gcalc_heap::Info *p4)
1892 {
1893   Gcalc_coord1 a2_a1x, a2_a1y;
1894   Gcalc_coord2 x1y2, x2y1;
1895   Gcalc_coord1 dya, dyb;
1896 
1897   gcalc_sub_coord1(a2_a1x, p3->node.shape.ix, p1->node.shape.ix);
1898   gcalc_sub_coord1(a2_a1y, p3->node.shape.iy, p1->node.shape.iy);
1899 
1900   gcalc_sub_coord1(dxa, p2->node.shape.ix, p1->node.shape.ix);
1901   gcalc_sub_coord1(dya, p2->node.shape.iy, p1->node.shape.iy);
1902   gcalc_sub_coord1(dxb, p4->node.shape.ix, p3->node.shape.ix);
1903   gcalc_sub_coord1(dyb, p4->node.shape.iy, p3->node.shape.iy);
1904 
1905   gcalc_mul_coord1(x1y2, dxa, dyb);
1906   gcalc_mul_coord1(x2y1, dya, dxb);
1907   gcalc_sub_coord(t_b, GCALC_COORD_BASE2, x1y2, x2y1);
1908 
1909 
1910   gcalc_mul_coord1(x1y2, a2_a1x, dyb);
1911   gcalc_mul_coord1(x2y1, a2_a1y, dxb);
1912   gcalc_sub_coord(t_a, GCALC_COORD_BASE2, x1y2, x2y1);
1913 }
1914 
1915 
get_y() const1916 double Gcalc_scan_iterator::get_y() const
1917 {
1918   if (state.pi->type == Gcalc_heap::nt_intersection)
1919   {
1920     Gcalc_coord1 dxa, dya;
1921     Gcalc_coord2 t_a, t_b;
1922     Gcalc_coord3 a_tb, b_ta, y_exp;
1923     calc_t(t_a, t_b, dxa, dya,
1924            state.pi->node.intersection.p1, state.pi->node.intersection.p2, state.pi->node.intersection.p3, state.pi->node.intersection.p4);
1925 
1926 
1927     gcalc_mul_coord(a_tb, GCALC_COORD_BASE3,
1928         t_b, GCALC_COORD_BASE2, state.pi->node.intersection.p1->node.shape.iy, GCALC_COORD_BASE);
1929     gcalc_mul_coord(b_ta, GCALC_COORD_BASE3,
1930         t_a, GCALC_COORD_BASE2, dya, GCALC_COORD_BASE);
1931 
1932     gcalc_add_coord(y_exp, GCALC_COORD_BASE3, a_tb, b_ta);
1933 
1934     return (get_pure_double(y_exp, GCALC_COORD_BASE3) /
1935              get_pure_double(t_b, GCALC_COORD_BASE2)) / m_heap->coord_extent;
1936   }
1937   else
1938     return state.pi->node.shape.y;
1939 }
1940 
1941 
get_event_x() const1942 double Gcalc_scan_iterator::get_event_x() const
1943 {
1944   if (state.pi->type == Gcalc_heap::nt_intersection)
1945   {
1946     Gcalc_coord1 dxa, dya;
1947     Gcalc_coord2 t_a, t_b;
1948     Gcalc_coord3 a_tb, b_ta, x_exp;
1949     calc_t(t_a, t_b, dxa, dya,
1950            state.pi->node.intersection.p1, state.pi->node.intersection.p2, state.pi->node.intersection.p3, state.pi->node.intersection.p4);
1951 
1952 
1953     gcalc_mul_coord(a_tb, GCALC_COORD_BASE3,
1954         t_b, GCALC_COORD_BASE2, state.pi->node.intersection.p1->node.shape.ix, GCALC_COORD_BASE);
1955     gcalc_mul_coord(b_ta, GCALC_COORD_BASE3,
1956         t_a, GCALC_COORD_BASE2, dxa, GCALC_COORD_BASE);
1957 
1958     gcalc_add_coord(x_exp, GCALC_COORD_BASE3, a_tb, b_ta);
1959 
1960     return (get_pure_double(x_exp, GCALC_COORD_BASE3) /
1961              get_pure_double(t_b, GCALC_COORD_BASE2)) / m_heap->coord_extent;
1962   }
1963   else
1964     return state.pi->node.shape.x;
1965 }
1966 
get_h() const1967 double Gcalc_scan_iterator::get_h() const
1968 {
1969   double cur_y= get_y();
1970   double next_y;
1971   if (state.pi->type == Gcalc_heap::nt_intersection)
1972   {
1973     double x;
1974     state.pi->calc_xy(&x, &next_y);
1975   }
1976   else
1977     next_y= state.pi->next ? state.pi->get_next()->node.shape.y : 0.0;
1978   return next_y - cur_y;
1979 }
1980 
1981 
get_sp_x(const point * sp) const1982 double Gcalc_scan_iterator::get_sp_x(const point *sp) const
1983 {
1984   double dy;
1985   if (sp->event & (scev_end | scev_two_ends | scev_point))
1986     return sp->pi->node.shape.x;
1987   dy= sp->next_pi->node.shape.y - sp->pi->node.shape.y;
1988   if (fabs(dy) < 1e-12)
1989     return sp->pi->node.shape.x;
1990   return sp->pi->node.shape.x + (sp->next_pi->node.shape.x - sp->pi->node.shape.x) * dy;
1991 }
1992 
1993 
get_pure_double(const Gcalc_internal_coord * d,int d_len)1994 double Gcalc_scan_iterator::get_pure_double(const Gcalc_internal_coord *d,
1995                                             int d_len)
1996 {
1997   int n= 1;
1998   long double res= (long double) FIRST_DIGIT(d[0]);
1999   do
2000   {
2001     res*= (long double) GCALC_DIG_BASE;
2002     res+= (long double) d[n];
2003   } while(++n < d_len);
2004 
2005   if (GCALC_SIGN(d[0]))
2006     res*= -1.0;
2007   return res;
2008 }
2009 
2010 
2011 #endif /* HAVE_SPATIAL */
2012