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