2 #include "xy_widen_regoin.h"
3 #include "Rasterizer.h"
5 #include "xy_circular_array_queue.h"
9 // @left arc : left part of an ellipse
10 // @right arc: right part of an ellipse
11 // @link arc : curve composed by all left most points of a series of left arc , or all right most points of a series of right arc
12 // @cross_line of arc a and b (a.y < b.y):
13 // if both a and b are left arc, @cross_line is the max line that satisfied:
14 // a(line)< b(line) on line<@cross_line,
16 // a(line)>=b(line) on line>=@cross_line
17 // if both a and b are right arc, @cross_line is the max line that satisfied:
18 // a(line)> b(line) on line<@cross_line,
20 // a(line)<=b(line) on line>=@cross_line
22 static const int MIN_CROSS_LINE
= (-2147483647 - 1);
23 static const int MAX_CROSS_LINE
= 0x7fffffff;
24 static const int MAX_X
= 0x7fffffff;
26 typedef unsigned __int64 XY_POINT
;
27 #define XY_POINT_X(point) ((point)&0xffffffff)
28 #define XY_POINT_Y(point) ((point)>>32)
29 #define XY_POINT_SET(point,x,y) ((point)=(((long long)(y)<<32)|(x)))
33 LinkArcItem():dead_line(0),arc_center(0){}
39 typedef XYCircularArrayQueue
<LinkArcItem
> LinkArc
;
47 typedef CAtlList
<LinkSpan
> LinkSpanList
;
50 typedef tSpanBuffer SpanBuffer
;
51 #define SPAN_LEFT(span) ((span).first)
52 #define SPAN_RIGHT(span) ((span).second)
53 #define SPAN_PTR_LEFT(span) ((span)->first)
54 #define SPAN_PTR_RIGHT(span) ((span)->second)
63 * ry must >0 and rx must >=0
65 int init(int rx
, int ry
);
67 inline int get_left_arc_x(int y
) const;
68 inline int get_left_arc_x(XY_POINT center
, int y
) const;
70 inline int get_right_arc_x(int y
) const;
71 inline int get_right_arc_x(XY_POINT center
, int y
) const;
73 int cross_left(XY_POINT c1
, XY_POINT base
) const;
74 int cross_right(XY_POINT c1
, XY_POINT base
) const;
76 int init_cross_point();
83 int *m_cross_matrix_base
;
85 XyEllipse(const XyEllipse
&);
86 void operator=(const XyEllipse
&);
89 class WidenRegionCreaterImpl
92 WidenRegionCreaterImpl();
93 ~WidenRegionCreaterImpl();
95 void xy_overlap_region(SpanBuffer
* dst
, const SpanBuffer
& src
, int rx
, int ry
);
97 int cross_left(const LinkArc
& arc
, XY_POINT center
);//return <0 if arc(o)<inner_pl, MAX if arc(0)>inner_pl, else return cross_line
99 void add_left(LinkArc
* arc
, XY_POINT center
);
100 void add_right(LinkArc
* arc
, XY_POINT center
);
101 void add_span(LinkSpan
* spans
, const Span
& span
);
102 void add_line(SpanBuffer
* dst
, LinkSpanList
& spans
, int cur_line
, int dead_line
);//add all line<dead_line to dst
105 XyEllipse
*m_ellipse
;
109 // WidenRegionCreater
112 WidenRegionCreater
* WidenRegionCreater::GetDefaultWidenRegionCreater()
114 static WidenRegionCreater result
;
115 static WidenRegionCreaterImpl impl
;
116 result
.m_impl
= &impl
;
120 WidenRegionCreater::WidenRegionCreater():m_impl(NULL
)
125 WidenRegionCreater::~WidenRegionCreater()
130 void WidenRegionCreater::xy_overlap_region( SpanBuffer
* dst
, const SpanBuffer
& src
, int rx
, int ry
)
132 m_impl
->xy_overlap_region(dst
, src
, rx
, ry
);
136 // WidenRegionCreaterImpl
139 WidenRegionCreaterImpl::WidenRegionCreaterImpl(): m_ellipse(NULL
)
143 WidenRegionCreaterImpl::~WidenRegionCreaterImpl()
148 void WidenRegionCreaterImpl::xy_overlap_region(SpanBuffer
* dst
, const SpanBuffer
& src
, int rx
, int ry
)
150 if (m_ellipse
!=NULL
&& (m_ellipse
->m_rx
!=rx
|| m_ellipse
->m_ry
!=ry
))
157 m_ellipse
= new XyEllipse();
163 int rv
= m_ellipse
->init(rx
, ry
);
171 LinkSpanList link_span_list
;
175 SpanBuffer::const_iterator it_src
= src
.begin();
176 SpanBuffer::const_iterator it_src_end
= src
.end();
178 LinkSpan
&sentinel
= link_span_list
.GetAt(link_span_list
.AddTail());
179 sentinel
.left
.init(2*ry
+2);
180 sentinel
.right
.init(2*ry
+2);
181 LinkArcItem
& item
= sentinel
.left
.inc_1_at_tail();
182 XY_POINT_SET(item
.arc_center
, MAX_X
, 0);
183 item
.dead_line
= MAX_CROSS_LINE
;
185 for ( ;it_src
!=it_src_end
; it_src
++)
187 const XY_POINT
&left
= SPAN_PTR_LEFT(it_src
);
188 const XY_POINT
&right
= SPAN_PTR_RIGHT(it_src
);
189 int line
= XY_POINT_Y(left
); //fix me
190 if (line
-ry
>dst_line
)
192 add_line(dst
, link_span_list
, dst_line
, line
- ry
);
193 dst_line
= line
- ry
;
194 ASSERT(!link_span_list
.IsEmpty() && !link_span_list
.GetTail().left
.empty());
195 ASSERT(XY_POINT_X(link_span_list
.GetTail().left
.get_at(0).arc_center
)==MAX_X
);
196 XY_POINT_SET(link_span_list
.GetTail().left
.get_at(0).arc_center
, MAX_X
, line
-1);//update sentinel
197 pos
= link_span_list
.GetHeadPosition();
201 LinkSpan
&spans
= link_span_list
.GetAt(pos
);
202 LinkArc
&arc
= spans
.left
;
203 int y
= cross_left(arc
, left
);
206 link_span_list
.GetNext(pos
);
209 else if ( y
>=-ry
)//fix me
211 add_span(&spans
, *it_src
);
212 link_span_list
.GetNext(pos
);
217 LinkSpan
&new_span
= link_span_list
.GetAt(link_span_list
.InsertBefore(pos
, LinkSpan()));
218 new_span
.left
.init(2*ry
+2);
219 LinkArcItem
& item
= new_span
.left
.inc_1_at_tail();
221 item
.arc_center
= SPAN_PTR_LEFT(it_src
);
222 item
.dead_line
= line
+ry
+1;
224 new_span
.right
.init(2*ry
+2);
225 LinkArcItem
& item2
= new_span
.right
.inc_1_at_tail();
226 item2
.arc_center
= SPAN_PTR_RIGHT(it_src
);
227 item2
.dead_line
= line
+ry
+1;
232 add_line(dst
, link_span_list
, dst_line
, MAX_CROSS_LINE
);
235 int WidenRegionCreaterImpl::cross_left(const LinkArc
& arc
, XY_POINT center
)
237 ASSERT(!arc
.empty());
238 int y
= m_ellipse
->cross_left(arc
.back().arc_center
, center
);
239 if (y
>=MAX_CROSS_LINE
)
241 return MAX_CROSS_LINE
;
245 y
= m_ellipse
->cross_left(arc
.get_at(0).arc_center
, center
);
246 if (y
<=MIN_CROSS_LINE
)
248 return MIN_CROSS_LINE
;
254 void WidenRegionCreaterImpl::add_span(LinkSpan
* spans
, const Span
& span
)
257 add_left(&spans
->left
, SPAN_LEFT(span
));
258 add_right(&spans
->right
, SPAN_RIGHT(span
));
261 void WidenRegionCreaterImpl::add_left( LinkArc
* arc
, XY_POINT center
)
263 int rx
= m_ellipse
->m_rx
;
264 int ry
= m_ellipse
->m_ry
;
266 ASSERT(!arc
->empty()&& m_ellipse
->cross_left(arc
->get_at(0).arc_center
, center
)>=-ry
);
269 int line
= XY_POINT_Y(center
);
270 for (i
=arc
->size()-1;i
>=1;i
--)
272 y
= m_ellipse
->cross_left( arc
->get_at(i
).arc_center
, center
);
273 if( y
>ry
)//not cross
277 else if ( y
+line
>arc
->get_at(i
-1).dead_line
)
279 arc
->get_at(i
).dead_line
= y
+line
;
289 y
= m_ellipse
->cross_left( arc
->get_at(0).arc_center
, center
);
290 ASSERT(y
>=-ry
&& y
+line
<=arc
->get_at(0).dead_line
);
291 arc
->get_at(0).dead_line
= y
+ line
;
293 LinkArcItem
& item
= arc
->inc_1_at_tail();
294 item
.arc_center
= center
;
295 item
.dead_line
= line
+ ry
+ 1;
298 void WidenRegionCreaterImpl::add_right( LinkArc
* arc
, XY_POINT center
)
300 int rx
= m_ellipse
->m_rx
;
301 int ry
= m_ellipse
->m_ry
;
303 ASSERT(!arc
->empty());
306 int line
= XY_POINT_Y(center
);
307 for (i
=arc
->size()-1;i
>=1;i
--)
309 y
= m_ellipse
->cross_right( arc
->get_at(i
).arc_center
, center
);
310 if( y
>ry
)//not cross
314 else if ( y
+line
>arc
->get_at(i
-1).dead_line
)
316 arc
->get_at(i
).dead_line
= y
+line
;
326 y
= m_ellipse
->cross_right( arc
->get_at(0).arc_center
, center
);
331 else if (y
<MAX_CROSS_LINE
)
333 ASSERT(y
+line
<=arc
->get_at(0).dead_line
);
334 arc
->get_at(0).dead_line
= y
+ line
;
337 LinkArcItem
& item
= arc
->inc_1_at_tail();
338 item
.arc_center
= center
;
339 item
.dead_line
= line
+ ry
+ 1;
342 void WidenRegionCreaterImpl::add_line( SpanBuffer
* dst
, LinkSpanList
& spans
, int cur_dst_line
, int dead_line
)
348 for( ;cur_dst_line
<dead_line
;cur_dst_line
++)
350 POSITION pos_cur
= spans
.GetHeadPosition();
351 POSITION pos_next
= pos_cur
;
352 ASSERT(pos_next
!=NULL
);
353 LinkSpan
*span
= &spans
.GetNext(pos_next
);
359 while(pos_next
!=NULL
)
361 ASSERT(!span
->left
.empty());
362 const LinkArcItem
&left_top
= span
->left
.get_at(0);
364 ASSERT(!span
->right
.empty());
365 const LinkArcItem
&right_top
= span
->right
.get_at(0);
367 ASSERT(cur_dst_line
< left_top
.dead_line
);
368 ASSERT(cur_dst_line
< right_top
.dead_line
);
370 XY_POINT left
, right
;
371 int x
= m_ellipse
->get_left_arc_x(left_top
.arc_center
, cur_dst_line
);
372 XY_POINT_SET(left
, x
, cur_dst_line
);
373 x
= m_ellipse
->get_right_arc_x(right_top
.arc_center
, cur_dst_line
);
374 XY_POINT_SET(right
, x
, cur_dst_line
);
375 ASSERT(SPAN_LEFT(dst_span
)<=left
);
376 if ( SPAN_RIGHT(dst_span
) >= left
)
378 if ( SPAN_RIGHT(dst_span
)<right
)
379 SPAN_RIGHT(dst_span
) = right
;
381 else if ( SPAN_RIGHT(dst_span
)>SPAN_LEFT(dst_span
) )
383 dst
->push_back(dst_span
);
384 SPAN_LEFT(dst_span
) = left
;
385 SPAN_RIGHT(dst_span
) = right
;
389 SPAN_LEFT(dst_span
) = left
;
390 SPAN_RIGHT(dst_span
) = right
;
393 if (cur_dst_line
+1==left_top
.dead_line
)
395 span
->left
.pop_front();
397 if (cur_dst_line
+1==right_top
.dead_line
)
399 span
->right
.pop_front();
401 if (span
->left
.empty())
403 ASSERT(span
->right
.empty());
404 spans
.RemoveAt(pos_cur
);
406 span
= &spans
.GetNext(pos_next
);
411 span
= &spans
.GetNext(pos_next
);
415 if ( SPAN_RIGHT(dst_span
)>SPAN_LEFT(dst_span
) )
417 dst
->push_back(dst_span
);
422 // ref: A Fast Bresenham Type Algorithm For Drawing Ellipses by John Kennedy
423 // http://homepage.smc.edu/kennedy_john/belipse.pdf
425 int gen_left_arc(int left_arc
[], int rx
, int ry
)
430 int *left_arc2
= left_arc
+ ry
;
433 for (int y
=-ry
;y
<=ry
;y
++)
453 __int64 dx
= b
*b
*(1-2*a
);
456 __int64 stopx
= b2
* a
;
458 while (stopx
>= stopy
)
467 if ( 2*err
+ dx
> 0 )
484 while (stopx
<= stopy
)
507 left_arc2
[y
] = left_arc2
[y
+1];
508 left_arc2
[-y
] = left_arc2
[y
+1];
513 left_arc2
[last_y_stop
] = left_arc
[last_y_stop
-1];
514 left_arc2
[-last_y_stop
] = left_arc
[last_y_stop
-1];
517 //ASSERT(y<last_y_stop);
525 XyEllipse::XyEllipse()
527 , m_left_arc_base(NULL
)
528 , m_cross_matrix(NULL
)
529 , m_cross_matrix_base(NULL
)
535 XyEllipse::~XyEllipse()
537 delete[]m_left_arc_base
;
538 delete[]m_cross_matrix_base
;
542 * ry must >0 and rx must >=0
544 int XyEllipse::init( int rx
, int ry
)
550 m_left_arc_base
= new int[2*ry
+2];
551 if (!m_left_arc_base
)
555 gen_left_arc(m_left_arc_base
, rx
, ry
);
556 m_left_arc
= m_left_arc_base
+ ry
;
563 int XyEllipse::get_left_arc_x( int y
) const
565 return m_left_arc
[y
];
568 int XyEllipse::get_left_arc_x( XY_POINT center
, int y
) const
570 return XY_POINT_X(center
) + m_left_arc
[y
-XY_POINT_Y(center
)];
573 int XyEllipse::get_right_arc_x( int y
) const
575 return -m_left_arc
[y
];
578 int XyEllipse::get_right_arc_x( XY_POINT center
, int y
) const
580 return XY_POINT_X(center
) - m_left_arc
[y
-XY_POINT_Y(center
)];
583 int XyEllipse::init_cross_point()
585 if (m_rx
<0 || m_ry
<=0 )
589 m_cross_matrix_base
= new int[ (2*m_ry
+1)*(2*m_rx
+1) ];
590 if (!m_cross_matrix_base
)
595 m_cross_matrix
= m_cross_matrix_base
+ (2*m_ry
)*(2*m_rx
+1) + m_rx
;
601 float rx_devide_ry
= f_rx
/f_ry
;
602 float ry_2
= m_ry
* m_ry
;
604 std::vector
<int> cross_x_base(2*m_ry
+1+1);
605 int *cross_x
= &cross_x_base
[0] + m_ry
+ 1;
606 cross_x
[-m_ry
-1] = m_rx
;
607 for (int dy
=-2*m_ry
;dy
<=-1;dy
++)
610 for ( ;y
-dy
<=m_ry
;y
++)
612 float f_cross_x
= rx_devide_ry
* ( sqrt(ry_2
- (y
- dy
)*(y
- dy
)) - sqrt(ry_2
- y
*y
) );
613 cross_x
[y
] = ceil(f_cross_x
);
614 ASSERT(cross_x
[y
]<=cross_x
[y
-1] && abs(cross_x
[y
])<=m_rx
);
617 int *cross_matrix
= m_cross_matrix
+ dy
*(2*m_rx
+1);
620 //[ -m_rx, cross_x[y] )
621 for (int j
=-m_rx
;j
<cross_x
[y
];j
++)
623 cross_matrix
[j
] = MAX_CROSS_LINE
;
627 //[ cross_x[y], cross_x[y-1] )
628 for (int j
=cross_x
[y
];j
<cross_x
[y
-1];j
++)
633 cross_matrix
[cross_x
[y
]] = y
;
634 //[ cross_x[y], m_rx ]
635 for (int j
=cross_x
[y
];j
<=m_rx
;j
++)
637 cross_matrix
[j
] = MIN_CROSS_LINE
;
643 int XyEllipse::cross_left( XY_POINT c1
, XY_POINT base
) const
645 int dx
= XY_POINT_X(c1
) - XY_POINT_X(base
);
646 int dy
= XY_POINT_Y(c1
) - XY_POINT_Y(base
);
647 ASSERT(dy
<0 && dy
>=-2*m_ry
);
650 return MAX_CROSS_LINE
;
654 return MIN_CROSS_LINE
;
656 else // [-m_rx, m_rx]
658 ASSERT( abs( *(m_cross_matrix
+ dy
*(2*m_rx
+1) + dx
) )<=m_ry
||
659 *(m_cross_matrix
+ dy
*(2*m_rx
+1) + dx
) == MIN_CROSS_LINE
||
660 *(m_cross_matrix
+ dy
*(2*m_rx
+1) + dx
) == MAX_CROSS_LINE
);
661 return *(m_cross_matrix
+ dy
*(2*m_rx
+1) + dx
);
665 int XyEllipse::cross_right( XY_POINT c1
, XY_POINT base
) const
667 int dx
= XY_POINT_X(base
) - XY_POINT_X(c1
);
668 int dy
= XY_POINT_Y(c1
) - XY_POINT_Y(base
);
669 ASSERT(dy
<0 && dy
>=-2*m_ry
);
672 return MAX_CROSS_LINE
;
676 return MIN_CROSS_LINE
;
678 else // [-m_rx, m_rx]
680 ASSERT( abs( *(m_cross_matrix
+ dy
*(2*m_rx
+1) + dx
) )<=m_ry
||
681 *(m_cross_matrix
+ dy
*(2*m_rx
+1) + dx
) == MIN_CROSS_LINE
||
682 *(m_cross_matrix
+ dy
*(2*m_rx
+1) + dx
) == MAX_CROSS_LINE
);
683 return *(m_cross_matrix
+ dy
*(2*m_rx
+1) + dx
);