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