1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dcbase.cpp
3 // Purpose: generic methods of the wxDC Class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
30 // bool wxDCBase::sm_cacheing = false;
32 // ============================================================================
34 // ============================================================================
36 #if WXWIN_COMPATIBILITY_2_6
37 void wxDCBase::BeginDrawing()
41 void wxDCBase::EndDrawing()
44 #endif // WXWIN_COMPATIBILITY_2_6
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 void wxDCBase::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
51 wxCoord width
, wxCoord height
)
53 wxCHECK_RET( Ok(), wxT("invalid window dc") );
55 wxCoord x2
= x1
+ width
,
58 // this is to yield width of 3 for width == height == 10
59 SetPen(wxPen(GetTextForeground(), (width
+ height
+ 1) / 7, wxSOLID
));
61 // we're drawing a scaled version of wx/generic/tick.xpm here
62 wxCoord x3
= x1
+ (4*width
) / 10, // x of the tick bottom
63 y3
= y1
+ height
/ 2; // y of the left tick branch
64 DoDrawLine(x1
, y3
, x3
, y2
);
65 DoDrawLine(x3
, y2
, x2
, y1
);
67 CalcBoundingBox(x1
, y1
);
68 CalcBoundingBox(x2
, y2
);
71 // ----------------------------------------------------------------------------
73 // ----------------------------------------------------------------------------
75 void wxDCBase::DrawLines(const wxList
*list
, wxCoord xoffset
, wxCoord yoffset
)
77 int n
= list
->GetCount();
78 wxPoint
*points
= new wxPoint
[n
];
81 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
83 wxPoint
*point
= (wxPoint
*)node
->GetData();
84 points
[i
].x
= point
->x
;
85 points
[i
].y
= point
->y
;
88 DoDrawLines(n
, points
, xoffset
, yoffset
);
94 void wxDCBase::DrawPolygon(const wxList
*list
,
95 wxCoord xoffset
, wxCoord yoffset
,
98 int n
= list
->GetCount();
99 wxPoint
*points
= new wxPoint
[n
];
102 for ( wxList::compatibility_iterator node
= list
->GetFirst(); node
; node
= node
->GetNext(), i
++ )
104 wxPoint
*point
= (wxPoint
*)node
->GetData();
105 points
[i
].x
= point
->x
;
106 points
[i
].y
= point
->y
;
109 DoDrawPolygon(n
, points
, xoffset
, yoffset
, fillStyle
);
115 wxDCBase::DoDrawPolyPolygon(int n
,
118 wxCoord xoffset
, wxCoord yoffset
,
123 DoDrawPolygon(count
[0], points
, xoffset
, yoffset
, fillStyle
);
131 for (i
= j
= lastOfs
= 0; i
< n
; i
++)
136 pts
= new wxPoint
[j
+n
-1];
137 for (i
= 0; i
< j
; i
++)
139 for (i
= 2; i
<= n
; i
++)
141 lastOfs
-= count
[n
-i
];
142 pts
[j
++] = pts
[lastOfs
];
146 SetPen(wxPen(*wxBLACK
, 0, wxTRANSPARENT
));
147 DoDrawPolygon(j
, pts
, xoffset
, yoffset
, fillStyle
);
149 for (i
= j
= 0; i
< n
; i
++)
151 DoDrawLines(count
[i
], pts
+j
, xoffset
, yoffset
);
157 // ----------------------------------------------------------------------------
159 // ----------------------------------------------------------------------------
163 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
164 void wxDCBase::DrawSpline(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord x3
, wxCoord y3
)
168 wxPoint
*point1
= new wxPoint
;
169 point1
->x
= x1
; point1
->y
= y1
;
170 point_list
.Append((wxObject
*)point1
);
172 wxPoint
*point2
= new wxPoint
;
173 point2
->x
= x2
; point2
->y
= y2
;
174 point_list
.Append((wxObject
*)point2
);
176 wxPoint
*point3
= new wxPoint
;
177 point3
->x
= x3
; point3
->y
= y3
;
178 point_list
.Append((wxObject
*)point3
);
180 DrawSpline(&point_list
);
182 for( wxList::compatibility_iterator node
= point_list
.GetFirst(); node
; node
= node
->GetNext() )
184 wxPoint
*p
= (wxPoint
*)node
->GetData();
189 void wxDCBase::DrawSpline(int n
, wxPoint points
[])
192 for (int i
=0; i
< n
; i
++)
194 list
.Append((wxObject
*)&points
[i
]);
200 // ----------------------------------- spline code ----------------------------------------
202 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
203 double a3
, double b3
, double a4
, double b4
);
204 void wx_clear_stack();
205 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
206 double *y3
, double *x4
, double *y4
);
207 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
208 double x4
, double y4
);
209 static bool wx_spline_add_point(double x
, double y
);
210 static void wx_spline_draw_point_array(wxDCBase
*dc
);
212 wxList wx_spline_point_list
;
214 #define half(z1, z2) ((z1+z2)/2.0)
217 /* iterative version */
219 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
222 register double xmid
, ymid
;
223 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
226 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
228 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
229 xmid
= (double)half(x2
, x3
);
230 ymid
= (double)half(y2
, y3
);
231 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
232 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
233 wx_spline_add_point( x1
, y1
);
234 wx_spline_add_point( xmid
, ymid
);
236 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
237 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
238 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
239 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
244 /* utilities used by spline drawing routines */
246 typedef struct wx_spline_stack_struct
{
247 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
250 #define SPLINE_STACK_DEPTH 20
251 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
252 static Stack
*wx_stack_top
;
253 static int wx_stack_count
;
255 void wx_clear_stack()
257 wx_stack_top
= wx_spline_stack
;
261 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
263 wx_stack_top
->x1
= x1
;
264 wx_stack_top
->y1
= y1
;
265 wx_stack_top
->x2
= x2
;
266 wx_stack_top
->y2
= y2
;
267 wx_stack_top
->x3
= x3
;
268 wx_stack_top
->y3
= y3
;
269 wx_stack_top
->x4
= x4
;
270 wx_stack_top
->y4
= y4
;
275 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
276 double *x3
, double *y3
, double *x4
, double *y4
)
278 if (wx_stack_count
== 0)
282 *x1
= wx_stack_top
->x1
;
283 *y1
= wx_stack_top
->y1
;
284 *x2
= wx_stack_top
->x2
;
285 *y2
= wx_stack_top
->y2
;
286 *x3
= wx_stack_top
->x3
;
287 *y3
= wx_stack_top
->y3
;
288 *x4
= wx_stack_top
->x4
;
289 *y4
= wx_stack_top
->y4
;
293 static bool wx_spline_add_point(double x
, double y
)
295 wxPoint
*point
= new wxPoint
;
298 wx_spline_point_list
.Append((wxObject
*)point
);
302 static void wx_spline_draw_point_array(wxDCBase
*dc
)
304 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
305 wxList::compatibility_iterator node
= wx_spline_point_list
.GetFirst();
308 wxPoint
*point
= (wxPoint
*)node
->GetData();
310 wx_spline_point_list
.Erase(node
);
311 node
= wx_spline_point_list
.GetFirst();
315 void wxDCBase::DoDrawSpline( wxList
*points
)
317 wxCHECK_RET( Ok(), wxT("invalid window dc") );
320 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
321 double x1
, y1
, x2
, y2
;
323 wxList::compatibility_iterator node
= points
->GetFirst();
324 if (node
== wxList::compatibility_iterator())
328 p
= (wxPoint
*)node
->GetData();
333 node
= node
->GetNext();
334 p
= (wxPoint
*)node
->GetData();
338 cx1
= (double)((x1
+ x2
) / 2);
339 cy1
= (double)((y1
+ y2
) / 2);
340 cx2
= (double)((cx1
+ x2
) / 2);
341 cy2
= (double)((cy1
+ y2
) / 2);
343 wx_spline_add_point(x1
, y1
);
345 while ((node
= node
->GetNext())
351 p
= (wxPoint
*)node
->GetData();
356 cx4
= (double)(x1
+ x2
) / 2;
357 cy4
= (double)(y1
+ y2
) / 2;
358 cx3
= (double)(x1
+ cx4
) / 2;
359 cy3
= (double)(y1
+ cy4
) / 2;
361 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
365 cx2
= (double)(cx1
+ x2
) / 2;
366 cy2
= (double)(cy1
+ y2
) / 2;
369 wx_spline_add_point( cx1
, cy1
);
370 wx_spline_add_point( x2
, y2
);
372 wx_spline_draw_point_array( this );
375 #endif // wxUSE_SPLINES
377 // ----------------------------------------------------------------------------
378 // Partial Text Extents
379 // ----------------------------------------------------------------------------
382 // Each element of the widths array will be the width of the string up to and
383 // including the corresponding character in text. This is the generic
384 // implementation, the port-specific classes should do this with native APIs
385 // if available and if faster. Note: pango_layout_index_to_pos is much slower
386 // than calling GetTextExtent!!
393 FontWidthCache() : m_scaleX(1), m_widths(NULL
) { }
394 ~FontWidthCache() { delete []m_widths
; }
399 m_widths
= new int[FWC_SIZE
];
401 memset(m_widths
, 0, sizeof(int)*FWC_SIZE
);
409 static FontWidthCache s_fontWidthCache
;
411 bool wxDCBase::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
415 const size_t len
= text
.Length();
419 // reset the cache if font or horizontal scale have changed
420 if ( !s_fontWidthCache
.m_widths
||
421 !wxIsSameDouble(s_fontWidthCache
.m_scaleX
, m_scaleX
) ||
422 (s_fontWidthCache
.m_font
!= GetFont()) )
424 s_fontWidthCache
.Reset();
425 s_fontWidthCache
.m_font
= GetFont();
426 s_fontWidthCache
.m_scaleX
= m_scaleX
;
429 // Calculate the position of each character based on the widths of
430 // the previous characters
432 for ( size_t i
= 0; i
< len
; i
++ )
434 const wxChar c
= text
[i
];
435 unsigned int c_int
= (unsigned int)c
;
437 if ((c_int
< FWC_SIZE
) && (s_fontWidthCache
.m_widths
[c_int
] != 0))
439 w
= s_fontWidthCache
.m_widths
[c_int
];
443 GetTextExtent(c
, &w
, &h
);
444 if (c_int
< FWC_SIZE
)
445 s_fontWidthCache
.m_widths
[c_int
] = w
;
449 widths
[i
] = totalWidth
;
456 // ----------------------------------------------------------------------------
457 // enhanced text drawing
458 // ----------------------------------------------------------------------------
460 void wxDCBase::GetMultiLineTextExtent(const wxString
& text
,
466 wxCoord widthTextMax
= 0, widthLine
,
467 heightTextTotal
= 0, heightLineDefault
= 0, heightLine
= 0;
470 for ( const wxChar
*pc
= text
; ; pc
++ )
472 if ( *pc
== _T('\n') || *pc
== _T('\0') )
474 if ( curLine
.empty() )
476 // we can't use GetTextExtent - it will return 0 for both width
477 // and height and an empty line should count in height
480 // assume that this line has the same height as the previous
482 if ( !heightLineDefault
)
483 heightLineDefault
= heightLine
;
485 if ( !heightLineDefault
)
487 // but we don't know it yet - choose something reasonable
488 GetTextExtent(_T("W"), NULL
, &heightLineDefault
,
492 heightTextTotal
+= heightLineDefault
;
496 GetTextExtent(curLine
, &widthLine
, &heightLine
,
498 if ( widthLine
> widthTextMax
)
499 widthTextMax
= widthLine
;
500 heightTextTotal
+= heightLine
;
503 if ( *pc
== _T('\n') )
522 *y
= heightTextTotal
;
527 void wxDCBase::DrawLabel(const wxString
& text
,
528 const wxBitmap
& bitmap
,
532 wxRect
*rectBounding
)
534 // find the text position
535 wxCoord widthText
, heightText
, heightLine
;
536 GetMultiLineTextExtent(text
, &widthText
, &heightText
, &heightLine
);
538 wxCoord width
, height
;
541 width
= widthText
+ bitmap
.GetWidth();
542 height
= bitmap
.GetHeight();
551 if ( alignment
& wxALIGN_RIGHT
)
553 x
= rect
.GetRight() - width
;
555 else if ( alignment
& wxALIGN_CENTRE_HORIZONTAL
)
557 x
= (rect
.GetLeft() + rect
.GetRight() + 1 - width
) / 2;
559 else // alignment & wxALIGN_LEFT
564 if ( alignment
& wxALIGN_BOTTOM
)
566 y
= rect
.GetBottom() - height
;
568 else if ( alignment
& wxALIGN_CENTRE_VERTICAL
)
570 y
= (rect
.GetTop() + rect
.GetBottom() + 1 - height
) / 2;
572 else // alignment & wxALIGN_TOP
577 // draw the bitmap first
583 DrawBitmap(bitmap
, x
, y
, true /* use mask */);
585 wxCoord offset
= bitmap
.GetWidth() + 4;
589 y
+= (height
- heightText
) / 2;
592 // we will draw the underscore under the accel char later
593 wxCoord startUnderscore
= 0,
597 // split the string into lines and draw each of them separately
599 for ( const wxChar
*pc
= text
; ; pc
++ )
601 if ( *pc
== _T('\n') || *pc
== _T('\0') )
603 int xRealStart
= x
; // init it here to avoid compielr warnings
605 if ( !curLine
.empty() )
607 // NB: can't test for !(alignment & wxALIGN_LEFT) because
609 if ( alignment
& (wxALIGN_RIGHT
| wxALIGN_CENTRE_HORIZONTAL
) )
612 GetTextExtent(curLine
, &widthLine
, NULL
);
614 if ( alignment
& wxALIGN_RIGHT
)
616 xRealStart
+= width
- widthLine
;
618 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
620 xRealStart
+= (width
- widthLine
) / 2;
623 //else: left aligned, nothing to do
625 DrawText(curLine
, xRealStart
, y
);
630 // do we have underscore in this line? we can check yUnderscore
631 // because it is set below to just y + heightLine if we do
632 if ( y
== yUnderscore
)
634 // adjust the horz positions to account for the shift
635 startUnderscore
+= xRealStart
;
636 endUnderscore
+= xRealStart
;
639 if ( *pc
== _T('\0') )
644 else // not end of line
646 if ( pc
- text
.c_str() == indexAccel
)
648 // remeber to draw underscore here
649 GetTextExtent(curLine
, &startUnderscore
, NULL
);
651 GetTextExtent(curLine
, &endUnderscore
, NULL
);
653 yUnderscore
= y
+ heightLine
;
662 // draw the underscore if found
663 if ( startUnderscore
!= endUnderscore
)
665 // it should be of the same colour as text
666 SetPen(wxPen(GetTextForeground(), 0, wxSOLID
));
670 DrawLine(startUnderscore
, yUnderscore
, endUnderscore
, yUnderscore
);
673 // return bounding rect if requested
676 *rectBounding
= wxRect(x
, y
- heightText
, widthText
, heightText
);
679 CalcBoundingBox(x0
, y0
);
680 CalcBoundingBox(x0
+ width0
, y0
+ height
);
684 void wxDCBase::DoGradientFillLinear(const wxRect
& rect
,
685 const wxColour
& initialColour
,
686 const wxColour
& destColour
,
687 wxDirection nDirection
)
690 wxPen oldPen
= m_pen
;
692 wxUint8 nR1
= destColour
.Red();
693 wxUint8 nG1
= destColour
.Green();
694 wxUint8 nB1
= destColour
.Blue();
695 wxUint8 nR2
= initialColour
.Red();
696 wxUint8 nG2
= initialColour
.Green();
697 wxUint8 nB2
= initialColour
.Blue();
700 if ( nDirection
== wxEAST
|| nDirection
== wxWEST
)
702 wxInt32 x
= rect
.GetWidth();
703 wxInt32 w
= x
; // width of area to shade
704 wxInt32 xDelta
= w
/256; // height of one shade bend
712 nR
= nR1
- (nR1
-nR2
)*(w
-x
)/w
;
714 nR
= nR1
+ (nR2
-nR1
)*(w
-x
)/w
;
717 nG
= nG1
- (nG1
-nG2
)*(w
-x
)/w
;
719 nG
= nG1
+ (nG2
-nG1
)*(w
-x
)/w
;
722 nB
= nB1
- (nB1
-nB2
)*(w
-x
)/w
;
724 nB
= nB1
+ (nB2
-nB1
)*(w
-x
)/w
;
726 SetPen(wxPen(wxColour(nR
, nG
, nB
), 1, wxSOLID
));
727 if(nDirection
== wxEAST
)
728 DrawRectangle(rect
.GetLeft()+x
, rect
.GetTop(),
729 xDelta
, rect
.GetHeight());
730 else //nDirection == wxWEST
731 DrawRectangle(rect
.GetRight()-x
-xDelta
, rect
.GetTop(),
732 xDelta
, rect
.GetHeight());
735 else // nDirection == wxNORTH || nDirection == wxSOUTH
737 wxInt32 y
= rect
.GetHeight();
738 wxInt32 w
= y
; // height of area to shade
739 wxInt32 yDelta
= w
/255; // height of one shade bend
747 nR
= nR1
- (nR1
-nR2
)*(w
-y
)/w
;
749 nR
= nR1
+ (nR2
-nR1
)*(w
-y
)/w
;
752 nG
= nG1
- (nG1
-nG2
)*(w
-y
)/w
;
754 nG
= nG1
+ (nG2
-nG1
)*(w
-y
)/w
;
757 nB
= nB1
- (nB1
-nB2
)*(w
-y
)/w
;
759 nB
= nB1
+ (nB2
-nB1
)*(w
-y
)/w
;
761 SetPen(wxPen(wxColour(nR
, nG
, nB
), 1, wxSOLID
));
762 if(nDirection
== wxNORTH
)
763 DrawRectangle(rect
.GetLeft(), rect
.GetTop()+y
,
764 rect
.GetWidth(), yDelta
);
765 else //nDirection == wxSOUTH
766 DrawRectangle(rect
.GetLeft(), rect
.GetBottom()-y
-yDelta
,
767 rect
.GetWidth(), yDelta
);
774 void wxDCBase::GradientFillConcentric(const wxRect
& rect
,
775 const wxColour
& initialColour
,
776 const wxColour
& destColour
,
777 const wxPoint
& circleCenter
)
779 //save the old pen color
780 wxColour oldPenColour
= m_pen
.GetColour();
782 wxUint8 nR1
= destColour
.Red();
783 wxUint8 nG1
= destColour
.Green();
784 wxUint8 nB1
= destColour
.Blue();
785 wxUint8 nR2
= initialColour
.Red();
786 wxUint8 nG2
= initialColour
.Green();
787 wxUint8 nB2
= initialColour
.Blue();
792 wxInt32 cx
= rect
.GetWidth() / 2;
793 wxInt32 cy
= rect
.GetHeight() / 2;
801 wxInt32 nCircleOffX
= circleCenter
.x
- (rect
.GetWidth() / 2);
802 wxInt32 nCircleOffY
= circleCenter
.y
- (rect
.GetHeight() / 2);
804 for ( wxInt32 x
= 0; x
< rect
.GetWidth(); x
++ )
806 for ( wxInt32 y
= 0; y
< rect
.GetHeight(); y
++ )
808 //get color difference
809 wxInt32 nGradient
= ((nRadius
-
811 pow((double)(x
- cx
- nCircleOffX
), 2) +
812 pow((double)(y
- cy
- nCircleOffY
), 2)
820 nR
= (wxUint8
)(nR1
+ ((nR2
- nR1
) * nGradient
/ 100));
821 nG
= (wxUint8
)(nG1
+ ((nG2
- nG1
) * nGradient
/ 100));
822 nB
= (wxUint8
)(nB1
+ ((nB2
- nB1
) * nGradient
/ 100));
825 m_pen
.SetColour(wxColour(nR
,nG
,nB
));
826 DrawPoint(wxPoint(x
+ rect
.GetLeft(), y
+ rect
.GetTop()));
829 //return old pen color
830 m_pen
.SetColour(oldPenColour
);
834 Notes for wxWidgets DrawEllipticArcRot(...)
836 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
837 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
840 All methods are generic, so they can be implemented in wxDCBase.
841 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
842 methods like (WinCE) wxDC::DoDrawArc(...).
844 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
845 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
846 parts) or every column (in steep parts) only one pixel is calculated.
847 Trigonometric calculation (sin, cos, tan, atan) is only done if the
848 starting angle is not equal to the ending angle. The calculation of the
849 pixels is done using simple arithmetic only and should perform not too
850 bad even on devices without floating point processor. I didn't test this yet.
852 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
853 For instance: an ellipse rotated 180 degrees is drawn
854 slightly different from the original.
856 The points are then moved to an array and used to draw a polyline and/or polygon
857 (with center added, the pie).
858 The result looks quite similar to the native ellipse, only e few pixels differ.
860 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
861 slower as DrawEllipse(...), which calls the native API.
862 An rotated ellipse outside the clipping region takes nearly the same time,
863 while an native ellipse outside takes nearly no time to draw.
865 If you draw an arc with this new method, you will see the starting and ending angles
866 are calculated properly.
867 If you use DrawEllipticArc(...), you will see they are only correct for circles
868 and not properly calculated for ellipses.
871 p.lenhard@t-online.de
875 void wxDCBase::DoDrawEllipticArcRot( wxCoord x
, wxCoord y
,
876 wxCoord w
, wxCoord h
,
877 double sa
, double ea
, double angle
)
881 CalculateEllipticPoints( &list
, x
, y
, w
, h
, sa
, ea
);
882 Rotate( &list
, angle
, wxPoint( x
+w
/2, y
+h
/2 ) );
884 // Add center (for polygon/pie)
885 list
.Append( (wxObject
*) new wxPoint( x
+w
/2, y
+h
/2 ) );
887 // copy list into array and delete list elements
888 int n
= list
.GetCount();
889 wxPoint
*points
= new wxPoint
[n
];
892 for ( node
= list
.GetFirst(); node
; node
= node
->GetNext(), i
++ )
894 wxPoint
*point
= (wxPoint
*)node
->GetData();
895 points
[i
].x
= point
->x
;
896 points
[i
].y
= point
->y
;
900 // first draw the pie without pen, if necessary
901 if( GetBrush() != *wxTRANSPARENT_BRUSH
)
903 wxPen
tempPen( GetPen() );
904 SetPen( *wxTRANSPARENT_PEN
);
905 DoDrawPolygon( n
, points
, 0, 0 );
909 // then draw the arc without brush, if necessary
910 if( GetPen() != *wxTRANSPARENT_PEN
)
913 DoDrawLines( n
-1, points
, 0, 0 );
918 } // DrawEllipticArcRot
920 void wxDCBase::Rotate( wxList
* points
, double angle
, wxPoint center
)
925 double dSinA
= -sin(angle
*2.0*pi
/360.0);
926 double dCosA
= cos(angle
*2.0*pi
/360.0);
927 for ( wxNode
* node
= points
->GetFirst(); node
; node
= node
->GetNext() )
929 wxPoint
* point
= (wxPoint
*)node
->GetData();
931 // transform coordinates, if necessary
932 if( center
.x
) point
->x
-= center
.x
;
933 if( center
.y
) point
->y
-= center
.y
;
935 // calculate rotation, rounding simply by implicit cast to integer
936 int xTemp
= point
->x
* dCosA
- point
->y
* dSinA
;
937 point
->y
= point
->x
* dSinA
+ point
->y
* dCosA
;
940 // back transform coordinates, if necessary
941 if( center
.x
) point
->x
+= center
.x
;
942 if( center
.y
) point
->y
+= center
.y
;
947 void wxDCBase::CalculateEllipticPoints( wxList
* points
,
948 wxCoord xStart
, wxCoord yStart
,
949 wxCoord w
, wxCoord h
,
950 double sa
, double ea
)
961 bool bUseAngles
= false;
967 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
969 if( 2*a
== w
) decrX
= 1;
971 if( 2*b
== h
) decrY
= 1;
973 wxCoord xCenter
= xStart
+ a
;
974 wxCoord yCenter
= yStart
+ b
;
975 // calculate data for start and end, if necessary
979 // normalisation of angles
980 while( sa
<0 ) sa
+= 360;
981 while( ea
<0 ) ea
+= 360;
982 while( sa
>=360 ) sa
-= 360;
983 while( ea
>=360 ) ea
-= 360;
984 // calculate quadrant numbers
985 if( sa
> 270 ) sq
= 3;
986 else if( sa
> 180 ) sq
= 2;
987 else if( sa
> 90 ) sq
= 1;
988 if( ea
> 270 ) eq
= 3;
989 else if( ea
> 180 ) eq
= 2;
990 else if( ea
> 90 ) eq
= 1;
991 sar
= sa
* pi
/ 180.0;
992 ear
= ea
* pi
/ 180.0;
993 // correct angle circle -> ellipse
994 sar
= atan( -a
/(double)b
* tan( sar
) );
995 if ( sq
== 1 || sq
== 2 ) sar
+= pi
;
996 ear
= atan( -a
/(double)b
* tan( ear
) );
997 if ( eq
== 1 || eq
== 2 ) ear
+= pi
;
998 // coordinates of points
999 xsa
= xCenter
+ a
* cos( sar
);
1000 if( sq
== 0 || sq
== 3 ) xsa
-= decrX
;
1001 ysa
= yCenter
+ b
* sin( sar
);
1002 if( sq
== 2 || sq
== 3 ) ysa
-= decrY
;
1003 xea
= xCenter
+ a
* cos( ear
);
1004 if( eq
== 0 || eq
== 3 ) xea
-= decrX
;
1005 yea
= yCenter
+ b
* sin( ear
);
1006 if( eq
== 2 || eq
== 3 ) yea
-= decrY
;
1008 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
1010 double c2
= 2.0 / w
;
1019 // Lists for quadrant 1 to 4
1020 wxList pointsarray
[4];
1021 // Calculate points for first quadrant and set in all quadrants
1022 for( x
= 0; x
<= a
; ++x
)
1027 bool bNewPoint
= false;
1028 while( y2
> c1
- c2
* x2
&& y
> 0 )
1034 // old y now to big: set point with old y, old x
1035 if( bNewPoint
&& x
>1)
1038 // remove points on the same line
1039 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
- y_old
) );
1040 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
- y_old
) );
1041 pointsarray
[2].Insert( (wxObject
*) new wxPoint( xCenter
- x1
, yCenter
+ y_old
- decrY
) );
1042 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ x1
- decrX
, yCenter
+ y_old
- decrY
) );
1044 } // calculate point
1046 // Starting and/or ending points for the quadrants, first quadrant gets both.
1047 pointsarray
[0].Insert( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1048 pointsarray
[0].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
- b
) );
1049 pointsarray
[1].Append( (wxObject
*) new wxPoint( xCenter
- a
, yCenter
) );
1050 pointsarray
[2].Append( (wxObject
*) new wxPoint( xCenter
, yCenter
+ b
- decrY
) );
1051 pointsarray
[3].Append( (wxObject
*) new wxPoint( xCenter
+ a
- decrX
, yCenter
) );
1053 // copy quadrants in original list
1056 // Copy the right part of the points in the lists
1057 // and delete the wxPoints, because they do not leave this method.
1058 points
->Append( (wxObject
*) new wxPoint( xsa
, ysa
) );
1060 bool bStarted
= false;
1061 bool bReady
= false;
1062 bool bForceTurn
= ( sq
== eq
&& sa
> ea
);
1065 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1067 // once: go to starting point in start quadrant
1070 ( (wxPoint
*) node
->GetData() )->x
< xsa
+1 && q
<= 1
1072 ( (wxPoint
*) node
->GetData() )->x
> xsa
-1 && q
>= 2
1079 // copy point, if not at ending point
1082 if( q
!= eq
|| bForceTurn
1084 ( (wxPoint
*) node
->GetData() )->x
> xea
+1 && q
<= 1
1086 ( (wxPoint
*) node
->GetData() )->x
< xea
-1 && q
>= 2
1090 wxPoint
* pPoint
= new wxPoint( *((wxPoint
*) node
->GetData() ) );
1091 points
->Append( (wxObject
*) pPoint
);
1093 else if( q
== eq
&& !bForceTurn
|| ( (wxPoint
*) node
->GetData() )->x
== xea
)
1103 } // while not bReady
1104 points
->Append( (wxObject
*) new wxPoint( xea
, yea
) );
1107 for( q
= 0; q
< 4; ++q
)
1109 for( wxNode
*node
= pointsarray
[q
].GetFirst(); node
; node
= node
->GetNext() )
1111 wxPoint
*p
= (wxPoint
*)node
->GetData();
1119 // copy whole ellipse, wxPoints will be deleted outside
1120 for( node
= pointsarray
[0].GetFirst(); node
; node
= node
->GetNext() )
1122 wxObject
*p
= node
->GetData();
1123 points
->Append( p
);
1125 for( node
= pointsarray
[1].GetFirst(); node
; node
= node
->GetNext() )
1127 wxObject
*p
= node
->GetData();
1128 points
->Append( p
);
1130 for( node
= pointsarray
[2].GetFirst(); node
; node
= node
->GetNext() )
1132 wxObject
*p
= node
->GetData();
1133 points
->Append( p
);
1135 for( node
= pointsarray
[3].GetFirst(); node
; node
= node
->GetNext() )
1137 wxObject
*p
= node
->GetData();
1138 points
->Append( p
);
1141 } // CalculateEllipticPoints