]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
use GetFont() instead of (possibly not initialized) m_font in GetCharWidth/Height()
[wxWidgets.git] / src / common / dcbase.cpp
CommitLineData
dbe94982 1/////////////////////////////////////////////////////////////////////////////
1e6feb95
VZ
2// Name: common/dcbase.cpp
3// Purpose: generic methods of the wxDC Class
4// Author: Vadim Zeitlin
dbe94982
BM
5// Modified by:
6// Created: 05/25/99
7// RCS-ID: $Id$
bd1e9c12 8// Copyright: (c) wxWindows team
55d99c7a 9// Licence: wxWindows licence
dbe94982
BM
10/////////////////////////////////////////////////////////////////////////////
11
1e6feb95
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
14f355c2 16#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
1e6feb95 17 #pragma implementation "dcbase.h"
dbe94982
BM
18#endif
19
1e6feb95
VZ
20// ----------------------------------------------------------------------------
21// headers
22// ----------------------------------------------------------------------------
23
dbe94982
BM
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
bd1e9c12 28 #pragma hdrstop
dbe94982
BM
29#endif
30
dbe94982
BM
31#include "wx/dc.h"
32
672dc5a7
JJ
33#include <math.h>
34
27748047 35// bool wxDCBase::sm_cacheing = FALSE;
0cbff120 36
1e6feb95
VZ
37// ============================================================================
38// implementation
39// ============================================================================
40
41// ----------------------------------------------------------------------------
42// special symbols
43// ----------------------------------------------------------------------------
44
cd9da200
VZ
45void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
46 wxCoord width, wxCoord height)
47{
48 wxCHECK_RET( Ok(), wxT("invalid window dc") );
49
50 wxCoord x2 = x1 + width,
51 y2 = y1 + height;
52
53 // this is to yield width of 3 for width == height == 10
54 SetPen(wxPen(GetTextForeground(), (width + height + 1) / 7, wxSOLID));
55
56 // we're drawing a scaled version of wx/generic/tick.xpm here
57 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
58 y3 = y1 + height / 2; // y of the left tick branch
59 DoDrawLine(x1, y3, x3, y2);
60 DoDrawLine(x3, y2, x2, y1);
61
62 CalcBoundingBox(x1, y1);
63 CalcBoundingBox(x2, y2);
64}
65
1e6feb95
VZ
66// ----------------------------------------------------------------------------
67// line/polygons
68// ----------------------------------------------------------------------------
69
72cdf4c9 70void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
dbe94982 71{
b1d4dd7a 72 int n = list->GetCount();
dbe94982
BM
73 wxPoint *points = new wxPoint[n];
74
75 int i = 0;
222ed1d6 76 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 77 {
b1d4dd7a 78 wxPoint *point = (wxPoint *)node->GetData();
dbe94982
BM
79 points[i].x = point->x;
80 points[i].y = point->y;
81 }
82
83 DoDrawLines(n, points, xoffset, yoffset);
84
85 delete [] points;
86}
87
88
89void wxDCBase::DrawPolygon(const wxList *list,
72cdf4c9 90 wxCoord xoffset, wxCoord yoffset,
dbe94982
BM
91 int fillStyle)
92{
b1d4dd7a 93 int n = list->GetCount();
dbe94982
BM
94 wxPoint *points = new wxPoint[n];
95
96 int i = 0;
222ed1d6 97 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 98 {
b1d4dd7a 99 wxPoint *point = (wxPoint *)node->GetData();
dbe94982
BM
100 points[i].x = point->x;
101 points[i].y = point->y;
102 }
103
104 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
105
106 delete [] points;
107}
108
63b9e659
VZ
109void
110wxDCBase::DoDrawPolyPolygon(int n,
793db755 111 int count[],
63b9e659
VZ
112 wxPoint points[],
113 wxCoord xoffset, wxCoord yoffset,
114 int fillStyle)
115{
116 if ( n == 1 )
117 {
793db755 118 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
63b9e659
VZ
119 return;
120 }
121
122 int i, j, lastOfs;
123 wxPoint* pts;
124 wxPen pen;
125
126 for (i = j = lastOfs = 0; i < n; i++)
127 {
128 lastOfs = j;
793db755 129 j += count[i];
63b9e659
VZ
130 }
131 pts = new wxPoint[j+n-1];
132 for (i = 0; i < j; i++)
133 pts[i] = points[i];
134 for (i = 2; i <= n; i++)
135 {
793db755 136 lastOfs -= count[n-i];
63b9e659
VZ
137 pts[j++] = pts[lastOfs];
138 }
139
140 pen = GetPen();
141 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
142 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
143 SetPen(pen);
144 for (i = j = 0; i < n; i++)
145 {
793db755
VZ
146 DoDrawLines(count[i], pts+j, xoffset, yoffset);
147 j += count[i];
63b9e659 148 }
6db1f43b 149 delete[] pts;
63b9e659
VZ
150}
151
1e6feb95
VZ
152// ----------------------------------------------------------------------------
153// splines
154// ----------------------------------------------------------------------------
dbe94982 155
88ac883a 156#if wxUSE_SPLINES
dbe94982
BM
157
158// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
72cdf4c9 159void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
dbe94982
BM
160{
161 wxList point_list;
162
163 wxPoint *point1 = new wxPoint;
164 point1->x = x1; point1->y = y1;
165 point_list.Append((wxObject*)point1);
166
167 wxPoint *point2 = new wxPoint;
168 point2->x = x2; point2->y = y2;
169 point_list.Append((wxObject*)point2);
170
171 wxPoint *point3 = new wxPoint;
172 point3->x = x3; point3->y = y3;
173 point_list.Append((wxObject*)point3);
174
175 DrawSpline(&point_list);
176
222ed1d6 177 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
dbe94982 178 {
b1d4dd7a 179 wxPoint *p = (wxPoint *)node->GetData();
dbe94982
BM
180 delete p;
181 }
182}
183
184void wxDCBase::DrawSpline(int n, wxPoint points[])
185{
186 wxList list;
187 for (int i =0; i < n; i++)
188 {
189 list.Append((wxObject*)&points[i]);
190 }
191
192 DrawSpline(&list);
193}
194
fe2e4366
VS
195// ----------------------------------- spline code ----------------------------------------
196
197void wx_quadratic_spline(double a1, double b1, double a2, double b2,
198 double a3, double b3, double a4, double b4);
199void wx_clear_stack();
200int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
201 double *y3, double *x4, double *y4);
202void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
203 double x4, double y4);
204static bool wx_spline_add_point(double x, double y);
205static void wx_spline_draw_point_array(wxDCBase *dc);
206
207wxList wx_spline_point_list;
208
209#define half(z1, z2) ((z1+z2)/2.0)
210#define THRESHOLD 5
211
212/* iterative version */
213
214void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
215 double b4)
216{
217 register double xmid, ymid;
218 double x1, y1, x2, y2, x3, y3, x4, y4;
219
220 wx_clear_stack();
221 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
222
223 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
224 xmid = (double)half(x2, x3);
225 ymid = (double)half(y2, y3);
226 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
227 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
228 wx_spline_add_point( x1, y1 );
229 wx_spline_add_point( xmid, ymid );
230 } else {
231 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
232 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
233 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
234 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
235 }
236 }
237}
238
239/* utilities used by spline drawing routines */
240
241typedef struct wx_spline_stack_struct {
242 double x1, y1, x2, y2, x3, y3, x4, y4;
243} Stack;
244
245#define SPLINE_STACK_DEPTH 20
246static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
247static Stack *wx_stack_top;
248static int wx_stack_count;
249
250void wx_clear_stack()
251{
252 wx_stack_top = wx_spline_stack;
253 wx_stack_count = 0;
254}
255
256void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
257{
258 wx_stack_top->x1 = x1;
259 wx_stack_top->y1 = y1;
260 wx_stack_top->x2 = x2;
261 wx_stack_top->y2 = y2;
262 wx_stack_top->x3 = x3;
263 wx_stack_top->y3 = y3;
264 wx_stack_top->x4 = x4;
265 wx_stack_top->y4 = y4;
266 wx_stack_top++;
267 wx_stack_count++;
268}
269
270int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
271 double *x3, double *y3, double *x4, double *y4)
272{
273 if (wx_stack_count == 0)
274 return (0);
275 wx_stack_top--;
276 wx_stack_count--;
277 *x1 = wx_stack_top->x1;
278 *y1 = wx_stack_top->y1;
279 *x2 = wx_stack_top->x2;
280 *y2 = wx_stack_top->y2;
281 *x3 = wx_stack_top->x3;
282 *y3 = wx_stack_top->y3;
283 *x4 = wx_stack_top->x4;
284 *y4 = wx_stack_top->y4;
285 return (1);
286}
287
288static bool wx_spline_add_point(double x, double y)
289{
290 wxPoint *point = new wxPoint ;
291 point->x = (int) x;
292 point->y = (int) y;
293 wx_spline_point_list.Append((wxObject*)point);
294 return TRUE;
295}
296
297static void wx_spline_draw_point_array(wxDCBase *dc)
298{
299 dc->DrawLines(&wx_spline_point_list, 0, 0 );
222ed1d6 300 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
fe2e4366
VS
301 while (node)
302 {
b1d4dd7a 303 wxPoint *point = (wxPoint *)node->GetData();
fe2e4366 304 delete point;
222ed1d6 305 wx_spline_point_list.Erase(node);
b1d4dd7a 306 node = wx_spline_point_list.GetFirst();
fe2e4366
VS
307 }
308}
309
310void wxDCBase::DoDrawSpline( wxList *points )
311{
312 wxCHECK_RET( Ok(), wxT("invalid window dc") );
313
314 wxPoint *p;
315 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
316 double x1, y1, x2, y2;
317
222ed1d6 318 wxList::compatibility_iterator node = points->GetFirst();
b1d4dd7a 319 p = (wxPoint *)node->GetData();
fe2e4366
VS
320
321 x1 = p->x;
322 y1 = p->y;
323
b1d4dd7a
RL
324 node = node->GetNext();
325 p = (wxPoint *)node->GetData();
fe2e4366
VS
326
327 x2 = p->x;
328 y2 = p->y;
329 cx1 = (double)((x1 + x2) / 2);
330 cy1 = (double)((y1 + y2) / 2);
331 cx2 = (double)((cx1 + x2) / 2);
332 cy2 = (double)((cy1 + y2) / 2);
333
334 wx_spline_add_point(x1, y1);
335
28b4db7f
VZ
336 while ((node = node->GetNext())
337#if !wxUSE_STL
338 != NULL
339#endif // !wxUSE_STL
340 )
fe2e4366 341 {
b1d4dd7a 342 p = (wxPoint *)node->GetData();
fe2e4366
VS
343 x1 = x2;
344 y1 = y2;
345 x2 = p->x;
346 y2 = p->y;
347 cx4 = (double)(x1 + x2) / 2;
348 cy4 = (double)(y1 + y2) / 2;
349 cx3 = (double)(x1 + cx4) / 2;
350 cy3 = (double)(y1 + cy4) / 2;
351
352 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
353
354 cx1 = cx4;
355 cy1 = cy4;
356 cx2 = (double)(cx1 + x2) / 2;
357 cy2 = (double)(cy1 + y2) / 2;
358 }
359
360 wx_spline_add_point( cx1, cy1 );
361 wx_spline_add_point( x2, y2 );
362
363 wx_spline_draw_point_array( this );
364}
365
88ac883a 366#endif // wxUSE_SPLINES
1e6feb95 367
0919e93e
RD
368// ----------------------------------------------------------------------------
369// Partial Text Extents
370// ----------------------------------------------------------------------------
371
372
373// Each element of the array will be the width of the string up to and
374// including the coresoponding character in text. This is the generic
375// implementation, the port-specific classes should do this with native APIs
376// if available.
377
378bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
379{
380 int totalWidth = 0;
381 size_t i;
382
383 widths.Empty();
384 widths.Add(0, text.Length());
385
386 // Calculate the position of each character based on the widths of
387 // the previous characters
388 for (i=0; i<text.Length(); i++) {
389 int w, h;
390 GetTextExtent(text[i], &w, &h);
391 totalWidth += w;
392 widths[i] = totalWidth;
393 }
394 return true;
395}
396
397
1e6feb95
VZ
398// ----------------------------------------------------------------------------
399// enhanced text drawing
400// ----------------------------------------------------------------------------
401
402void wxDCBase::GetMultiLineTextExtent(const wxString& text,
403 wxCoord *x,
404 wxCoord *y,
405 wxCoord *h,
406 wxFont *font)
407{
c7aaa64f
VS
408 wxCoord widthTextMax = 0, widthLine,
409 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
1e6feb95
VZ
410
411 wxString curLine;
412 for ( const wxChar *pc = text; ; pc++ )
413 {
414 if ( *pc == _T('\n') || *pc == _T('\0') )
415 {
416 if ( curLine.empty() )
417 {
418 // we can't use GetTextExtent - it will return 0 for both width
419 // and height and an empty line should count in height
420 // calculation
421
422 // assume that this line has the same height as the previous
423 // one
424 if ( !heightLineDefault )
425 heightLineDefault = heightLine;
426
427 if ( !heightLineDefault )
428 {
429 // but we don't know it yet - choose something reasonable
430 GetTextExtent(_T("W"), NULL, &heightLineDefault,
431 NULL, NULL, font);
432 }
433
434 heightTextTotal += heightLineDefault;
435 }
436 else
437 {
438 GetTextExtent(curLine, &widthLine, &heightLine,
439 NULL, NULL, font);
440 if ( widthLine > widthTextMax )
441 widthTextMax = widthLine;
442 heightTextTotal += heightLine;
443 }
444
445 if ( *pc == _T('\n') )
446 {
447 curLine.clear();
448 }
449 else
450 {
451 // the end of string
452 break;
453 }
454 }
455 else
456 {
457 curLine += *pc;
458 }
459 }
460
461 if ( x )
462 *x = widthTextMax;
463 if ( y )
464 *y = heightTextTotal;
465 if ( h )
466 *h = heightLine;
467}
468
469void wxDCBase::DrawLabel(const wxString& text,
470 const wxBitmap& bitmap,
471 const wxRect& rect,
472 int alignment,
473 int indexAccel,
474 wxRect *rectBounding)
475{
476 // find the text position
477 wxCoord widthText, heightText, heightLine;
478 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
479
480 wxCoord width, height;
481 if ( bitmap.Ok() )
482 {
483 width = widthText + bitmap.GetWidth();
484 height = bitmap.GetHeight();
485 }
486 else // no bitmap
487 {
488 width = widthText;
489 height = heightText;
490 }
491
492 wxCoord x, y;
493 if ( alignment & wxALIGN_RIGHT )
494 {
495 x = rect.GetRight() - width;
496 }
497 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
498 {
499 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
500 }
501 else // alignment & wxALIGN_LEFT
502 {
503 x = rect.GetLeft();
504 }
505
506 if ( alignment & wxALIGN_BOTTOM )
507 {
508 y = rect.GetBottom() - height;
509 }
510 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
511 {
512 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
513 }
514 else // alignment & wxALIGN_TOP
515 {
516 y = rect.GetTop();
517 }
518
519 // draw the bitmap first
520 wxCoord x0 = x,
521 y0 = y,
522 width0 = width;
523 if ( bitmap.Ok() )
524 {
525 DrawBitmap(bitmap, x, y, TRUE /* use mask */);
526
527 wxCoord offset = bitmap.GetWidth() + 4;
528 x += offset;
529 width -= offset;
530
531 y += (height - heightText) / 2;
532 }
533
534 // we will draw the underscore under the accel char later
535 wxCoord startUnderscore = 0,
536 endUnderscore = 0,
537 yUnderscore = 0;
538
539 // split the string into lines and draw each of them separately
540 wxString curLine;
541 for ( const wxChar *pc = text; ; pc++ )
542 {
543 if ( *pc == _T('\n') || *pc == _T('\0') )
544 {
545 int xRealStart = x; // init it here to avoid compielr warnings
546
547 if ( !curLine.empty() )
548 {
549 // NB: can't test for !(alignment & wxALIGN_LEFT) because
550 // wxALIGN_LEFT is 0
551 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
552 {
553 wxCoord widthLine;
554 GetTextExtent(curLine, &widthLine, NULL);
555
556 if ( alignment & wxALIGN_RIGHT )
557 {
558 xRealStart += width - widthLine;
559 }
560 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
561 {
562 xRealStart += (width - widthLine) / 2;
563 }
564 }
565 //else: left aligned, nothing to do
566
567 DrawText(curLine, xRealStart, y);
568 }
569
570 y += heightLine;
571
572 // do we have underscore in this line? we can check yUnderscore
573 // because it is set below to just y + heightLine if we do
574 if ( y == yUnderscore )
575 {
576 // adjust the horz positions to account for the shift
577 startUnderscore += xRealStart;
578 endUnderscore += xRealStart;
579 }
580
581 if ( *pc == _T('\0') )
582 break;
583
584 curLine.clear();
585 }
586 else // not end of line
587 {
328bfc22 588 if ( pc - text.c_str() == indexAccel )
1e6feb95
VZ
589 {
590 // remeber to draw underscore here
591 GetTextExtent(curLine, &startUnderscore, NULL);
592 curLine += *pc;
593 GetTextExtent(curLine, &endUnderscore, NULL);
594
595 yUnderscore = y + heightLine;
596 }
597 else
598 {
599 curLine += *pc;
600 }
601 }
602 }
603
604 // draw the underscore if found
605 if ( startUnderscore != endUnderscore )
606 {
607 // it should be of the same colour as text
608 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
609
610 yUnderscore--;
611
612 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
613 }
614
615 // return bounding rect if requested
616 if ( rectBounding )
617 {
618 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
619 }
620
621 CalcBoundingBox(x0, y0);
622 CalcBoundingBox(x0 + width0, y0 + height);
623}
12bdd77c
JS
624
625/*
626Notes for wxWindows DrawEllipticArcRot(...)
627
628wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
629It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
630which are also new.
631
632All methods are generic, so they can be implemented in wxDCBase.
633DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
634methods like (WinCE) wxDC::DoDrawArc(...).
635
636CalculateEllipticPoints(...) fills a given list of wxPoints with some points
637of an elliptic arc. The algorithm is pixel-based: In every row (in flat
638parts) or every column (in steep parts) only one pixel is calculated.
639Trigonometric calculation (sin, cos, tan, atan) is only done if the
640starting angle is not equal to the ending angle. The calculation of the
641pixels is done using simple arithmetic only and should perform not too
642bad even on devices without floating point processor. I didn't test this yet.
643
644Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
645For instance: an ellipse rotated 180 degrees is drawn
646slightly different from the original.
647
648The points are then moved to an array and used to draw a polyline and/or polygon
649(with center added, the pie).
650The result looks quite similar to the native ellipse, only e few pixels differ.
651
652The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
653slower as DrawEllipse(...), which calls the native API.
654An rotated ellipse outside the clipping region takes nearly the same time,
655while an native ellipse outside takes nearly no time to draw.
656
657If you draw an arc with this new method, you will see the starting and ending angles
658are calculated properly.
659If you use DrawEllipticArc(...), you will see they are only correct for circles
660and not properly calculated for ellipses.
661
662Peter Lenhard
663p.lenhard@t-online.de
664*/
665
666#ifdef __WXWINCE__
667void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
668 wxCoord w, wxCoord h,
669 double sa, double ea, double angle )
670{
671 wxList list;
672
673 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
674 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
675
676 // Add center (for polygon/pie)
677 list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) );
678
679 // copy list into array and delete list elements
680 int n = list.Number();
681 wxPoint *points = new wxPoint[n];
682 int i = 0;
683 wxNode* node = 0;
684 for ( node = list.First(); node; node = node->Next(), i++ )
685 {
686 wxPoint *point = (wxPoint *)node->Data();
687 points[i].x = point->x;
688 points[i].y = point->y;
689 delete point;
690 }
691
692 // first draw the pie without pen, if necessary
63b9e659 693 if( GetBrush() != *wxTRANSPARENT_BRUSH )
12bdd77c
JS
694 {
695 wxPen tempPen( GetPen() );
696 SetPen( *wxTRANSPARENT_PEN );
697 DoDrawPolygon( n, points, 0, 0 );
698 SetPen( tempPen );
699 }
700
701 // then draw the arc without brush, if necessary
63b9e659 702 if( GetPen() != *wxTRANSPARENT_PEN )
12bdd77c
JS
703 {
704 // without center
705 DoDrawLines( n-1, points, 0, 0 );
706 }
707
708 delete [] points;
709
710} // DrawEllipticArcRot
711
712void wxDCBase::Rotate( wxList* points, double angle, wxPoint center )
713{
714 if( angle != 0.0 )
715 {
716 double pi(3.1415926536);
717 double dSinA = -sin(angle*2.0*pi/360.0);
718 double dCosA = cos(angle*2.0*pi/360.0);
719 for ( wxNode* node = points->First(); node; node = node->Next() )
720 {
721 wxPoint* point = (wxPoint*)node->Data();
722
723 // transform coordinates, if necessary
724 if( center.x ) point->x -= center.x;
725 if( center.y ) point->y -= center.y;
726
727 // calculate rotation, rounding simply by implicit cast to integer
728 int xTemp = point->x * dCosA - point->y * dSinA;
729 point->y = point->x * dSinA + point->y * dCosA;
730 point->x = xTemp;
731
732 // back transform coordinates, if necessary
733 if( center.x ) point->x += center.x;
734 if( center.y ) point->y += center.y;
735 }
736 }
737}
738
739void wxDCBase::CalculateEllipticPoints( wxList* points,
740 wxCoord xStart, wxCoord yStart,
741 wxCoord w, wxCoord h,
742 double sa, double ea )
743{
744 double pi = 3.1415926535;
745 double sar = 0;
746 double ear = 0;
747 int xsa = 0;
748 int ysa = 0;
749 int xea = 0;
750 int yea = 0;
751 int sq = 0;
752 int eq = 0;
753 bool bUseAngles = false;
754 if( w<0 ) w = -w;
755 if( h<0 ) h = -h;
756 // half-axes
757 wxCoord a = w/2;
758 wxCoord b = h/2;
759 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
760 int decrX = 0;
761 if( 2*a == w ) decrX = 1;
762 int decrY = 0;
763 if( 2*b == h ) decrY = 1;
764 // center
765 wxCoord xCenter = xStart + a;
766 wxCoord yCenter = yStart + b;
767 // calculate data for start and end, if necessary
768 if( sa != ea )
769 {
770 bUseAngles = true;
771 // normalisation of angles
772 while( sa<0 ) sa += 360;
773 while( ea<0 ) ea += 360;
774 while( sa>=360 ) sa -= 360;
775 while( ea>=360 ) ea -= 360;
776 // calculate quadrant numbers
777 if( sa > 270 ) sq = 3;
778 else if( sa > 180 ) sq = 2;
779 else if( sa > 90 ) sq = 1;
780 if( ea > 270 ) eq = 3;
781 else if( ea > 180 ) eq = 2;
782 else if( ea > 90 ) eq = 1;
783 sar = sa * pi / 180.0;
784 ear = ea * pi / 180.0;
785 // correct angle circle -> ellipse
786 sar = atan( -a/(double)b * tan( sar ) );
787 if ( sq == 1 || sq == 2 ) sar += pi;
788 ear = atan( -a/(double)b * tan( ear ) );
789 if ( eq == 1 || eq == 2 ) ear += pi;
790 // coordinates of points
791 xsa = xCenter + a * cos( sar );
792 if( sq == 0 || sq == 3 ) xsa -= decrX;
793 ysa = yCenter + b * sin( sar );
794 if( sq == 2 || sq == 3 ) ysa -= decrY;
795 xea = xCenter + a * cos( ear );
796 if( eq == 0 || eq == 3 ) xea -= decrX;
797 yea = yCenter + b * sin( ear );
798 if( eq == 2 || eq == 3 ) yea -= decrY;
799 } // if iUseAngles
800 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
801 double c1 = b * b;
802 double c2 = 2.0 / w;
803 c2 *= c2;
804 c2 *= c1;
805 wxCoord x = 0;
806 wxCoord y = b;
807 long x2 = 1;
808 long y2 = y*y;
809 long y2_old = 0;
810 long y_old = 0;
811 // Lists for quadrant 1 to 4
812 wxList pointsarray[4];
813 // Calculate points for first quadrant and set in all quadrants
814 for( x = 0; x <= a; ++x )
815 {
816 x2 = x2+x+x-1;
817 y2_old = y2;
818 y_old = y;
819 bool bNewPoint = false;
820 while( y2 > c1 - c2 * x2 && y > 0 )
821 {
822 bNewPoint = true;
823 y2 = y2-y-y+1;
824 --y;
825 }
826 // old y now to big: set point with old y, old x
827 if( bNewPoint && x>1)
828 {
829 int x1 = x - 1;
830 // remove points on the same line
831 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
832 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) );
833 pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
834 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
835 } // set point
836 } // calculate point
837
838 // Starting and/or ending points for the quadrants, first quadrant gets both.
839 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
840 pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) );
841 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) );
842 pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) );
843 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
844
845 // copy quadrants in original list
846 if( bUseAngles )
847 {
848 // Copy the right part of the points in the lists
849 // and delete the wxPoints, because they do not leave this method.
850 points->Append( (wxObject*) new wxPoint( xsa, ysa ) );
851 int q = sq;
852 bool bStarted = false;
853 bool bReady = false;
854 bool bForceTurn = ( sq == eq && sa > ea );
855 while( !bReady )
856 {
857 for( wxNode *node = pointsarray[q].First(); node; node = node->Next() )
858 {
859 // once: go to starting point in start quadrant
860 if( !bStarted &&
861 (
862 ( (wxPoint*) node->Data() )->x < xsa+1 && q <= 1
863 ||
864 ( (wxPoint*) node->Data() )->x > xsa-1 && q >= 2
865 )
866 )
867 {
868 bStarted = true;
869 }
870
871 // copy point, if not at ending point
872 if( bStarted )
873 {
874 if( q != eq || bForceTurn
875 ||
876 ( (wxPoint*) node->Data() )->x > xea+1 && q <= 1
877 ||
878 ( (wxPoint*) node->Data() )->x < xea-1 && q >= 2
879 )
880 {
881 // copy point
882 wxPoint* pPoint = new wxPoint( *((wxPoint*) node->Data() ) );
883 points->Append( (wxObject*) pPoint );
884 }
885 else if( q == eq && !bForceTurn || ( (wxPoint*) node->Data() )->x == xea)
886 {
887 bReady = true;
888 }
889 }
890 } // for node
891 ++q;
892 if( q > 3 ) q = 0;
893 bForceTurn = false;
894 bStarted = true;
895 } // while not bReady
896 points->Append( (wxObject*) new wxPoint( xea, yea ) );
897
898 // delete points
899 for( q = 0; q < 4; ++q )
900 {
901 for( wxNode *node = pointsarray[q].First(); node; node = node->Next() )
902 {
903 wxPoint *p = (wxPoint *)node->Data();
904 delete p;
905 }
906 }
907
908 }
909 else
910 {
911 // copy whole ellipse, wxPoints will be deleted outside
912 for( wxNode *node = pointsarray[0].First(); node; node = node->Next() )
913 {
914 wxObject *p = node->Data();
915 points->Append( p );
916 }
917 for( node = pointsarray[1].First(); node; node = node->Next() )
918 {
919 wxObject *p = node->Data();
920 points->Append( p );
921 }
922 for( node = pointsarray[2].First(); node; node = node->Next() )
923 {
924 wxObject *p = node->Data();
925 points->Append( p );
926 }
927 for( node = pointsarray[3].First(); node; node = node->Next() )
928 {
929 wxObject *p = node->Data();
930 points->Append( p );
931 }
932 } // not iUseAngles
933} // CalculateEllipticPoints
934
935#endif
936