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