]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcbase.cpp
Delay checking for the requested sash position until the first
[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) wxWindows team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
17 #pragma implementation "dcbase.h"
18 #endif
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #include "wx/dc.h"
32
33 #include <math.h>
34
35 // bool wxDCBase::sm_cacheing = FALSE;
36
37 // ============================================================================
38 // implementation
39 // ============================================================================
40
41 // ----------------------------------------------------------------------------
42 // special symbols
43 // ----------------------------------------------------------------------------
44
45 void 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
66 // ----------------------------------------------------------------------------
67 // line/polygons
68 // ----------------------------------------------------------------------------
69
70 void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
71 {
72 int n = list->GetCount();
73 wxPoint *points = new wxPoint[n];
74
75 int i = 0;
76 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
77 {
78 wxPoint *point = (wxPoint *)node->GetData();
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
89 void wxDCBase::DrawPolygon(const wxList *list,
90 wxCoord xoffset, wxCoord yoffset,
91 int fillStyle)
92 {
93 int n = list->GetCount();
94 wxPoint *points = new wxPoint[n];
95
96 int i = 0;
97 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
98 {
99 wxPoint *point = (wxPoint *)node->GetData();
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
109 void
110 wxDCBase::DoDrawPolyPolygon(int n,
111 int count[],
112 wxPoint points[],
113 wxCoord xoffset, wxCoord yoffset,
114 int fillStyle)
115 {
116 if ( n == 1 )
117 {
118 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
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;
129 j += count[i];
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 {
136 lastOfs -= count[n-i];
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 {
146 DoDrawLines(count[i], pts+j, xoffset, yoffset);
147 j += count[i];
148 }
149 delete pts;
150 }
151
152 // ----------------------------------------------------------------------------
153 // splines
154 // ----------------------------------------------------------------------------
155
156 #if wxUSE_SPLINES
157
158 // TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
159 void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
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
177 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
178 {
179 wxPoint *p = (wxPoint *)node->GetData();
180 delete p;
181 }
182 }
183
184 void 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
195 // ----------------------------------- spline code ----------------------------------------
196
197 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
198 double a3, double b3, double a4, double b4);
199 void wx_clear_stack();
200 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
201 double *y3, double *x4, double *y4);
202 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
203 double x4, double y4);
204 static bool wx_spline_add_point(double x, double y);
205 static void wx_spline_draw_point_array(wxDCBase *dc);
206
207 wxList wx_spline_point_list;
208
209 #define half(z1, z2) ((z1+z2)/2.0)
210 #define THRESHOLD 5
211
212 /* iterative version */
213
214 void 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
241 typedef struct wx_spline_stack_struct {
242 double x1, y1, x2, y2, x3, y3, x4, y4;
243 } Stack;
244
245 #define SPLINE_STACK_DEPTH 20
246 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
247 static Stack *wx_stack_top;
248 static int wx_stack_count;
249
250 void wx_clear_stack()
251 {
252 wx_stack_top = wx_spline_stack;
253 wx_stack_count = 0;
254 }
255
256 void 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
270 int 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
288 static 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
297 static void wx_spline_draw_point_array(wxDCBase *dc)
298 {
299 dc->DrawLines(&wx_spline_point_list, 0, 0 );
300 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
301 while (node)
302 {
303 wxPoint *point = (wxPoint *)node->GetData();
304 delete point;
305 wx_spline_point_list.Erase(node);
306 node = wx_spline_point_list.GetFirst();
307 }
308 }
309
310 void 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
318 wxList::compatibility_iterator node = points->GetFirst();
319 p = (wxPoint *)node->GetData();
320
321 x1 = p->x;
322 y1 = p->y;
323
324 node = node->GetNext();
325 p = (wxPoint *)node->GetData();
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
336 while ((node = node->GetNext())
337 #if !wxUSE_STL
338 != NULL
339 #endif // !wxUSE_STL
340 )
341 {
342 p = (wxPoint *)node->GetData();
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
366 #endif // wxUSE_SPLINES
367
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
378 bool 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
398 // ----------------------------------------------------------------------------
399 // enhanced text drawing
400 // ----------------------------------------------------------------------------
401
402 void wxDCBase::GetMultiLineTextExtent(const wxString& text,
403 wxCoord *x,
404 wxCoord *y,
405 wxCoord *h,
406 wxFont *font)
407 {
408 wxCoord widthTextMax = 0, widthLine,
409 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
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
469 void 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 {
588 if ( pc - text.c_str() == indexAccel )
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 }
624
625 /*
626 Notes for wxWindows DrawEllipticArcRot(...)
627
628 wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
629 It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
630 which are also new.
631
632 All methods are generic, so they can be implemented in wxDCBase.
633 DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
634 methods like (WinCE) wxDC::DoDrawArc(...).
635
636 CalculateEllipticPoints(...) fills a given list of wxPoints with some points
637 of an elliptic arc. The algorithm is pixel-based: In every row (in flat
638 parts) or every column (in steep parts) only one pixel is calculated.
639 Trigonometric calculation (sin, cos, tan, atan) is only done if the
640 starting angle is not equal to the ending angle. The calculation of the
641 pixels is done using simple arithmetic only and should perform not too
642 bad even on devices without floating point processor. I didn't test this yet.
643
644 Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
645 For instance: an ellipse rotated 180 degrees is drawn
646 slightly different from the original.
647
648 The points are then moved to an array and used to draw a polyline and/or polygon
649 (with center added, the pie).
650 The result looks quite similar to the native ellipse, only e few pixels differ.
651
652 The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
653 slower as DrawEllipse(...), which calls the native API.
654 An rotated ellipse outside the clipping region takes nearly the same time,
655 while an native ellipse outside takes nearly no time to draw.
656
657 If you draw an arc with this new method, you will see the starting and ending angles
658 are calculated properly.
659 If you use DrawEllipticArc(...), you will see they are only correct for circles
660 and not properly calculated for ellipses.
661
662 Peter Lenhard
663 p.lenhard@t-online.de
664 */
665
666 #ifdef __WXWINCE__
667 void 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
693 if( GetBrush() != *wxTRANSPARENT_BRUSH )
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
702 if( GetPen() != *wxTRANSPARENT_PEN )
703 {
704 // without center
705 DoDrawLines( n-1, points, 0, 0 );
706 }
707
708 delete [] points;
709
710 } // DrawEllipticArcRot
711
712 void 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
739 void 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