2011-05-04 20:20:17 +02:00
|
|
|
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
|
2011-10-06 14:41:28 +02:00
|
|
|
Copyright (C) 2011 Monty Program Ab.
|
2011-05-04 20:20:17 +02:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef GCALC_SLICESCAN_INCLUDED
|
|
|
|
#define GCALC_SLICESCAN_INCLUDED
|
|
|
|
|
2011-10-04 12:01:21 +02:00
|
|
|
#ifndef DBUG_OFF
|
|
|
|
#define GCALC_CHECK_WITH_FLOAT
|
|
|
|
#else
|
|
|
|
#define GCALC_DBUG_OFF
|
|
|
|
#endif /*DBUG_OFF*/
|
|
|
|
|
2011-10-04 12:29:39 +02:00
|
|
|
#ifndef GCALC_DBUG_OFF
|
2011-10-04 12:01:21 +02:00
|
|
|
#define GCALC_DBUG_PRINT(b) DBUG_PRINT("Gcalc", b)
|
|
|
|
#define GCALC_DBUG_ENTER(a) DBUG_ENTER("Gcalc "a)
|
|
|
|
#define GCALC_DBUG_RETURN(r) DBUG_RETURN(r)
|
|
|
|
#define GCALC_DBUG_ASSERT(r) DBUG_ASSERT(r)
|
2011-10-04 12:29:39 +02:00
|
|
|
#else
|
|
|
|
#define GCALC_DBUG_PRINT(b) do {} while(0)
|
|
|
|
#define GCALC_DBUG_ENTER(a) do {} while(0)
|
|
|
|
#define GCALC_DBUG_RETURN(r) return (r)
|
|
|
|
#define GCALC_DBUG_ASSERT(r) do {} while(0)
|
|
|
|
#endif /*GCALC_DBUG_OFF*/
|
2011-05-04 20:20:17 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Gcalc_dyn_list class designed to manage long lists of same-size objects
|
|
|
|
with the possible efficiency.
|
|
|
|
It allocates fixed-size blocks of memory (blk_size specified at the time
|
|
|
|
of creation). When new object is added to the list, it occupies part of
|
|
|
|
this block until it's full. Then the new block is allocated.
|
|
|
|
Freed objects are chained to the m_free list, and if it's not empty, the
|
|
|
|
newly added object is taken from this list instead the block.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Gcalc_dyn_list
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
class Item
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Item *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
Gcalc_dyn_list(size_t blk_size, size_t sizeof_item);
|
|
|
|
~Gcalc_dyn_list();
|
|
|
|
Item *new_item()
|
|
|
|
{
|
|
|
|
Item *result;
|
|
|
|
if (m_free)
|
|
|
|
{
|
|
|
|
result= m_free;
|
|
|
|
m_free= m_free->next;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result= alloc_new_blk();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
inline void free_item(Item *item)
|
|
|
|
{
|
|
|
|
item->next= m_free;
|
|
|
|
m_free= item;
|
|
|
|
}
|
2011-10-05 11:45:39 +02:00
|
|
|
inline void free_list(Item **list, Item **hook)
|
2011-05-04 20:20:17 +02:00
|
|
|
{
|
2011-10-05 11:45:39 +02:00
|
|
|
*hook= m_free;
|
|
|
|
m_free= *list;
|
2011-05-04 20:20:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void free_list(Item *list)
|
|
|
|
{
|
|
|
|
Item **hook= &list;
|
|
|
|
while (*hook)
|
|
|
|
hook= &(*hook)->next;
|
2011-10-05 11:45:39 +02:00
|
|
|
free_list(&list, hook);
|
2011-05-04 20:20:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void reset();
|
|
|
|
void cleanup();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
size_t m_blk_size;
|
|
|
|
size_t m_sizeof_item;
|
|
|
|
unsigned int m_points_per_blk;
|
|
|
|
void *m_first_blk;
|
|
|
|
void **m_blk_hook;
|
|
|
|
Item *m_free;
|
|
|
|
Item *m_keep;
|
|
|
|
|
|
|
|
Item *alloc_new_blk();
|
|
|
|
void format_blk(void* block);
|
|
|
|
inline Item *ptr_add(Item *ptr, int n_items)
|
|
|
|
{
|
|
|
|
return (Item *)(((char*)ptr) + n_items * m_sizeof_item);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-09-20 21:04:41 +02:00
|
|
|
/* Internal Gcalc coordinates to provide the precise calculations */
|
|
|
|
|
2011-10-05 11:45:39 +02:00
|
|
|
#define GCALC_DIG_BASE 1000000000
|
|
|
|
typedef int32 gcalc_digit_t;
|
|
|
|
typedef long long gcalc_coord2;
|
2011-09-20 21:04:41 +02:00
|
|
|
|
2011-10-05 11:45:39 +02:00
|
|
|
#define GCALC_COORD_BASE 2
|
2011-09-20 21:04:41 +02:00
|
|
|
|
|
|
|
class Gcalc_internal_coord
|
|
|
|
{
|
|
|
|
public:
|
2011-10-05 11:45:39 +02:00
|
|
|
gcalc_digit_t *digits;
|
2011-09-20 21:04:41 +02:00
|
|
|
int sign;
|
|
|
|
int n_digits;
|
|
|
|
void set_zero();
|
|
|
|
int is_zero() const;
|
|
|
|
#ifdef GCALC_CHECK_WITH_FLOAT
|
2011-10-05 11:45:39 +02:00
|
|
|
static double *coord_extent;
|
2011-09-20 21:04:41 +02:00
|
|
|
long double get_double() const;
|
|
|
|
#endif /*GCALC_CHECK_WITH_FLOAT*/
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Gcalc_coord1 : public Gcalc_internal_coord
|
|
|
|
{
|
2011-10-05 11:45:39 +02:00
|
|
|
gcalc_digit_t c[GCALC_COORD_BASE];
|
2011-09-20 21:04:41 +02:00
|
|
|
public:
|
|
|
|
void init()
|
|
|
|
{
|
2011-10-05 11:45:39 +02:00
|
|
|
n_digits= GCALC_COORD_BASE;
|
2011-09-20 21:04:41 +02:00
|
|
|
digits= c;
|
|
|
|
}
|
2011-10-05 11:45:39 +02:00
|
|
|
int set_double(double d, double ext);
|
2011-09-20 21:04:41 +02:00
|
|
|
void copy(const Gcalc_coord1 *from);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Gcalc_coord2 : public Gcalc_internal_coord
|
|
|
|
{
|
2011-10-05 11:45:39 +02:00
|
|
|
gcalc_digit_t c[GCALC_COORD_BASE*2];
|
2011-09-20 21:04:41 +02:00
|
|
|
public:
|
|
|
|
void init()
|
|
|
|
{
|
2011-10-05 11:45:39 +02:00
|
|
|
n_digits= GCALC_COORD_BASE*2;
|
2011-09-20 21:04:41 +02:00
|
|
|
digits= c;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void gcalc_mul_coord(Gcalc_internal_coord *result,
|
|
|
|
const Gcalc_internal_coord *a,
|
|
|
|
const Gcalc_internal_coord *b);
|
|
|
|
|
|
|
|
void gcalc_add_coord(Gcalc_internal_coord *result,
|
|
|
|
const Gcalc_internal_coord *a,
|
|
|
|
const Gcalc_internal_coord *b);
|
|
|
|
|
|
|
|
void gcalc_sub_coord(Gcalc_internal_coord *result,
|
|
|
|
const Gcalc_internal_coord *a,
|
|
|
|
const Gcalc_internal_coord *b);
|
|
|
|
|
|
|
|
int gcalc_cmp_coord(const Gcalc_internal_coord *a,
|
|
|
|
const Gcalc_internal_coord *b);
|
|
|
|
|
|
|
|
/* Internal coordinates declarations end. */
|
|
|
|
|
|
|
|
|
2011-05-04 20:20:17 +02:00
|
|
|
typedef uint gcalc_shape_info;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Gcalc_heap represents the 'dynamic list' of Info objects, that
|
|
|
|
contain information about vertexes of all the shapes that take
|
|
|
|
part in some spatial calculation. Can become quite long.
|
|
|
|
After filled, the list is usually sorted and then walked through
|
|
|
|
in the slicescan algorithm.
|
|
|
|
The Gcalc_heap and the algorithm can only operate with two
|
|
|
|
kinds of shapes - polygon and polyline. So all the spatial
|
|
|
|
objects should be represented as sets of these two.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Gcalc_heap : public Gcalc_dyn_list
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
class Info : public Gcalc_dyn_list::Item
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
gcalc_shape_info shape;
|
|
|
|
Info *left;
|
|
|
|
Info *right;
|
|
|
|
double x,y;
|
2011-09-20 21:04:41 +02:00
|
|
|
Gcalc_coord1 ix, iy;
|
2011-05-04 20:20:17 +02:00
|
|
|
|
|
|
|
inline bool is_bottom() const { return !left; }
|
|
|
|
inline Info *get_next() { return (Info *)next; }
|
|
|
|
inline const Info *get_next() const { return (const Info *)next; }
|
|
|
|
};
|
2011-09-20 21:04:41 +02:00
|
|
|
class Intersection_info : public Gcalc_dyn_list::Item
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/* Line p1-p2 supposed to intersect line p3-p4 */
|
|
|
|
const Info *p1;
|
|
|
|
const Info *p2;
|
|
|
|
const Info *p3;
|
|
|
|
const Info *p4;
|
|
|
|
void calc_xy(double *x, double *y) const;
|
|
|
|
#ifdef GCALC_CHECK_WITH_FLOAT
|
|
|
|
void calc_xy_ld(long double *x, long double *y) const;
|
|
|
|
#endif /*GCALC_CHECK_WITH_FLOAT*/
|
|
|
|
};
|
2011-05-04 20:20:17 +02:00
|
|
|
|
|
|
|
Gcalc_heap(size_t blk_size=8192) :
|
2011-09-20 21:04:41 +02:00
|
|
|
Gcalc_dyn_list(blk_size, sizeof(Info)),
|
|
|
|
m_hook(&m_first), m_n_points(0),
|
|
|
|
m_intersection_hook((Gcalc_dyn_list::Item **) &m_first_intersection)
|
|
|
|
{}
|
|
|
|
Info *new_point_info(double x, double y, gcalc_shape_info shape);
|
|
|
|
Intersection_info *new_intersection(const Info *p1, const Info *p2,
|
|
|
|
const Info *p3, const Info *p4);
|
2011-05-04 20:20:17 +02:00
|
|
|
void prepare_operation();
|
|
|
|
inline bool ready() const { return m_hook == NULL; }
|
|
|
|
Info *get_first() { return (Info *)m_first; }
|
|
|
|
const Info *get_first() const { return (const Info *)m_first; }
|
|
|
|
Gcalc_dyn_list::Item **get_last_hook() { return m_hook; }
|
|
|
|
void reset();
|
2011-10-05 11:45:39 +02:00
|
|
|
#ifdef GCALC_CHECK_WITH_FLOAT
|
|
|
|
long double get_double(const Gcalc_internal_coord *c) const;
|
|
|
|
#endif /*GCALC_CHECK_WITH_FLOAT*/
|
2011-05-04 20:20:17 +02:00
|
|
|
private:
|
|
|
|
Gcalc_dyn_list::Item *m_first;
|
|
|
|
Gcalc_dyn_list::Item **m_hook;
|
|
|
|
int m_n_points;
|
2011-09-20 21:04:41 +02:00
|
|
|
Intersection_info *m_first_intersection;
|
|
|
|
Gcalc_dyn_list::Item **m_intersection_hook;
|
2011-10-05 11:45:39 +02:00
|
|
|
double coord_extent;
|
2011-05-04 20:20:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
the spatial object has to be represented as a set of
|
|
|
|
simple polygones and polylines to be sent to the slicescan.
|
|
|
|
|
|
|
|
Gcalc_shape_transporter class and his descendants are used to
|
|
|
|
simplify storing the information about the shape into necessary structures.
|
|
|
|
This base class only fills the Gcalc_heap with the information about
|
|
|
|
shapes and vertices.
|
|
|
|
|
|
|
|
Normally the Gcalc_shape_transporter family object is sent as a parameter
|
|
|
|
to the 'get_shapes' method of an 'spatial' object so it can pass
|
|
|
|
the spatial information about itself. The virtual methods are
|
|
|
|
treating this data in a way the caller needs.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Gcalc_shape_transporter
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
Gcalc_heap::Info *m_first;
|
|
|
|
Gcalc_heap::Info *m_prev;
|
|
|
|
int m_shape_started;
|
|
|
|
void int_complete();
|
|
|
|
protected:
|
|
|
|
Gcalc_heap *m_heap;
|
|
|
|
int int_single_point(gcalc_shape_info Info, double x, double y);
|
|
|
|
int int_add_point(gcalc_shape_info Info, double x, double y);
|
|
|
|
void int_start_line()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(!m_shape_started);
|
|
|
|
m_shape_started= 1;
|
|
|
|
m_first= m_prev= NULL;
|
|
|
|
}
|
|
|
|
void int_complete_line()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(m_shape_started== 1);
|
|
|
|
int_complete();
|
|
|
|
m_shape_started= 0;
|
|
|
|
}
|
|
|
|
void int_start_ring()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(m_shape_started== 2);
|
|
|
|
m_shape_started= 3;
|
|
|
|
m_first= m_prev= NULL;
|
|
|
|
}
|
|
|
|
void int_complete_ring()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(m_shape_started== 3);
|
|
|
|
int_complete();
|
|
|
|
m_shape_started= 2;
|
|
|
|
}
|
|
|
|
void int_start_poly()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(!m_shape_started);
|
|
|
|
m_shape_started= 2;
|
|
|
|
}
|
|
|
|
void int_complete_poly()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(m_shape_started== 2);
|
|
|
|
m_shape_started= 0;
|
|
|
|
}
|
|
|
|
bool line_started() { return m_shape_started == 1; };
|
|
|
|
public:
|
|
|
|
Gcalc_shape_transporter(Gcalc_heap *heap) :
|
|
|
|
m_shape_started(0), m_heap(heap) {}
|
|
|
|
|
|
|
|
virtual int single_point(double x, double y)=0;
|
|
|
|
virtual int start_line()=0;
|
|
|
|
virtual int complete_line()=0;
|
|
|
|
virtual int start_poly()=0;
|
|
|
|
virtual int complete_poly()=0;
|
|
|
|
virtual int start_ring()=0;
|
|
|
|
virtual int complete_ring()=0;
|
|
|
|
virtual int add_point(double x, double y)=0;
|
|
|
|
virtual int start_collection(int n_objects) { return 0; }
|
2011-09-22 15:53:36 +02:00
|
|
|
virtual int empty_shape() { return 0; }
|
2011-05-04 20:20:17 +02:00
|
|
|
int start_simple_poly()
|
|
|
|
{
|
|
|
|
return start_poly() || start_ring();
|
|
|
|
}
|
|
|
|
int complete_simple_poly()
|
|
|
|
{
|
|
|
|
return complete_ring() || complete_poly();
|
|
|
|
}
|
|
|
|
virtual ~Gcalc_shape_transporter() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
enum Gcalc_scan_events
|
|
|
|
{
|
2011-09-01 08:44:56 +02:00
|
|
|
scev_none= 0,
|
2011-05-04 20:20:17 +02:00
|
|
|
scev_point= 1, /* Just a new point in thread */
|
|
|
|
scev_thread= 2, /* Start of the new thread */
|
|
|
|
scev_two_threads= 4, /* A couple of new threads started */
|
|
|
|
scev_intersection= 8, /* Intersection happened */
|
|
|
|
scev_end= 16, /* Single thread finished */
|
|
|
|
scev_two_ends= 32, /* A couple of threads finished */
|
|
|
|
scev_single_point= 64 /* Got single point */
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef int sc_thread_id;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Gcalc_scan_iterator incapsulates the slisescan algorithm.
|
|
|
|
It takes filled Gcalc_heap as an datasource. Then can be
|
|
|
|
iterated trought the vertexes and intersection points with
|
|
|
|
the step() method. After the 'step()' one usually observes
|
|
|
|
the current 'slice' to do the necessary calculations, like
|
|
|
|
looking for intersections, calculating the area, whatever.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Gcalc_scan_iterator : public Gcalc_dyn_list
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
class point : public Gcalc_dyn_list::Item
|
|
|
|
{
|
|
|
|
public:
|
2011-09-20 21:04:41 +02:00
|
|
|
Gcalc_coord1 dx;
|
|
|
|
Gcalc_coord1 dy;
|
2011-05-04 20:20:17 +02:00
|
|
|
Gcalc_heap::Info *pi;
|
|
|
|
Gcalc_heap::Info *next_pi;
|
|
|
|
sc_thread_id thread;
|
2011-10-04 12:01:21 +02:00
|
|
|
const Gcalc_coord1 *l_border;
|
|
|
|
const Gcalc_coord1 *r_border;
|
|
|
|
int always_on_left;
|
2011-09-01 08:44:56 +02:00
|
|
|
|
|
|
|
const point *intersection_link;
|
|
|
|
Gcalc_scan_events event;
|
2011-05-04 20:20:17 +02:00
|
|
|
|
|
|
|
inline const point *c_get_next() const
|
|
|
|
{ return (const point *)next; }
|
2011-09-20 21:04:41 +02:00
|
|
|
inline bool is_bottom() const { return !next_pi; }
|
2011-05-04 20:20:17 +02:00
|
|
|
gcalc_shape_info get_shape() const { return pi->shape; }
|
|
|
|
inline point *get_next() { return (point *)next; }
|
|
|
|
inline const point *get_next() const { return (const point *)next; }
|
|
|
|
/* copies all but 'next' 'x' and 'precursor' */
|
2011-09-20 21:04:41 +02:00
|
|
|
void copy_core(const point *from);
|
|
|
|
void copy_all(const point *from);
|
2011-09-01 08:44:56 +02:00
|
|
|
/* Compare the dx_dy parameters regarding the horiz_dir */
|
|
|
|
/* returns -1 if less, 0 if equal, 1 if bigger */
|
2011-09-20 21:04:41 +02:00
|
|
|
static int cmp_dx_dy(const Gcalc_coord1 *dx_a,
|
|
|
|
const Gcalc_coord1 *dy_a,
|
|
|
|
const Gcalc_coord1 *dx_b,
|
|
|
|
const Gcalc_coord1 *dy_b);
|
|
|
|
static int cmp_dx_dy(const Gcalc_heap::Info *p1,
|
|
|
|
const Gcalc_heap::Info *p2,
|
|
|
|
const Gcalc_heap::Info *p3,
|
|
|
|
const Gcalc_heap::Info *p4);
|
2011-09-01 08:44:56 +02:00
|
|
|
int cmp_dx_dy(const point *p) const;
|
|
|
|
int simple_event() const
|
2011-05-04 20:20:17 +02:00
|
|
|
{
|
2011-09-01 08:44:56 +02:00
|
|
|
return !next ? (event & (scev_point | scev_end)) :
|
|
|
|
(!next->next && event == scev_two_ends);
|
2011-05-04 20:20:17 +02:00
|
|
|
}
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
void dbug_print();
|
|
|
|
#endif /*DBUG_OFF*/
|
2011-09-20 21:04:41 +02:00
|
|
|
#ifdef GCALC_CHECK_WITH_FLOAT
|
|
|
|
void calc_x(long double *x, long double y, long double ix) const;
|
|
|
|
#endif /*GCALC_CHECK_WITH_FLOAT*/
|
2011-05-04 20:20:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class intersection : public Gcalc_dyn_list::Item
|
|
|
|
{
|
|
|
|
public:
|
2011-09-13 10:59:11 +02:00
|
|
|
int n_row;
|
2011-05-04 20:20:17 +02:00
|
|
|
sc_thread_id thread_a;
|
|
|
|
sc_thread_id thread_b;
|
2011-09-20 21:04:41 +02:00
|
|
|
const Gcalc_heap::Intersection_info *ii;
|
2011-05-04 20:20:17 +02:00
|
|
|
inline intersection *get_next() { return (intersection *)next; }
|
|
|
|
};
|
|
|
|
|
2011-09-01 08:44:56 +02:00
|
|
|
class slice_state
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
point *slice;
|
|
|
|
point *event_position;
|
|
|
|
Gcalc_dyn_list::Item **event_position_hook;
|
|
|
|
Gcalc_dyn_list::Item **event_end_hook;
|
2011-09-20 21:04:41 +02:00
|
|
|
int intersection_scan;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
const Gcalc_heap::Info *pi;
|
|
|
|
const Gcalc_heap::Intersection_info *isc;
|
|
|
|
};
|
2011-09-01 08:44:56 +02:00
|
|
|
slice_state() : slice(NULL) {}
|
|
|
|
void clear_event_position()
|
|
|
|
{
|
|
|
|
event_position= NULL;
|
|
|
|
event_end_hook= (Gcalc_dyn_list::Item **) &event_position;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-05-04 20:20:17 +02:00
|
|
|
public:
|
|
|
|
Gcalc_scan_iterator(size_t blk_size= 8192);
|
|
|
|
|
|
|
|
void init(Gcalc_heap *points); /* Iterator can be reused */
|
|
|
|
void reset();
|
|
|
|
int step()
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(more_points());
|
2011-09-01 08:44:56 +02:00
|
|
|
return m_intersections ? intersection_scan() : normal_scan();
|
2011-05-04 20:20:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline Gcalc_heap::Info *more_points() { return m_cur_pi; }
|
|
|
|
inline bool more_trapezoids()
|
|
|
|
{ return m_cur_pi && m_cur_pi->next; }
|
|
|
|
|
2011-09-01 08:44:56 +02:00
|
|
|
inline const point *get_events() const
|
|
|
|
{ return m_events; }
|
2011-05-04 20:20:17 +02:00
|
|
|
inline const point *get_event_position() const
|
2011-09-01 08:44:56 +02:00
|
|
|
{ return current_state->event_position; }
|
|
|
|
inline const point *get_event_end() const
|
|
|
|
{ return (point *) *current_state->event_end_hook; }
|
|
|
|
inline const point *get_b_slice() const { return current_state->slice; }
|
|
|
|
inline const point *get_t_slice() const { return next_state->slice; }
|
2011-09-20 21:04:41 +02:00
|
|
|
double get_h() const;
|
|
|
|
double get_y() const;
|
|
|
|
double get_event_x() const;
|
|
|
|
double get_sp_x(const point *sp) const;
|
|
|
|
int intersection_step() const { return current_state->intersection_scan; }
|
|
|
|
const Gcalc_heap::Info *get_cur_pi() const
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(!intersection_step());
|
|
|
|
return current_state->pi;
|
|
|
|
}
|
|
|
|
const Gcalc_heap::Intersection_info *get_cur_ii() const
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(intersection_step());
|
|
|
|
return current_state->isc;
|
|
|
|
}
|
2011-05-04 20:20:17 +02:00
|
|
|
|
|
|
|
private:
|
2011-09-20 21:04:41 +02:00
|
|
|
Gcalc_heap *m_heap;
|
2011-05-04 20:20:17 +02:00
|
|
|
Gcalc_heap::Info *m_cur_pi;
|
2011-09-01 08:44:56 +02:00
|
|
|
slice_state state0, state1, state_s;
|
|
|
|
slice_state *current_state;
|
|
|
|
slice_state *next_state;
|
|
|
|
slice_state *saved_state;
|
|
|
|
|
2011-05-04 20:20:17 +02:00
|
|
|
intersection *m_intersections;
|
|
|
|
int m_n_intersections;
|
|
|
|
intersection *m_cur_intersection;
|
|
|
|
bool m_next_is_top_point;
|
|
|
|
sc_thread_id m_cur_thread;
|
|
|
|
|
2011-09-01 08:44:56 +02:00
|
|
|
point *m_events;
|
2011-05-04 20:20:17 +02:00
|
|
|
int normal_scan();
|
|
|
|
int intersection_scan();
|
|
|
|
void sort_intersections();
|
|
|
|
int handle_intersections();
|
|
|
|
int insert_top_point();
|
2011-09-13 10:59:11 +02:00
|
|
|
int add_intersection(int n_row, const point *a, const point *b,
|
2011-09-01 08:44:56 +02:00
|
|
|
Gcalc_dyn_list::Item ***p_hook);
|
2011-05-04 20:20:17 +02:00
|
|
|
int find_intersections();
|
|
|
|
|
|
|
|
intersection *new_intersection()
|
|
|
|
{
|
|
|
|
return (intersection *)new_item();
|
|
|
|
}
|
|
|
|
point *new_slice_point()
|
|
|
|
{
|
2011-09-20 21:04:41 +02:00
|
|
|
point *new_point= (point *)new_item();
|
|
|
|
new_point->dx.init();
|
|
|
|
new_point->dy.init();
|
|
|
|
return new_point;
|
2011-05-04 20:20:17 +02:00
|
|
|
}
|
|
|
|
point *new_slice(point *example);
|
2011-09-01 08:44:56 +02:00
|
|
|
int arrange_event();
|
|
|
|
void mark_event_position1(point *ep, Gcalc_dyn_list::Item **ep_hook);
|
2011-05-04 20:20:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Gcalc_trapezoid_iterator simplifies the calculations on
|
|
|
|
the current slice of the Gcalc_scan_iterator.
|
|
|
|
One can walk through the trapezoids formed between
|
|
|
|
previous and current slices.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Gcalc_trapezoid_iterator
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
const Gcalc_scan_iterator::point *sp0;
|
|
|
|
const Gcalc_scan_iterator::point *sp1;
|
|
|
|
public:
|
|
|
|
Gcalc_trapezoid_iterator(const Gcalc_scan_iterator *scan_i) :
|
|
|
|
sp0(scan_i->get_b_slice()),
|
|
|
|
sp1(scan_i->get_t_slice())
|
|
|
|
{}
|
|
|
|
|
|
|
|
inline bool more() const { return sp1 && sp1->next; }
|
|
|
|
|
|
|
|
const Gcalc_scan_iterator::point *lt() const { return sp1; }
|
|
|
|
const Gcalc_scan_iterator::point *lb() const { return sp0; }
|
|
|
|
const Gcalc_scan_iterator::point *rb() const
|
|
|
|
{
|
|
|
|
const Gcalc_scan_iterator::point *result= sp0;
|
|
|
|
while ((result= result->c_get_next())->is_bottom())
|
|
|
|
{}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
const Gcalc_scan_iterator::point *rt() const
|
|
|
|
{ return sp1->c_get_next(); }
|
|
|
|
|
|
|
|
void operator++()
|
|
|
|
{
|
|
|
|
sp0= rb();
|
|
|
|
sp1= rt();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Gcalc_point_iterator simplifies the calculations on
|
|
|
|
the current slice of the Gcalc_scan_iterator.
|
|
|
|
One can walk through the points on the current slice.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Gcalc_point_iterator
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
const Gcalc_scan_iterator::point *sp;
|
|
|
|
public:
|
|
|
|
Gcalc_point_iterator(const Gcalc_scan_iterator *scan_i):
|
|
|
|
sp(scan_i->get_b_slice())
|
|
|
|
{}
|
|
|
|
|
|
|
|
inline bool more() const { return sp != NULL; }
|
|
|
|
inline void operator++() { sp= sp->c_get_next(); }
|
|
|
|
inline const Gcalc_scan_iterator::point *point() const { return sp; }
|
|
|
|
inline const Gcalc_heap::Info *get_pi() const { return sp->pi; }
|
|
|
|
inline gcalc_shape_info get_shape() const { return sp->get_shape(); }
|
2011-09-01 08:44:56 +02:00
|
|
|
inline void restart(const Gcalc_scan_iterator *scan_i)
|
|
|
|
{ sp= scan_i->get_b_slice(); }
|
2011-05-04 20:20:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /*GCALC_SLICESCAN_INCLUDED*/
|
|
|
|
|