| 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 02111-1301 USA */ |
| 16 | |
| 17 | |
| 18 | #ifndef GCALC_SLICESCAN_INCLUDED |
| 19 | #define GCALC_SLICESCAN_INCLUDED |
| 20 | |
| 21 | #ifndef DBUG_OFF |
| 22 | // #define GCALC_CHECK_WITH_FLOAT |
| 23 | #else |
| 24 | #define GCALC_DBUG_OFF |
| 25 | #endif /*DBUG_OFF*/ |
| 26 | |
| 27 | #ifndef GCALC_DBUG_OFF |
| 28 | #define GCALC_DBUG_PRINT(b) DBUG_PRINT("Gcalc", b) |
| 29 | #define GCALC_DBUG_ENTER(a) DBUG_ENTER("Gcalc " a) |
| 30 | #define GCALC_DBUG_RETURN(r) DBUG_RETURN(r) |
| 31 | #define GCALC_DBUG_VOID_RETURN DBUG_VOID_RETURN |
| 32 | #define GCALC_DBUG_ASSERT(r) DBUG_ASSERT(r) |
| 33 | #else |
| 34 | #define GCALC_DBUG_PRINT(b) do {} while(0) |
| 35 | #define GCALC_DBUG_ENTER(a) do {} while(0) |
| 36 | #define GCALC_DBUG_RETURN(r) return (r) |
| 37 | #define GCALC_DBUG_VOID_RETURN do {} while(0) |
| 38 | #define GCALC_DBUG_ASSERT(r) do {} while(0) |
| 39 | #endif /*GCALC_DBUG_OFF*/ |
| 40 | |
| 41 | #define GCALC_TERMINATED(state_var) (state_var && (*state_var)) |
| 42 | #define GCALC_SET_TERMINATED(state_var, val) state_var= val |
| 43 | #define GCALC_DECL_TERMINATED_STATE(varname) \ |
| 44 | volatile int *varname; |
| 45 | |
| 46 | /* |
| 47 | Gcalc_dyn_list class designed to manage long lists of same-size objects |
| 48 | with the possible efficiency. |
| 49 | It allocates fixed-size blocks of memory (blk_size specified at the time |
| 50 | of creation). When new object is added to the list, it occupies part of |
| 51 | this block until it's full. Then the new block is allocated. |
| 52 | Freed objects are chained to the m_free list, and if it's not empty, the |
| 53 | newly added object is taken from this list instead the block. |
| 54 | */ |
| 55 | |
| 56 | class Gcalc_dyn_list |
| 57 | { |
| 58 | public: |
| 59 | class Item |
| 60 | { |
| 61 | public: |
| 62 | Item *next; |
| 63 | }; |
| 64 | |
| 65 | Gcalc_dyn_list(size_t blk_size, size_t sizeof_item); |
| 66 | ~Gcalc_dyn_list(); |
| 67 | Item *new_item() |
| 68 | { |
| 69 | Item *result; |
| 70 | if (m_free) |
| 71 | { |
| 72 | result= m_free; |
| 73 | m_free= m_free->next; |
| 74 | } |
| 75 | else |
| 76 | result= alloc_new_blk(); |
| 77 | |
| 78 | return result; |
| 79 | } |
| 80 | inline void free_item(Item *item) |
| 81 | { |
| 82 | item->next= m_free; |
| 83 | m_free= item; |
| 84 | } |
| 85 | inline void free_list(Item **list, Item **hook) |
| 86 | { |
| 87 | *hook= m_free; |
| 88 | m_free= *list; |
| 89 | } |
| 90 | |
| 91 | void free_list(Item *list) |
| 92 | { |
| 93 | Item **hook= &list; |
| 94 | while (*hook) |
| 95 | hook= &(*hook)->next; |
| 96 | free_list(&list, hook); |
| 97 | } |
| 98 | |
| 99 | void reset(); |
| 100 | void cleanup(); |
| 101 | |
| 102 | protected: |
| 103 | size_t m_blk_size; |
| 104 | size_t m_sizeof_item; |
| 105 | unsigned int m_points_per_blk; |
| 106 | void *m_first_blk; |
| 107 | void **m_blk_hook; |
| 108 | Item *m_free; |
| 109 | Item *m_keep; |
| 110 | |
| 111 | Item *alloc_new_blk(); |
| 112 | void format_blk(void* block); |
| 113 | inline Item *ptr_add(Item *ptr, int n_items) |
| 114 | { |
| 115 | return (Item *)(((char*)ptr) + n_items * m_sizeof_item); |
| 116 | } |
| 117 | }; |
| 118 | |
| 119 | /* Internal Gcalc coordinates to provide the precise calculations */ |
| 120 | |
| 121 | #define GCALC_DIG_BASE 1000000000 |
| 122 | typedef uint32 gcalc_digit_t; |
| 123 | typedef unsigned long long gcalc_coord2; |
| 124 | typedef gcalc_digit_t Gcalc_internal_coord; |
| 125 | #define GCALC_COORD_BASE 2 |
| 126 | #define GCALC_COORD_BASE2 4 |
| 127 | #define GCALC_COORD_BASE3 6 |
| 128 | #define GCALC_COORD_BASE4 8 |
| 129 | #define GCALC_COORD_BASE5 10 |
| 130 | |
| 131 | typedef gcalc_digit_t Gcalc_coord1[GCALC_COORD_BASE]; |
| 132 | typedef gcalc_digit_t Gcalc_coord2[GCALC_COORD_BASE*2]; |
| 133 | typedef gcalc_digit_t Gcalc_coord3[GCALC_COORD_BASE*3]; |
| 134 | |
| 135 | |
| 136 | void gcalc_mul_coord(Gcalc_internal_coord *result, int result_len, |
| 137 | const Gcalc_internal_coord *a, int a_len, |
| 138 | const Gcalc_internal_coord *b, int b_len); |
| 139 | |
| 140 | void gcalc_add_coord(Gcalc_internal_coord *result, int result_len, |
| 141 | const Gcalc_internal_coord *a, |
| 142 | const Gcalc_internal_coord *b); |
| 143 | |
| 144 | void gcalc_sub_coord(Gcalc_internal_coord *result, int result_len, |
| 145 | const Gcalc_internal_coord *a, |
| 146 | const Gcalc_internal_coord *b); |
| 147 | |
| 148 | int gcalc_cmp_coord(const Gcalc_internal_coord *a, |
| 149 | const Gcalc_internal_coord *b, int len); |
| 150 | |
| 151 | /* Internal coordinates declarations end. */ |
| 152 | |
| 153 | |
| 154 | typedef uint gcalc_shape_info; |
| 155 | |
| 156 | /* |
| 157 | Gcalc_heap represents the 'dynamic list' of Info objects, that |
| 158 | contain information about vertexes of all the shapes that take |
| 159 | part in some spatial calculation. Can become quite long. |
| 160 | After filled, the list is usually sorted and then walked through |
| 161 | in the slicescan algorithm. |
| 162 | The Gcalc_heap and the algorithm can only operate with two |
| 163 | kinds of shapes - polygon and polyline. So all the spatial |
| 164 | objects should be represented as sets of these two. |
| 165 | */ |
| 166 | |
| 167 | class Gcalc_heap : public Gcalc_dyn_list |
| 168 | { |
| 169 | public: |
| 170 | enum node_type |
| 171 | { |
| 172 | nt_shape_node, |
| 173 | nt_intersection, |
| 174 | nt_eq_node |
| 175 | }; |
| 176 | class Info : public Gcalc_dyn_list::Item |
| 177 | { |
| 178 | public: |
| 179 | node_type type; |
| 180 | union |
| 181 | { |
| 182 | struct |
| 183 | { |
| 184 | /* nt_shape_node */ |
| 185 | gcalc_shape_info shape; |
| 186 | Info *left; |
| 187 | Info *right; |
| 188 | double x,y; |
| 189 | Gcalc_coord1 ix, iy; |
| 190 | int top_node; |
| 191 | } shape; |
| 192 | struct |
| 193 | { |
| 194 | /* nt_intersection */ |
| 195 | /* Line p1-p2 supposed to intersect line p3-p4 */ |
| 196 | const Info *p1; |
| 197 | const Info *p2; |
| 198 | const Info *p3; |
| 199 | const Info *p4; |
| 200 | void *data; |
| 201 | int equal; |
| 202 | } intersection; |
| 203 | struct |
| 204 | { |
| 205 | /* nt_eq_node */ |
| 206 | const Info *node; |
| 207 | void *data; |
| 208 | } eq; |
| 209 | } node; |
| 210 | |
| 211 | bool is_bottom() const |
| 212 | { GCALC_DBUG_ASSERT(type == nt_shape_node); return !node.shape.left; } |
| 213 | bool is_top() const |
| 214 | { GCALC_DBUG_ASSERT(type == nt_shape_node); return node.shape.top_node; } |
| 215 | bool is_single_node() const |
| 216 | { return is_bottom() && is_top(); } |
| 217 | |
| 218 | void calc_xy(double *x, double *y) const; |
| 219 | int equal_pi(const Info *pi) const; |
| 220 | #ifdef GCALC_CHECK_WITH_FLOAT |
| 221 | void calc_xy_ld(long double *x, long double *y) const; |
| 222 | #endif /*GCALC_CHECK_WITH_FLOAT*/ |
| 223 | |
| 224 | Info *get_next() { return (Info *)next; } |
| 225 | const Info *get_next() const { return (const Info *)next; } |
| 226 | }; |
| 227 | |
| 228 | Gcalc_heap(size_t blk_size=8192) : |
| 229 | Gcalc_dyn_list(blk_size, sizeof(Info)), |
| 230 | m_hook(&m_first), m_n_points(0) |
| 231 | {} |
| 232 | void set_extent(double xmin, double xmax, double ymin, double ymax); |
| 233 | Info *new_point_info(double x, double y, gcalc_shape_info shape); |
| 234 | void free_point_info(Info *i, Gcalc_dyn_list::Item **i_hook); |
| 235 | Info *new_intersection(const Info *p1, const Info *p2, |
| 236 | const Info *p3, const Info *p4); |
| 237 | void prepare_operation(); |
| 238 | inline bool ready() const { return m_hook == NULL; } |
| 239 | Info *get_first() { return (Info *)m_first; } |
| 240 | const Info *get_first() const { return (const Info *)m_first; } |
| 241 | Gcalc_dyn_list::Item **get_last_hook() { return m_hook; } |
| 242 | void reset(); |
| 243 | #ifdef GCALC_CHECK_WITH_FLOAT |
| 244 | long double get_double(const Gcalc_internal_coord *c) const; |
| 245 | #endif /*GCALC_CHECK_WITH_FLOAT*/ |
| 246 | double coord_extent; |
| 247 | Gcalc_dyn_list::Item **get_cur_hook() { return m_hook; } |
| 248 | |
| 249 | private: |
| 250 | Gcalc_dyn_list::Item *m_first; |
| 251 | Gcalc_dyn_list::Item **m_hook; |
| 252 | int m_n_points; |
| 253 | }; |
| 254 | |
| 255 | |
| 256 | /* |
| 257 | the spatial object has to be represented as a set of |
| 258 | simple polygones and polylines to be sent to the slicescan. |
| 259 | |
| 260 | Gcalc_shape_transporter class and his descendants are used to |
| 261 | simplify storing the information about the shape into necessary structures. |
| 262 | This base class only fills the Gcalc_heap with the information about |
| 263 | shapes and vertices. |
| 264 | |
| 265 | Normally the Gcalc_shape_transporter family object is sent as a parameter |
| 266 | to the 'get_shapes' method of an 'spatial' object so it can pass |
| 267 | the spatial information about itself. The virtual methods are |
| 268 | treating this data in a way the caller needs. |
| 269 | */ |
| 270 | |
| 271 | class Gcalc_shape_transporter |
| 272 | { |
| 273 | private: |
| 274 | Gcalc_heap::Info *m_first; |
| 275 | Gcalc_heap::Info *m_prev; |
| 276 | Gcalc_dyn_list::Item **m_prev_hook; |
| 277 | int m_shape_started; |
| 278 | void int_complete(); |
| 279 | protected: |
| 280 | Gcalc_heap *m_heap; |
| 281 | int int_single_point(gcalc_shape_info Info, double x, double y); |
| 282 | int int_add_point(gcalc_shape_info Info, double x, double y); |
| 283 | void int_start_line() |
| 284 | { |
| 285 | DBUG_ASSERT(!m_shape_started); |
| 286 | m_shape_started= 1; |
| 287 | m_first= m_prev= NULL; |
| 288 | } |
| 289 | void int_complete_line() |
| 290 | { |
| 291 | DBUG_ASSERT(m_shape_started== 1); |
| 292 | int_complete(); |
| 293 | m_shape_started= 0; |
| 294 | } |
| 295 | void int_start_ring() |
| 296 | { |
| 297 | DBUG_ASSERT(m_shape_started== 2); |
| 298 | m_shape_started= 3; |
| 299 | m_first= m_prev= NULL; |
| 300 | } |
| 301 | void int_complete_ring() |
| 302 | { |
| 303 | DBUG_ASSERT(m_shape_started== 3); |
| 304 | int_complete(); |
| 305 | m_shape_started= 2; |
| 306 | } |
| 307 | void int_start_poly() |
| 308 | { |
| 309 | DBUG_ASSERT(!m_shape_started); |
| 310 | m_shape_started= 2; |
| 311 | } |
| 312 | void int_complete_poly() |
| 313 | { |
| 314 | DBUG_ASSERT(m_shape_started== 2); |
| 315 | m_shape_started= 0; |
| 316 | } |
| 317 | bool line_started() { return m_shape_started == 1; }; |
| 318 | public: |
| 319 | Gcalc_shape_transporter(Gcalc_heap *heap) : |
| 320 | m_shape_started(0), m_heap(heap) {} |
| 321 | |
| 322 | virtual int single_point(double x, double y)=0; |
| 323 | virtual int start_line()=0; |
| 324 | virtual int complete_line()=0; |
| 325 | virtual int start_poly()=0; |
| 326 | virtual int complete_poly()=0; |
| 327 | virtual int start_ring()=0; |
| 328 | virtual int complete_ring()=0; |
| 329 | virtual int add_point(double x, double y)=0; |
| 330 | virtual int start_collection(int n_objects) { return 0; } |
| 331 | virtual int empty_shape() { return 0; } |
| 332 | int start_simple_poly() |
| 333 | { |
| 334 | return start_poly() || start_ring(); |
| 335 | } |
| 336 | int complete_simple_poly() |
| 337 | { |
| 338 | return complete_ring() || complete_poly(); |
| 339 | } |
| 340 | virtual ~Gcalc_shape_transporter() {} |
| 341 | }; |
| 342 | |
| 343 | |
| 344 | enum Gcalc_scan_events |
| 345 | { |
| 346 | scev_none= 0, |
| 347 | scev_point= 1, /* Just a new point in thread */ |
| 348 | scev_thread= 2, /* Start of the new thread */ |
| 349 | scev_two_threads= 4, /* A couple of new threads started */ |
| 350 | scev_intersection= 8, /* Intersection happened */ |
| 351 | scev_end= 16, /* Single thread finished */ |
| 352 | scev_two_ends= 32, /* A couple of threads finished */ |
| 353 | scev_single_point= 64 /* Got single point */ |
| 354 | }; |
| 355 | |
| 356 | |
| 357 | /* |
| 358 | Gcalc_scan_iterator incapsulates the slisescan algorithm. |
| 359 | It takes filled Gcalc_heap as an datasource. Then can be |
| 360 | iterated trought the vertexes and intersection points with |
| 361 | the step() method. After the 'step()' one usually observes |
| 362 | the current 'slice' to do the necessary calculations, like |
| 363 | looking for intersections, calculating the area, whatever. |
| 364 | */ |
| 365 | |
| 366 | class Gcalc_scan_iterator : public Gcalc_dyn_list |
| 367 | { |
| 368 | public: |
| 369 | class point : public Gcalc_dyn_list::Item |
| 370 | { |
| 371 | public: |
| 372 | Gcalc_coord1 dx; |
| 373 | Gcalc_coord1 dy; |
| 374 | Gcalc_heap::Info *pi; |
| 375 | Gcalc_heap::Info *next_pi; |
| 376 | Gcalc_heap::Info *ev_pi; |
| 377 | const Gcalc_coord1 *l_border; |
| 378 | const Gcalc_coord1 *r_border; |
| 379 | point *ev_next; |
| 380 | |
| 381 | Gcalc_scan_events event; |
| 382 | |
| 383 | inline const point *c_get_next() const |
| 384 | { return (const point *)next; } |
| 385 | inline bool is_bottom() const { return !next_pi; } |
| 386 | gcalc_shape_info get_shape() const { return pi->node.shape.shape; } |
| 387 | inline point *get_next() { return (point *)next; } |
| 388 | inline const point *get_next() const { return (const point *)next; } |
| 389 | /* Compare the dx_dy parameters regarding the horiz_dir */ |
| 390 | /* returns -1 if less, 0 if equal, 1 if bigger */ |
| 391 | static int cmp_dx_dy(const Gcalc_coord1 dx_a, |
| 392 | const Gcalc_coord1 dy_a, |
| 393 | const Gcalc_coord1 dx_b, |
| 394 | const Gcalc_coord1 dy_b); |
| 395 | static int cmp_dx_dy(const Gcalc_heap::Info *p1, |
| 396 | const Gcalc_heap::Info *p2, |
| 397 | const Gcalc_heap::Info *p3, |
| 398 | const Gcalc_heap::Info *p4); |
| 399 | int cmp_dx_dy(const point *p) const; |
| 400 | point **next_ptr() { return (point **) &next; } |
| 401 | #ifndef GCALC_DBUG_OFF |
| 402 | unsigned int thread; |
| 403 | #endif /*GCALC_DBUG_OFF*/ |
| 404 | #ifdef GCALC_CHECK_WITH_FLOAT |
| 405 | void calc_x(long double *x, long double y, long double ix) const; |
| 406 | #endif /*GCALC_CHECK_WITH_FLOAT*/ |
| 407 | }; |
| 408 | |
| 409 | /* That class introduced mostly for the 'typecontrol' reason. */ |
| 410 | /* only difference from the point classis the get_next() function. */ |
| 411 | class event_point : public point |
| 412 | { |
| 413 | public: |
| 414 | inline const event_point *get_next() const |
| 415 | { return (const event_point*) ev_next; } |
| 416 | int simple_event() const |
| 417 | { |
| 418 | return !ev_next ? (event & (scev_point | scev_end)) : |
| 419 | (!ev_next->ev_next && event == scev_two_ends); |
| 420 | } |
| 421 | }; |
| 422 | |
| 423 | class intersection_info : public Gcalc_dyn_list::Item |
| 424 | { |
| 425 | public: |
| 426 | point *edge_a; |
| 427 | point *edge_b; |
| 428 | |
| 429 | Gcalc_coord2 t_a; |
| 430 | Gcalc_coord2 t_b; |
| 431 | int t_calculated; |
| 432 | Gcalc_coord3 x_exp; |
| 433 | int x_calculated; |
| 434 | Gcalc_coord3 y_exp; |
| 435 | int y_calculated; |
| 436 | void calc_t() |
| 437 | {if (!t_calculated) do_calc_t(); } |
| 438 | void calc_y_exp() |
| 439 | { if (!y_calculated) do_calc_y(); } |
| 440 | void calc_x_exp() |
| 441 | { if (!x_calculated) do_calc_x(); } |
| 442 | |
| 443 | void do_calc_t(); |
| 444 | void do_calc_x(); |
| 445 | void do_calc_y(); |
| 446 | }; |
| 447 | |
| 448 | |
| 449 | class slice_state |
| 450 | { |
| 451 | public: |
| 452 | point *slice; |
| 453 | point **event_position_hook; |
| 454 | point *event_end; |
| 455 | const Gcalc_heap::Info *pi; |
| 456 | }; |
| 457 | |
| 458 | public: |
| 459 | Gcalc_scan_iterator(size_t blk_size= 8192); |
| 460 | |
| 461 | GCALC_DECL_TERMINATED_STATE(killed) |
| 462 | |
| 463 | void init(Gcalc_heap *points); /* Iterator can be reused */ |
| 464 | void reset(); |
| 465 | int step(); |
| 466 | |
| 467 | Gcalc_heap::Info *more_points() { return m_cur_pi; } |
| 468 | bool more_trapezoids() |
| 469 | { return m_cur_pi && m_cur_pi->next; } |
| 470 | |
| 471 | const point *get_bottom_points() const |
| 472 | { return m_bottom_points; } |
| 473 | const point *get_event_position() const |
| 474 | { return *state.event_position_hook; } |
| 475 | const point *get_event_end() const |
| 476 | { return state.event_end; } |
| 477 | const event_point *get_events() const |
| 478 | { return (const event_point *) |
| 479 | (*state.event_position_hook == state.event_end ? |
| 480 | m_bottom_points : *state.event_position_hook); } |
| 481 | const point *get_b_slice() const { return state.slice; } |
| 482 | double get_h() const; |
| 483 | double get_y() const; |
| 484 | double get_event_x() const; |
| 485 | double get_sp_x(const point *sp) const; |
| 486 | int intersection_step() const |
| 487 | { return state.pi->type == Gcalc_heap::nt_intersection; } |
| 488 | const Gcalc_heap::Info *get_cur_pi() const |
| 489 | { |
| 490 | return state.pi; |
| 491 | } |
| 492 | |
| 493 | private: |
| 494 | Gcalc_heap *m_heap; |
| 495 | Gcalc_heap::Info *m_cur_pi; |
| 496 | slice_state state; |
| 497 | |
| 498 | #ifndef GCALC_DBUG_OFF |
| 499 | unsigned int m_cur_thread; |
| 500 | #endif /*GCALC_DBUG_OFF*/ |
| 501 | |
| 502 | point *m_bottom_points; |
| 503 | point **m_bottom_hook; |
| 504 | |
| 505 | int node_scan(); |
| 506 | void eq_scan(); |
| 507 | void intersection_scan(); |
| 508 | void remove_bottom_node(); |
| 509 | int insert_top_node(); |
| 510 | int add_intersection(point *sp_a, point *sp_b, |
| 511 | Gcalc_heap::Info *pi_from); |
| 512 | int add_eq_node(Gcalc_heap::Info *node, point *sp); |
| 513 | int add_events_for_node(point *sp_node); |
| 514 | |
| 515 | point *new_slice_point() |
| 516 | { |
| 517 | point *new_point= (point *)new_item(); |
| 518 | return new_point; |
| 519 | } |
| 520 | intersection_info *new_intersection_info(point *a, point *b) |
| 521 | { |
| 522 | intersection_info *ii= (intersection_info *)new_item(); |
| 523 | ii->edge_a= a; |
| 524 | ii->edge_b= b; |
| 525 | ii->t_calculated= ii->x_calculated= ii->y_calculated= 0; |
| 526 | return ii; |
| 527 | } |
| 528 | int arrange_event(int do_sorting, int n_intersections); |
| 529 | static double get_pure_double(const Gcalc_internal_coord *d, int d_len); |
| 530 | }; |
| 531 | |
| 532 | |
| 533 | /* |
| 534 | Gcalc_trapezoid_iterator simplifies the calculations on |
| 535 | the current slice of the Gcalc_scan_iterator. |
| 536 | One can walk through the trapezoids formed between |
| 537 | previous and current slices. |
| 538 | */ |
| 539 | |
| 540 | #ifdef TMP_BLOCK |
| 541 | class Gcalc_trapezoid_iterator |
| 542 | { |
| 543 | protected: |
| 544 | const Gcalc_scan_iterator::point *sp0; |
| 545 | const Gcalc_scan_iterator::point *sp1; |
| 546 | public: |
| 547 | Gcalc_trapezoid_iterator(const Gcalc_scan_iterator *scan_i) : |
| 548 | sp0(scan_i->get_b_slice()), |
| 549 | sp1(scan_i->get_t_slice()) |
| 550 | {} |
| 551 | |
| 552 | inline bool more() const { return sp1 && sp1->next; } |
| 553 | |
| 554 | const Gcalc_scan_iterator::point *lt() const { return sp1; } |
| 555 | const Gcalc_scan_iterator::point *lb() const { return sp0; } |
| 556 | const Gcalc_scan_iterator::point *rb() const |
| 557 | { |
| 558 | const Gcalc_scan_iterator::point *result= sp0; |
| 559 | while ((result= result->c_get_next())->is_bottom()) |
| 560 | {} |
| 561 | return result; |
| 562 | } |
| 563 | const Gcalc_scan_iterator::point *rt() const |
| 564 | { return sp1->c_get_next(); } |
| 565 | |
| 566 | void operator++() |
| 567 | { |
| 568 | sp0= rb(); |
| 569 | sp1= rt(); |
| 570 | } |
| 571 | }; |
| 572 | #endif /*TMP_BLOCK*/ |
| 573 | |
| 574 | |
| 575 | /* |
| 576 | Gcalc_point_iterator simplifies the calculations on |
| 577 | the current slice of the Gcalc_scan_iterator. |
| 578 | One can walk through the points on the current slice. |
| 579 | */ |
| 580 | |
| 581 | class Gcalc_point_iterator |
| 582 | { |
| 583 | protected: |
| 584 | const Gcalc_scan_iterator::point *sp; |
| 585 | public: |
| 586 | Gcalc_point_iterator(const Gcalc_scan_iterator *scan_i): |
| 587 | sp(scan_i->get_b_slice()) |
| 588 | {} |
| 589 | |
| 590 | inline bool more() const { return sp != NULL; } |
| 591 | inline void operator++() { sp= sp->c_get_next(); } |
| 592 | inline const Gcalc_scan_iterator::point *point() const { return sp; } |
| 593 | inline const Gcalc_heap::Info *get_pi() const { return sp->pi; } |
| 594 | inline gcalc_shape_info get_shape() const { return sp->get_shape(); } |
| 595 | inline void restart(const Gcalc_scan_iterator *scan_i) |
| 596 | { sp= scan_i->get_b_slice(); } |
| 597 | }; |
| 598 | |
| 599 | #endif /*GCALC_SLICESCAN_INCLUDED*/ |
| 600 | |
| 601 | |