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
20 #ifdef HAVE_SPATIAL
21
22 #include "gcalc_tools.h"
23 #include "spatial.h"
24
25 #define float_to_coord(d) ((double) d)
26
27
28 /*
29 Adds new shape to the relation.
30 After that it can be used as an argument of an operation.
31 */
32
add_new_shape(uint32 shape_id,shape_type shape_kind)33 gcalc_shape_info Gcalc_function::add_new_shape(uint32 shape_id,
34 shape_type shape_kind)
35 {
36 shapes_buffer.q_append((uint32) shape_kind);
37 return n_shapes++;
38 }
39
40
41 /*
42 Adds new operation to the constructed relation.
43 To construct the complex relation one has to specify operations
44 in prefix style.
45 */
46
add_operation(uint operation,uint32 n_operands)47 void Gcalc_function::add_operation(uint operation, uint32 n_operands)
48 {
49 uint32 op_code= (uint32 ) operation + n_operands;
50 function_buffer.q_append(op_code);
51 }
52
53
54 /*
55 Sometimes the number of arguments is unknown at the moment the operation
56 is added. That allows to specify it later.
57 */
58
add_operands_to_op(uint32 operation_pos,uint32 n_operands)59 void Gcalc_function::add_operands_to_op(uint32 operation_pos, uint32 n_operands)
60 {
61 uint32 op_code= uint4korr(function_buffer.ptr() + operation_pos) + n_operands;
62 function_buffer.write_at_position(operation_pos, op_code);
63 }
64
65
66 /*
67 Just like the add_operation() but the result will be the inverted
68 value of an operation.
69 */
70
add_not_operation(op_type operation,uint32 n_operands)71 void Gcalc_function::add_not_operation(op_type operation, uint32 n_operands)
72 {
73 uint32 op_code= ((uint32) op_not | (uint32 ) operation) + n_operands;
74 function_buffer.q_append(op_code);
75 }
76
77
single_shape_op(shape_type shape_kind,gcalc_shape_info * si)78 int Gcalc_function::single_shape_op(shape_type shape_kind, gcalc_shape_info *si)
79 {
80 if (reserve_shape_buffer(1) || reserve_op_buffer(1))
81 return 1;
82 *si= add_new_shape(0, shape_kind);
83 add_operation(op_shape, *si);
84 return 0;
85 }
86
87
repeat_expression(uint32 exp_pos)88 int Gcalc_function::repeat_expression(uint32 exp_pos)
89 {
90 if (reserve_op_buffer(1))
91 return 1;
92 add_operation(op_repeat, exp_pos);
93 return 0;
94 }
95
96
97 /*
98 Specify how many arguments we're going to have.
99 */
100
reserve_shape_buffer(uint n_shapes)101 int Gcalc_function::reserve_shape_buffer(uint n_shapes)
102 {
103 return shapes_buffer.reserve(n_shapes * 4, 512);
104 }
105
106
107 /*
108 Specify how many operations we're going to have.
109 */
110
reserve_op_buffer(uint n_ops)111 int Gcalc_function::reserve_op_buffer(uint n_ops)
112 {
113 return function_buffer.reserve(n_ops * 4, 512);
114 }
115
116
alloc_states()117 int Gcalc_function::alloc_states()
118 {
119 if (function_buffer.reserve((n_shapes+1) * 2 * sizeof(int)))
120 return 1;
121 i_states= (int *) (function_buffer.ptr() + ALIGN_SIZE(function_buffer.length()));
122 b_states= i_states + (n_shapes + 1);
123 return 0;
124 }
125
126
count_internal(const char * cur_func,uint set_type,const char ** end)127 int Gcalc_function::count_internal(const char *cur_func, uint set_type,
128 const char **end)
129 {
130 uint c_op= uint4korr(cur_func);
131 op_type next_func= (op_type) (c_op & op_any);
132 int mask= (c_op & op_not) ? 1:0;
133 uint n_ops= c_op & ~(op_any | op_not | v_mask);
134 uint n_shape= c_op & ~(op_any | op_not | v_mask); /* same as n_ops */
135 value v_state= (value) (c_op & v_mask);
136 int result= 0;
137 const char *sav_cur_func= cur_func;
138
139 // GCALC_DBUG_ENTER("Gcalc_function::count_internal");
140
141 cur_func+= 4;
142 if (next_func == op_shape)
143 {
144 if (set_type == 0)
145 result= i_states[n_shape] | b_states[n_shape];
146 /* the last call for the count_internal outside of all shapes. */
147 else if (set_type == 1)
148 result= 0;
149 else if (set_type == op_border)
150 result= b_states[n_shape];
151 else if (set_type == op_internals)
152 result= i_states[n_shape] && !b_states[n_shape];
153 goto exit;
154 }
155
156 if (next_func == op_false)
157 {
158 result= 0;
159 goto exit;
160 }
161
162 if (next_func == op_border || next_func == op_internals)
163 {
164 result= count_internal(cur_func,
165 (set_type == 1) ? set_type : next_func, &cur_func);
166 goto exit;
167 }
168
169 if (next_func == op_repeat)
170 {
171 result= count_internal(function_buffer.ptr() + n_ops, set_type, 0);
172 goto exit;
173 }
174
175 if (n_ops == 0)
176 return mask;
177 //GCALC_DBUG_RETURN(mask);
178
179 result= count_internal(cur_func, set_type, &cur_func);
180
181 while (--n_ops)
182 {
183 int next_res= count_internal(cur_func, set_type, &cur_func);
184 switch (next_func)
185 {
186 case op_union:
187 if (result == result_true || next_res == result_true)
188 result= result_true;
189 else if (result == result_unknown || next_res == result_unknown)
190 result= result_unknown;
191 else
192 result= result_false;
193 break;
194 case op_intersection:
195 if (result == result_false || next_res == result_false)
196 result= result_false;
197 else if (result == result_unknown || next_res == result_unknown)
198 result= result_unknown;
199 else
200 result= result_true;
201 break;
202 case op_symdifference:
203 if (result == result_unknown || next_res == result_unknown)
204 result= result_unknown;
205 else
206 result= result ^ next_res;
207 break;
208 case op_difference:
209 if (result == result_false || next_res == result_true)
210 result= result_false;
211 else if (result == result_unknown || next_res == result_unknown)
212 result= result_unknown;
213 else
214 result= result_true;
215 break;
216 default:
217 GCALC_DBUG_ASSERT(FALSE);
218 };
219 }
220
221 exit:
222 if (result != result_unknown)
223 result^= mask;
224 if (v_state != v_empty)
225 {
226 switch (v_state)
227 {
228 case v_find_t:
229 if (result == result_true)
230 {
231 c_op= (c_op & ~v_mask) | v_t_found;
232 int4store(sav_cur_func, c_op);
233 }
234 else
235 {
236 if (set_type != 1)
237 result= result_unknown;
238 }
239 break;
240 case v_find_f:
241 if (result == result_false)
242 {
243 c_op= (c_op & ~v_mask) | v_f_found;
244 int4store(sav_cur_func, c_op);
245 }
246 else
247 {
248 if (set_type != 1)
249 result= result_unknown;
250 }
251 break;
252 case v_t_found:
253 result= 1;
254 break;
255 case v_f_found:
256 result= 0;
257 break;
258 default:
259 GCALC_DBUG_ASSERT(0);
260 };
261 }
262
263 if (end)
264 *end= cur_func;
265 return result;
266 //GCALC_DBUG_RETURN(result);
267 }
268
269
clear_i_states()270 void Gcalc_function::clear_i_states()
271 {
272 for (uint i= 0; i < n_shapes; i++)
273 i_states[i]= 0;
274 }
275
276
clear_b_states()277 void Gcalc_function::clear_b_states()
278 {
279 for (uint i= 0; i < n_shapes; i++)
280 b_states[i]= 0;
281 }
282
283
284 /*
285 Clear the state of the object.
286 */
287
reset()288 void Gcalc_function::reset()
289 {
290 n_shapes= 0;
291 shapes_buffer.length(0);
292 function_buffer.length(0);
293 }
294
295
check_function(Gcalc_scan_iterator & scan_it)296 int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it)
297 {
298 const Gcalc_scan_iterator::point *eq_start, *cur_eq;
299 const Gcalc_scan_iterator::event_point *events;
300 int result;
301 GCALC_DBUG_ENTER("Gcalc_function::check_function");
302
303 while (scan_it.more_points())
304 {
305 if (scan_it.step())
306 GCALC_DBUG_RETURN(-1);
307 events= scan_it.get_events();
308
309 /* these kinds of events don't change the function */
310 Gcalc_point_iterator pit(&scan_it);
311 clear_b_states();
312 clear_i_states();
313 /* Walk to the event, marking polygons we met */
314 for (; pit.point() != scan_it.get_event_position(); ++pit)
315 {
316 gcalc_shape_info si= pit.point()->get_shape();
317 if ((get_shape_kind(si) == Gcalc_function::shape_polygon))
318 invert_i_state(si);
319 }
320 if (events->simple_event())
321 {
322 if (events->event == scev_end)
323 set_b_state(events->get_shape());
324
325 if ((result= count()) != result_unknown)
326 GCALC_DBUG_RETURN(result);
327 clear_b_states();
328 continue;
329 }
330
331 /* Check the status of the event point */
332 for (; events; events= events->get_next())
333 {
334 gcalc_shape_info si= events->get_shape();
335 if (events->event == scev_thread ||
336 events->event == scev_end ||
337 (get_shape_kind(si) == Gcalc_function::shape_polygon))
338 set_b_state(si);
339 else if (events->event == scev_single_point ||
340 get_shape_kind(si) == Gcalc_function::shape_line)
341 set_i_state(si);
342 }
343
344 if ((result= count()) != result_unknown)
345 GCALC_DBUG_RETURN(result);
346
347 /* Set back states changed in the loop above. */
348 for (events= scan_it.get_events(); events; events= events->get_next())
349 {
350 gcalc_shape_info si= events->get_shape();
351 if (events->event == scev_thread ||
352 events->event == scev_end ||
353 get_shape_kind(si) == Gcalc_function::shape_polygon)
354 clear_b_state(si);
355 else if (events->event == scev_single_point ||
356 get_shape_kind(si) == Gcalc_function::shape_line)
357 clear_i_state(si);
358 }
359
360 if (scan_it.get_event_position() == scan_it.get_event_end())
361 continue;
362
363 /* Check the status after the event */
364 eq_start= pit.point();
365 do
366 {
367 ++pit;
368 if (pit.point() != scan_it.get_event_end() &&
369 eq_start->cmp_dx_dy(pit.point()) == 0)
370 continue;
371 for (cur_eq= eq_start; cur_eq != pit.point();
372 cur_eq= cur_eq->get_next())
373 {
374 gcalc_shape_info si= cur_eq->get_shape();
375 if (get_shape_kind(si) == Gcalc_function::shape_polygon)
376 set_b_state(si);
377 else
378 invert_i_state(si);
379 }
380 if ((result= count()) != result_unknown)
381 GCALC_DBUG_RETURN(result);
382
383 for (cur_eq= eq_start; cur_eq != pit.point(); cur_eq= cur_eq->get_next())
384 {
385 gcalc_shape_info si= cur_eq->get_shape();
386 if ((get_shape_kind(si) == Gcalc_function::shape_polygon))
387 {
388 clear_b_state(si);
389 invert_i_state(si);
390 }
391 else
392 invert_i_state(cur_eq->get_shape());
393 }
394 if ((result= count()) != result_unknown)
395 GCALC_DBUG_RETURN(result);
396
397 eq_start= pit.point();
398 } while (pit.point() != scan_it.get_event_end());
399 }
400 GCALC_DBUG_RETURN(count_last());
401 }
402
403
single_point(double x,double y)404 int Gcalc_operation_transporter::single_point(double x, double y)
405 {
406 gcalc_shape_info si;
407 return m_fn->single_shape_op(Gcalc_function::shape_point, &si) ||
408 int_single_point(si, x, y);
409 }
410
411
start_line()412 int Gcalc_operation_transporter::start_line()
413 {
414 int_start_line();
415 return m_fn->single_shape_op(Gcalc_function::shape_line, &m_si);
416 }
417
418
complete_line()419 int Gcalc_operation_transporter::complete_line()
420 {
421 int_complete_line();
422 return 0;
423 }
424
425
start_poly()426 int Gcalc_operation_transporter::start_poly()
427 {
428 int_start_poly();
429 return m_fn->single_shape_op(Gcalc_function::shape_polygon, &m_si);
430 }
431
432
complete_poly()433 int Gcalc_operation_transporter::complete_poly()
434 {
435 int_complete_poly();
436 return 0;
437 }
438
439
start_ring()440 int Gcalc_operation_transporter::start_ring()
441 {
442 int_start_ring();
443 return 0;
444 }
445
446
complete_ring()447 int Gcalc_operation_transporter::complete_ring()
448 {
449 int_complete_ring();
450 return 0;
451 }
452
453
add_point(double x,double y)454 int Gcalc_operation_transporter::add_point(double x, double y)
455 {
456 return int_add_point(m_si, x, y);
457 }
458
459
start_collection(int n_objects)460 int Gcalc_operation_transporter::start_collection(int n_objects)
461 {
462 if (m_fn->reserve_shape_buffer(n_objects) || m_fn->reserve_op_buffer(1))
463 return 1;
464 m_fn->add_operation(Gcalc_function::op_union, n_objects);
465 return 0;
466 }
467
468
empty_shape()469 int Gcalc_operation_transporter::empty_shape()
470 {
471 if (m_fn->reserve_op_buffer(1))
472 return 1;
473 m_fn->add_operation(Gcalc_function::op_false, 0);
474 return 0;
475 }
476
477
start_shape(Gcalc_function::shape_type shape)478 int Gcalc_result_receiver::start_shape(Gcalc_function::shape_type shape)
479 {
480 GCALC_DBUG_ENTER("Gcalc_result_receiver::start_shape");
481 if (buffer.reserve(4*2, 512))
482 GCALC_DBUG_RETURN(1);
483 cur_shape= shape;
484 shape_pos= buffer.length();
485 buffer.length(shape_pos + ((shape == Gcalc_function::shape_point) ? 4:8));
486 n_points= 0;
487 shape_area= 0.0;
488
489 GCALC_DBUG_RETURN(0);
490 }
491
492
add_point(double x,double y)493 int Gcalc_result_receiver::add_point(double x, double y)
494 {
495 GCALC_DBUG_ENTER("Gcalc_result_receiver::add_point");
496 if (n_points && x == prev_x && y == prev_y)
497 GCALC_DBUG_RETURN(0);
498
499 if (!n_points++)
500 {
501 prev_x= first_x= x;
502 prev_y= first_y= y;
503 GCALC_DBUG_RETURN(0);
504 }
505
506 shape_area+= prev_x*y - prev_y*x;
507
508 if (buffer.reserve(8*2, 512))
509 GCALC_DBUG_RETURN(1);
510 buffer.q_append(prev_x);
511 buffer.q_append(prev_y);
512 prev_x= x;
513 prev_y= y;
514 GCALC_DBUG_RETURN(0);
515 }
516
517
complete_shape()518 int Gcalc_result_receiver::complete_shape()
519 {
520 GCALC_DBUG_ENTER("Gcalc_result_receiver::complete_shape");
521 if (n_points == 0)
522 {
523 buffer.length(shape_pos);
524 GCALC_DBUG_RETURN(0);
525 }
526 if (n_points == 1)
527 {
528 if (cur_shape != Gcalc_function::shape_point)
529 {
530 if (cur_shape == Gcalc_function::shape_hole)
531 {
532 buffer.length(shape_pos);
533 GCALC_DBUG_RETURN(0);
534 }
535 cur_shape= Gcalc_function::shape_point;
536 buffer.length(buffer.length()-4);
537 }
538 }
539 else
540 {
541 GCALC_DBUG_ASSERT(cur_shape != Gcalc_function::shape_point);
542 if (cur_shape == Gcalc_function::shape_hole)
543 {
544 shape_area+= prev_x*first_y - prev_y*first_x;
545 if (fabs(shape_area) < 1e-8)
546 {
547 buffer.length(shape_pos);
548 GCALC_DBUG_RETURN(0);
549 }
550 }
551
552 if ((cur_shape == Gcalc_function::shape_polygon ||
553 cur_shape == Gcalc_function::shape_hole) &&
554 prev_x == first_x && prev_y == first_y)
555 {
556 n_points--;
557 buffer.write_at_position(shape_pos+4, n_points);
558 goto do_complete;
559 }
560 buffer.write_at_position(shape_pos+4, n_points);
561 }
562
563 if (buffer.reserve(8*2, 512))
564 GCALC_DBUG_RETURN(1);
565 buffer.q_append(prev_x);
566 buffer.q_append(prev_y);
567
568 do_complete:
569 buffer.write_at_position(shape_pos, (uint32) cur_shape);
570
571 if (!n_shapes++)
572 {
573 GCALC_DBUG_ASSERT(cur_shape != Gcalc_function::shape_hole);
574 common_shapetype= cur_shape;
575 }
576 else if (cur_shape == Gcalc_function::shape_hole)
577 {
578 ++n_holes;
579 }
580 else if (!collection_result && (cur_shape != common_shapetype))
581 {
582 collection_result= true;
583 }
584 GCALC_DBUG_RETURN(0);
585 }
586
587
single_point(double x,double y)588 int Gcalc_result_receiver::single_point(double x, double y)
589 {
590 return start_shape(Gcalc_function::shape_point) ||
591 add_point(x, y) ||
592 complete_shape();
593 }
594
595
done()596 int Gcalc_result_receiver::done()
597 {
598 return 0;
599 }
600
601
reset()602 void Gcalc_result_receiver::reset()
603 {
604 buffer.length(0);
605 collection_result= FALSE;
606 n_shapes= n_holes= 0;
607 }
608
609
get_result_typeid()610 int Gcalc_result_receiver::get_result_typeid()
611 {
612 if (!n_shapes || collection_result)
613 return Geometry::wkb_geometrycollection;
614
615 switch (common_shapetype)
616 {
617 case Gcalc_function::shape_polygon:
618 return (n_shapes - n_holes == 1) ?
619 Geometry::wkb_polygon : Geometry::wkb_multipolygon;
620 case Gcalc_function::shape_point:
621 return (n_shapes == 1) ? Geometry::wkb_point : Geometry::wkb_multipoint;
622 case Gcalc_function::shape_line:
623 return (n_shapes == 1) ? Geometry::wkb_linestring :
624 Geometry::wkb_multilinestring;
625 default:
626 GCALC_DBUG_ASSERT(0);
627 }
628 return 0;
629 }
630
631
move_hole(uint32 dest_position,uint32 source_position,uint32 * position_shift)632 int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_position,
633 uint32 *position_shift)
634 {
635 char *ptr;
636 int source_len;
637 GCALC_DBUG_ENTER("Gcalc_result_receiver::move_hole");
638 GCALC_DBUG_PRINT(("ps %d %d", dest_position, source_position));
639
640 *position_shift= source_len= buffer.length() - source_position;
641
642 if (dest_position == source_position)
643 GCALC_DBUG_RETURN(0);
644
645 if (buffer.reserve(source_len, MY_ALIGN(source_len, 512)))
646 GCALC_DBUG_RETURN(1);
647
648 ptr= (char *) buffer.ptr();
649 memmove(ptr + dest_position + source_len, ptr + dest_position,
650 buffer.length() - dest_position);
651 memcpy(ptr + dest_position, ptr + buffer.length(), source_len);
652 GCALC_DBUG_RETURN(0);
653 }
654
655
Gcalc_operation_reducer(size_t blk_size)656 Gcalc_operation_reducer::Gcalc_operation_reducer(size_t blk_size) :
657 Gcalc_dyn_list(blk_size, sizeof(res_point)),
658 #ifndef GCALC_DBUG_OFF
659 n_res_points(0),
660 #endif /*GCALC_DBUG_OFF*/
661 m_res_hook((Gcalc_dyn_list::Item **)&m_result),
662 m_first_active_thread(NULL)
663 {}
664
665
Gcalc_operation_reducer(const Gcalc_operation_reducer & gor)666 Gcalc_operation_reducer::Gcalc_operation_reducer(
667 const Gcalc_operation_reducer &gor) :
668 Gcalc_dyn_list(gor),
669 #ifndef GCALC_DBUG_OFF
670 n_res_points(0),
671 #endif /*GCALC_DBUG_OFF*/
672 m_res_hook((Gcalc_dyn_list::Item **)&m_result),
673 m_first_active_thread(NULL)
674 {}
675
676
init(Gcalc_function * fn,modes mode)677 void Gcalc_operation_reducer::init(Gcalc_function *fn, modes mode)
678 {
679 m_fn= fn;
680 m_mode= mode;
681 m_first_active_thread= NULL;
682 m_lines= NULL;
683 m_lines_hook= (Gcalc_dyn_list::Item **) &m_lines;
684 m_poly_borders= NULL;
685 m_poly_borders_hook= (Gcalc_dyn_list::Item **) &m_poly_borders;
686 GCALC_SET_TERMINATED(killed, 0);
687 }
688
689
690 Gcalc_operation_reducer::
Gcalc_operation_reducer(Gcalc_function * fn,modes mode,size_t blk_size)691 Gcalc_operation_reducer(Gcalc_function *fn, modes mode, size_t blk_size) :
692 Gcalc_dyn_list(blk_size, sizeof(res_point)),
693 m_res_hook((Gcalc_dyn_list::Item **)&m_result)
694 {
695 init(fn, mode);
696 }
697
698
set(const Gcalc_scan_iterator * si)699 void Gcalc_operation_reducer::res_point::set(const Gcalc_scan_iterator *si)
700 {
701 intersection_point= si->intersection_step();
702 pi= si->get_cur_pi();
703 }
704
705
706 Gcalc_operation_reducer::res_point *
add_res_point(Gcalc_function::shape_type type)707 Gcalc_operation_reducer::add_res_point(Gcalc_function::shape_type type)
708 {
709 GCALC_DBUG_ENTER("Gcalc_operation_reducer::add_res_point");
710 res_point *result= (res_point *)new_item();
711 *m_res_hook= result;
712 result->prev_hook= m_res_hook;
713 m_res_hook= &result->next;
714 result->type= type;
715 #ifndef GCALC_DBUG_OFF
716 result->point_n= n_res_points++;
717 #endif /*GCALC_DBUG_OFF*/
718 GCALC_DBUG_RETURN(result);
719 }
720
add_line(int incoming,active_thread * t,const Gcalc_scan_iterator::point * p)721 int Gcalc_operation_reducer::add_line(int incoming, active_thread *t,
722 const Gcalc_scan_iterator::point *p)
723 {
724 line *l= new_line();
725 GCALC_DBUG_ENTER("Gcalc_operation_reducer::add_line");
726 if (!l)
727 GCALC_DBUG_RETURN(1);
728 l->incoming= incoming;
729 l->t= t;
730 l->p= p;
731 *m_lines_hook= l;
732 m_lines_hook= &l->next;
733 GCALC_DBUG_RETURN(0);
734 }
735
736
add_poly_border(int incoming,active_thread * t,int prev_state,const Gcalc_scan_iterator::point * p)737 int Gcalc_operation_reducer::add_poly_border(int incoming,
738 active_thread *t, int prev_state, const Gcalc_scan_iterator::point *p)
739 {
740 poly_border *b= new_poly_border();
741 GCALC_DBUG_ENTER("Gcalc_operation_reducer::add_poly_border");
742 if (!b)
743 GCALC_DBUG_RETURN(1);
744 b->incoming= incoming;
745 b->t= t;
746 b->prev_state= prev_state;
747 b->p= p;
748 *m_poly_borders_hook= b;
749 m_poly_borders_hook= &b->next;
750 GCALC_DBUG_RETURN(0);
751 }
752
753
continue_range(active_thread * t,const Gcalc_heap::Info * p,const Gcalc_heap::Info * p_next)754 int Gcalc_operation_reducer::continue_range(active_thread *t,
755 const Gcalc_heap::Info *p,
756 const Gcalc_heap::Info *p_next)
757 {
758 res_point *rp= add_res_point(t->rp->type);
759 GCALC_DBUG_ENTER("Gcalc_operation_reducer::continue_range");
760 if (!rp)
761 GCALC_DBUG_RETURN(1);
762 rp->glue= NULL;
763 rp->down= t->rp;
764 t->rp->up= rp;
765 rp->intersection_point= false;
766 rp->pi= p;
767 t->rp= rp;
768 t->p1= p;
769 t->p2= p_next;
770 GCALC_DBUG_RETURN(0);
771 }
772
773
continue_i_range(active_thread * t,const Gcalc_heap::Info * ii)774 inline int Gcalc_operation_reducer::continue_i_range(active_thread *t,
775 const Gcalc_heap::Info *ii)
776 {
777 res_point *rp= add_res_point(t->rp->type);
778 GCALC_DBUG_ENTER("Gcalc_operation_reducer::continue_i_range");
779 if (!rp)
780 GCALC_DBUG_RETURN(1);
781 rp->glue= NULL;
782 rp->down= t->rp;
783 t->rp->up= rp;
784 rp->intersection_point= true;
785 rp->pi= ii;
786 t->rp= rp;
787 GCALC_DBUG_RETURN(0);
788 }
789
end_couple(active_thread * t0,active_thread * t1,const Gcalc_heap::Info * p)790 int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1,
791 const Gcalc_heap::Info *p)
792 {
793 res_point *rp0, *rp1;
794 GCALC_DBUG_ENTER("Gcalc_operation_reducer::end_couple");
795 GCALC_DBUG_ASSERT(t0->rp->type == t1->rp->type);
796 if (!(rp0= add_res_point(t0->rp->type)) ||
797 !(rp1= add_res_point(t0->rp->type)))
798 GCALC_DBUG_RETURN(1);
799 rp0->down= t0->rp;
800 rp1->down= t1->rp;
801 rp1->glue= rp0;
802 rp0->glue= rp1;
803 rp0->up= rp1->up= NULL;
804 t0->rp->up= rp0;
805 t1->rp->up= rp1;
806 rp0->intersection_point= rp1->intersection_point= false;
807 rp0->pi= rp1->pi= p;
808 GCALC_DBUG_RETURN(0);
809 }
810
811
count_slice(Gcalc_scan_iterator * si)812 int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si)
813 {
814 Gcalc_point_iterator pi(si);
815 int prev_state= 0;
816 int sav_prev_state;
817 active_thread *prev_range= NULL;
818 const Gcalc_scan_iterator::event_point *events;
819 const Gcalc_scan_iterator::point *eq_start;
820 active_thread **cur_t_hook= &m_first_active_thread;
821 active_thread **starting_t_hook;
822 active_thread *bottom_threads= NULL;
823 active_thread *eq_thread, *point_thread;;
824 GCALC_DBUG_ENTER("Gcalc_operation_reducer::count_slice");
825
826 m_fn->clear_i_states();
827 /* Walk to the event, remembering what is needed. */
828 for (; pi.point() != si->get_event_position();
829 ++pi, cur_t_hook= (active_thread **) &(*cur_t_hook)->next)
830 {
831 active_thread *cur_t= *cur_t_hook;
832 if (cur_t->enabled() &&
833 cur_t->rp->type == Gcalc_function::shape_polygon)
834 {
835 prev_state^= 1;
836 prev_range= prev_state ? cur_t : 0;
837 }
838 if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon)
839 m_fn->invert_i_state(pi.get_shape());
840 }
841
842 events= si->get_events();
843 if (events->simple_event())
844 {
845 active_thread *cur_t= *cur_t_hook;
846 switch (events->event)
847 {
848 case scev_point:
849 {
850 if (cur_t->enabled() &&
851 continue_range(cur_t, events->pi, events->next_pi))
852 GCALC_DBUG_RETURN(1);
853 break;
854 }
855 case scev_end:
856 {
857 if (cur_t->enabled() && end_line(cur_t, si))
858 GCALC_DBUG_RETURN(1);
859 *cur_t_hook= cur_t->get_next();
860 free_item(cur_t);
861 break;
862 }
863 case scev_two_ends:
864 {
865 if (cur_t->enabled() && cur_t->get_next()->enabled())
866 {
867 /* When two threads are ended here */
868 if (end_couple(cur_t, cur_t->get_next(), events->pi))
869 GCALC_DBUG_RETURN(1);
870 }
871 else if (cur_t->enabled() || cur_t->get_next()->enabled())
872 {
873 /* Rare case when edges of a polygon coincide */
874 if (end_line(cur_t->enabled() ? cur_t : cur_t->get_next(), si))
875 GCALC_DBUG_RETURN(1);
876 }
877 *cur_t_hook= cur_t->get_next()->get_next();
878 free_item(cur_t->next);
879 free_item(cur_t);
880 break;
881 }
882 default:
883 GCALC_DBUG_ASSERT(0);
884 }
885 GCALC_DBUG_RETURN(0);
886 }
887
888 starting_t_hook= cur_t_hook;
889 sav_prev_state= prev_state;
890
891 /* Walk through the event, collecting all the 'incoming' threads */
892 for (; events; events= events->get_next())
893 {
894 active_thread *cur_t= *cur_t_hook;
895
896 if (events->event == scev_single_point)
897 continue;
898
899 if (events->event == scev_thread ||
900 events->event == scev_two_threads)
901 {
902 active_thread *new_t= new_active_thread();
903 if (!new_t)
904 GCALC_DBUG_RETURN(1);
905 new_t->rp= NULL;
906 /* Insert into the main thread list before the current */
907 new_t->next= cur_t;
908 *cur_t_hook= new_t;
909 cur_t_hook= (active_thread **) &new_t->next;
910 }
911 else
912 {
913 if (events->is_bottom())
914 {
915 /* Move thread from the main list to the bottom_threads. */
916 *cur_t_hook= cur_t->get_next();
917 cur_t->next= bottom_threads;
918 bottom_threads= cur_t;
919 }
920 if (cur_t->enabled())
921 {
922 if (cur_t->rp->type == Gcalc_function::shape_line)
923 {
924 GCALC_DBUG_ASSERT(!prev_state);
925 add_line(1, cur_t, events);
926 }
927 else
928 {
929 add_poly_border(1, cur_t, prev_state, events);
930 prev_state^= 1;
931 }
932 if (!events->is_bottom())
933 {
934 active_thread *new_t= new_active_thread();
935 if (!new_t)
936 GCALC_DBUG_RETURN(1);
937 new_t->rp= NULL;
938 /* Replace the current thread with the new. */
939 new_t->next= cur_t->next;
940 *cur_t_hook= new_t;
941 cur_t_hook= (active_thread **) &new_t->next;
942 /* And move old to the bottom list */
943 cur_t->next= bottom_threads;
944 bottom_threads= cur_t;
945 }
946 }
947 else if (!events->is_bottom())
948 cur_t_hook= (active_thread **) &cur_t->next;
949 }
950 }
951 prev_state= sav_prev_state;
952 cur_t_hook= starting_t_hook;
953
954 eq_start= pi.point();
955 eq_thread= point_thread= *starting_t_hook;
956 m_fn->clear_b_states();
957 while (eq_start != si->get_event_end())
958 {
959 const Gcalc_scan_iterator::point *cur_eq;
960 int in_state, after_state;
961
962 ++pi;
963 point_thread= point_thread->get_next();
964
965 if (pi.point() != si->get_event_end() &&
966 eq_start->cmp_dx_dy(pi.point()) == 0)
967 continue;
968
969 for (cur_eq= eq_start; cur_eq != pi.point(); cur_eq= cur_eq->get_next())
970 m_fn->set_b_state(cur_eq->get_shape());
971 in_state= m_fn->count();
972
973 m_fn->clear_b_states();
974 for (cur_eq= eq_start; cur_eq != pi.point(); cur_eq= cur_eq->get_next())
975 {
976 gcalc_shape_info si= cur_eq->get_shape();
977 if ((m_fn->get_shape_kind(si) == Gcalc_function::shape_polygon))
978 m_fn->invert_i_state(si);
979 }
980 after_state= m_fn->count();
981 if (prev_state != after_state)
982 {
983 if (add_poly_border(0, eq_thread, prev_state, eq_start))
984 GCALC_DBUG_RETURN(1);
985 }
986 else if (!prev_state /* &&!after_state */ && in_state)
987 {
988 if (add_line(0, eq_thread, eq_start))
989 GCALC_DBUG_RETURN(1);
990 }
991
992 prev_state= after_state;
993 eq_start= pi.point();
994 eq_thread= point_thread;
995 }
996
997 if (!sav_prev_state && !m_poly_borders && !m_lines)
998 {
999 /* Check if we need to add the event point itself */
1000 m_fn->clear_i_states();
1001 /* b_states supposed to be clean already */
1002 for (pi.restart(si); pi.point() != si->get_event_position(); ++pi)
1003 {
1004 if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon)
1005 m_fn->invert_i_state(pi.get_shape());
1006 }
1007 for (events= si->get_events(); events; events= events->get_next())
1008 m_fn->set_b_state(events->get_shape());
1009
1010 GCALC_DBUG_RETURN(m_fn->count() ? add_single_point(si) : 0);
1011 }
1012
1013 if (m_poly_borders)
1014 {
1015 *m_poly_borders_hook= NULL;
1016 while (m_poly_borders)
1017 {
1018 poly_border *pb1, *pb2;
1019 pb1= m_poly_borders;
1020 GCALC_DBUG_ASSERT(m_poly_borders->next);
1021
1022 pb2= get_pair_border(pb1);
1023 /* Remove pb1 from the list. The pb2 already removed in get_pair_border. */
1024 m_poly_borders= pb1->get_next();
1025 if (connect_threads(pb1->incoming, pb2->incoming,
1026 pb1->t, pb2->t, pb1->p, pb2->p,
1027 prev_range, si, Gcalc_function::shape_polygon))
1028 GCALC_DBUG_RETURN(1);
1029
1030 free_item(pb1);
1031 free_item(pb2);
1032 }
1033 m_poly_borders_hook= (Gcalc_dyn_list::Item **) &m_poly_borders;
1034 m_poly_borders= NULL;
1035 }
1036
1037 if (m_lines)
1038 {
1039 *m_lines_hook= NULL;
1040 if (m_lines->get_next() &&
1041 !m_lines->get_next()->get_next())
1042 {
1043 if (connect_threads(m_lines->incoming, m_lines->get_next()->incoming,
1044 m_lines->t, m_lines->get_next()->t,
1045 m_lines->p, m_lines->get_next()->p,
1046 NULL, si, Gcalc_function::shape_line))
1047 GCALC_DBUG_RETURN(1);
1048 }
1049 else
1050 {
1051 for (line *cur_line= m_lines; cur_line; cur_line= cur_line->get_next())
1052 {
1053 if (cur_line->incoming)
1054 {
1055 if (end_line(cur_line->t, si))
1056 GCALC_DBUG_RETURN(1);
1057 }
1058 else
1059 start_line(cur_line->t, cur_line->p, si);
1060 }
1061 }
1062 free_list(m_lines);
1063 m_lines= NULL;
1064 m_lines_hook= (Gcalc_dyn_list::Item **) &m_lines;
1065 }
1066
1067 if (bottom_threads)
1068 free_list(bottom_threads);
1069
1070 GCALC_DBUG_RETURN(0);
1071 }
1072
1073
add_single_point(const Gcalc_scan_iterator * si)1074 int Gcalc_operation_reducer::add_single_point(const Gcalc_scan_iterator *si)
1075 {
1076 res_point *rp= add_res_point(Gcalc_function::shape_point);
1077 GCALC_DBUG_ENTER("Gcalc_operation_reducer::add_single_point");
1078 if (!rp)
1079 GCALC_DBUG_RETURN(1);
1080 rp->glue= rp->up= rp->down= NULL;
1081 rp->set(si);
1082 GCALC_DBUG_RETURN(0);
1083 }
1084
1085
1086 Gcalc_operation_reducer::poly_border
get_pair_border(poly_border * b1)1087 *Gcalc_operation_reducer::get_pair_border(poly_border *b1)
1088 {
1089 poly_border *prev_b= b1;
1090 poly_border *result= b1->get_next();
1091 GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_pair_border");
1092 if (b1->prev_state)
1093 {
1094 if (b1->incoming)
1095 {
1096 /* Find the first outgoing, otherwise the last one. */
1097 while (result->incoming && result->get_next())
1098 {
1099 prev_b= result;
1100 result= result->get_next();
1101 }
1102 }
1103 else
1104 {
1105 /* Get the last one */
1106 while (result->get_next())
1107 {
1108 prev_b= result;
1109 result= result->get_next();
1110 }
1111 }
1112 }
1113 else /* !b1->prev_state */
1114 {
1115 if (b1->incoming)
1116 {
1117 /* Get the next incoming, otherwise the last one. */
1118 while (!result->incoming && result->get_next())
1119 {
1120 prev_b= result;
1121 result= result->get_next();
1122 }
1123 }
1124 else
1125 {
1126 /* Just pick the next one */
1127 }
1128 }
1129 /* Delete the result from the list. */
1130 prev_b->next= result->next;
1131 GCALC_DBUG_RETURN(result);
1132 }
1133
1134
connect_threads(int incoming_a,int incoming_b,active_thread * ta,active_thread * tb,const Gcalc_scan_iterator::point * pa,const Gcalc_scan_iterator::point * pb,active_thread * prev_range,const Gcalc_scan_iterator * si,Gcalc_function::shape_type s_t)1135 int Gcalc_operation_reducer::connect_threads(
1136 int incoming_a, int incoming_b,
1137 active_thread *ta, active_thread *tb,
1138 const Gcalc_scan_iterator::point *pa, const Gcalc_scan_iterator::point *pb,
1139 active_thread *prev_range,
1140 const Gcalc_scan_iterator *si, Gcalc_function::shape_type s_t)
1141 {
1142 GCALC_DBUG_ENTER("Gcalc_operation_reducer::connect_threads");
1143 GCALC_DBUG_PRINT(("incoming %d %d", incoming_a, incoming_b));
1144 if (incoming_a && incoming_b)
1145 {
1146 res_point *rpa, *rpb;
1147 GCALC_DBUG_ASSERT(ta->rp->type == tb->rp->type);
1148 if (!(rpa= add_res_point(ta->rp->type)) ||
1149 !(rpb= add_res_point(ta->rp->type)))
1150 GCALC_DBUG_RETURN(1);
1151 rpa->down= ta->rp;
1152 rpb->down= tb->rp;
1153 rpb->glue= rpa;
1154 rpa->glue= rpb;
1155 rpa->up= rpb->up= NULL;
1156 ta->rp->up= rpa;
1157 tb->rp->up= rpb;
1158 rpa->set(si);
1159 rpb->set(si);
1160 ta->rp= tb->rp= NULL;
1161 GCALC_DBUG_RETURN(0);
1162 }
1163 if (!incoming_a)
1164 {
1165 GCALC_DBUG_ASSERT(!incoming_b);
1166
1167 res_point *rp0, *rp1;
1168 if (!(rp0= add_res_point(s_t)) || !(rp1= add_res_point(s_t)))
1169 GCALC_DBUG_RETURN(1);
1170 rp0->glue= rp1;
1171 rp1->glue= rp0;
1172 rp0->set(si);
1173 rp1->set(si);
1174 rp0->down= rp1->down= NULL;
1175 ta->rp= rp0;
1176 tb->rp= rp1;
1177 ta->p1= pa->pi;
1178 ta->p2= pa->next_pi;
1179
1180 tb->p1= pb->pi;
1181 tb->p2= pb->next_pi;
1182
1183 if (prev_range)
1184 {
1185 rp0->outer_poly= prev_range->thread_start;
1186 tb->thread_start= prev_range->thread_start;
1187 /* Check if needed */
1188 ta->thread_start= prev_range->thread_start;
1189 }
1190 else
1191 {
1192 rp0->outer_poly= 0;
1193 ta->thread_start= rp0;
1194 /* Check if needed */
1195 tb->thread_start= rp0;
1196 }
1197 GCALC_DBUG_RETURN(0);
1198 }
1199 /* else, if only ta is incoming */
1200
1201 GCALC_DBUG_ASSERT(tb != ta);
1202 tb->rp= ta->rp;
1203 tb->thread_start= ta->thread_start;
1204 if (Gcalc_scan_iterator::point::
1205 cmp_dx_dy(ta->p1, ta->p2, pb->pi, pb->next_pi) != 0)
1206 {
1207 if (si->intersection_step() ?
1208 continue_i_range(tb, si->get_cur_pi()) :
1209 continue_range(tb, si->get_cur_pi(), pb->next_pi))
1210 GCALC_DBUG_RETURN(1);
1211 }
1212 tb->p1= pb->pi;
1213 tb->p2= pb->next_pi;
1214
1215 GCALC_DBUG_RETURN(0);
1216 }
1217
1218
start_line(active_thread * t,const Gcalc_scan_iterator::point * p,const Gcalc_scan_iterator * si)1219 int Gcalc_operation_reducer::start_line(active_thread *t,
1220 const Gcalc_scan_iterator::point *p,
1221 const Gcalc_scan_iterator *si)
1222 {
1223 res_point *rp= add_res_point(Gcalc_function::shape_line);
1224 GCALC_DBUG_ENTER("Gcalc_operation_reducer::start_line");
1225 if (!rp)
1226 GCALC_DBUG_RETURN(1);
1227 rp->glue= rp->down= NULL;
1228 rp->set(si);
1229 t->rp= rp;
1230 t->p1= p->pi;
1231 t->p2= p->next_pi;
1232 GCALC_DBUG_RETURN(0);
1233 }
1234
1235
end_line(active_thread * t,const Gcalc_scan_iterator * si)1236 int Gcalc_operation_reducer::end_line(active_thread *t,
1237 const Gcalc_scan_iterator *si)
1238 {
1239 GCALC_DBUG_ENTER("Gcalc_operation_reducer::end_line");
1240 GCALC_DBUG_ASSERT(t->rp->type == Gcalc_function::shape_line);
1241 res_point *rp= add_res_point(Gcalc_function::shape_line);
1242 if (!rp)
1243 GCALC_DBUG_RETURN(1);
1244 rp->glue= rp->up= NULL;
1245 rp->down= t->rp;
1246 rp->set(si);
1247 t->rp->up= rp;
1248 t->rp= NULL;
1249
1250 GCALC_DBUG_RETURN(0);
1251 }
1252
1253
count_all(Gcalc_heap * hp)1254 int Gcalc_operation_reducer::count_all(Gcalc_heap *hp)
1255 {
1256 Gcalc_scan_iterator si;
1257 GCALC_DBUG_ENTER("Gcalc_operation_reducer::count_all");
1258 si.init(hp);
1259 GCALC_SET_TERMINATED(si.killed, killed);
1260 while (si.more_points())
1261 {
1262 if (si.step())
1263 GCALC_DBUG_RETURN(1);
1264 if (count_slice(&si))
1265 GCALC_DBUG_RETURN(1);
1266 }
1267 GCALC_DBUG_RETURN(0);
1268 }
1269
free_result(res_point * res)1270 inline void Gcalc_operation_reducer::free_result(res_point *res)
1271 {
1272 if ((*res->prev_hook= res->next))
1273 {
1274 res->get_next()->prev_hook= res->prev_hook;
1275 }
1276 free_item(res);
1277 }
1278
1279
get_single_result(res_point * res,Gcalc_result_receiver * storage)1280 inline int Gcalc_operation_reducer::get_single_result(res_point *res,
1281 Gcalc_result_receiver *storage)
1282 {
1283 GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_single_result");
1284 if (res->intersection_point)
1285 {
1286 double x, y;
1287 res->pi->calc_xy(&x, &y);
1288 if (storage->single_point(x,y))
1289 GCALC_DBUG_RETURN(1);
1290 }
1291 else
1292 if (storage->single_point(res->pi->node.shape.x, res->pi->node.shape.y))
1293 GCALC_DBUG_RETURN(1);
1294 free_result(res);
1295 GCALC_DBUG_RETURN(0);
1296 }
1297
1298
get_result_thread(res_point * cur,Gcalc_result_receiver * storage,int move_upward,res_point * first_poly_node)1299 int Gcalc_operation_reducer::get_result_thread(res_point *cur,
1300 Gcalc_result_receiver *storage,
1301 int move_upward,
1302 res_point *first_poly_node)
1303 {
1304 res_point *next;
1305 bool glue_step= false;
1306 double x, y;
1307 GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_result_thread");
1308 while (cur)
1309 {
1310 if (!glue_step)
1311 {
1312 if (cur->intersection_point)
1313 {
1314 cur->pi->calc_xy(&x, &y);
1315 }
1316 else
1317 {
1318 x= cur->pi->node.shape.x;
1319 y= cur->pi->node.shape.y;
1320 }
1321 if (storage->add_point(x, y))
1322 GCALC_DBUG_RETURN(1);
1323 }
1324
1325 next= move_upward ? cur->up : cur->down;
1326 if (!next && !glue_step)
1327 {
1328 next= cur->glue;
1329 move_upward^= 1;
1330 glue_step= true;
1331 if (next)
1332 next->glue= NULL;
1333 }
1334 else
1335 glue_step= false;
1336
1337 cur->first_poly_node= first_poly_node;
1338 free_result(cur);
1339 cur= next;
1340 }
1341 GCALC_DBUG_RETURN(0);
1342 }
1343
1344
get_polygon_result(res_point * cur,Gcalc_result_receiver * storage,res_point * first_poly_node)1345 int Gcalc_operation_reducer::get_polygon_result(res_point *cur,
1346 Gcalc_result_receiver *storage,
1347 res_point *first_poly_node)
1348 {
1349 GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_polygon_result");
1350 res_point *glue= cur->glue;
1351 glue->up->down= NULL;
1352 free_result(glue);
1353 GCALC_DBUG_RETURN(get_result_thread(cur, storage, 1, first_poly_node) ||
1354 storage->complete_shape());
1355 }
1356
1357
get_line_result(res_point * cur,Gcalc_result_receiver * storage)1358 int Gcalc_operation_reducer::get_line_result(res_point *cur,
1359 Gcalc_result_receiver *storage)
1360 {
1361 res_point *next;
1362 res_point *cur_orig= cur;
1363 int move_upward= 1;
1364 GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_line_result");
1365 if (cur->glue)
1366 {
1367 /* Here we have to find the beginning of the line */
1368 next= cur->up;
1369 move_upward= 1;
1370 while (next)
1371 {
1372 cur= next;
1373 next= move_upward ? next->up : next->down;
1374 if (!next)
1375 {
1376 next= cur->glue;
1377 if (next == cur_orig)
1378 {
1379 /* It's the line loop */
1380 cur= cur_orig;
1381 cur->glue->glue= NULL;
1382 move_upward= 1;
1383 break;
1384 }
1385 move_upward^= 1;
1386 }
1387 }
1388 }
1389
1390 GCALC_DBUG_RETURN(get_result_thread(cur, storage, move_upward, 0) ||
1391 storage->complete_shape());
1392 }
1393
1394
get_result(Gcalc_result_receiver * storage)1395 int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage)
1396 {
1397 poly_instance *polygons= NULL;
1398
1399 GCALC_DBUG_ENTER("Gcalc_operation_reducer::get_result");
1400 *m_res_hook= NULL;
1401
1402 /* This is to workaround an old gcc's bug */
1403 if (m_res_hook == (Gcalc_dyn_list::Item **) &m_result)
1404 goto done;
1405
1406 while (m_result)
1407 {
1408 Gcalc_function::shape_type shape= m_result->type;
1409 if (shape == Gcalc_function::shape_point)
1410 {
1411 if (get_single_result(m_result, storage))
1412 GCALC_DBUG_RETURN(1);
1413 continue;
1414 }
1415 if (shape == Gcalc_function::shape_polygon)
1416 {
1417 if (m_result->outer_poly)
1418 {
1419 uint32 insert_position, hole_position, position_shift;
1420 poly_instance *cur_poly;
1421 insert_position= m_result->outer_poly->first_poly_node->poly_position;
1422 GCALC_DBUG_ASSERT(insert_position);
1423 hole_position= storage->position();
1424 storage->start_shape(Gcalc_function::shape_hole);
1425 if (get_polygon_result(m_result, storage,
1426 m_result->outer_poly->first_poly_node) ||
1427 storage->move_hole(insert_position, hole_position,
1428 &position_shift))
1429 GCALC_DBUG_RETURN(1);
1430 for (cur_poly= polygons;
1431 cur_poly && *cur_poly->after_poly_position >= insert_position;
1432 cur_poly= cur_poly->get_next())
1433 *cur_poly->after_poly_position+= position_shift;
1434 }
1435 else
1436 {
1437 uint32 *poly_position= &m_result->poly_position;
1438 poly_instance *p= new_poly();
1439 p->after_poly_position= poly_position;
1440 p->next= polygons;
1441 polygons= p;
1442 storage->start_shape(Gcalc_function::shape_polygon);
1443 if (get_polygon_result(m_result, storage, m_result))
1444 GCALC_DBUG_RETURN(1);
1445 *poly_position= storage->position();
1446 }
1447 }
1448 else
1449 {
1450 storage->start_shape(shape);
1451 if (get_line_result(m_result, storage))
1452 GCALC_DBUG_RETURN(1);
1453 }
1454 }
1455
1456 done:
1457 m_res_hook= (Gcalc_dyn_list::Item **)&m_result;
1458 storage->done();
1459 GCALC_DBUG_RETURN(0);
1460 }
1461
1462
reset()1463 void Gcalc_operation_reducer::reset()
1464 {
1465 free_list((Gcalc_heap::Item **) &m_result, m_res_hook);
1466 m_res_hook= (Gcalc_dyn_list::Item **)&m_result;
1467 free_list(m_first_active_thread);
1468 }
1469
1470 #endif /*HAVE_SPATIAL*/
1471
1472