]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
as after recent change wxID_SEPARATOR is now -2, it is better for idMenuTitle to...
[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,
111 int start[],
112 wxPoint points[],
113 wxCoord xoffset, wxCoord yoffset,
114 int fillStyle)
115{
116 if ( n == 1 )
117 {
118 DoDrawPolygon(start[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 += start[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 -= start[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(start[i], pts+j, xoffset, yoffset);
147 j += start[i];
148 }
149 delete pts;
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
VZ
367
368// ----------------------------------------------------------------------------
369// enhanced text drawing
370// ----------------------------------------------------------------------------
371
372void wxDCBase::GetMultiLineTextExtent(const wxString& text,
373 wxCoord *x,
374 wxCoord *y,
375 wxCoord *h,
376 wxFont *font)
377{
c7aaa64f
VS
378 wxCoord widthTextMax = 0, widthLine,
379 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
1e6feb95
VZ
380
381 wxString curLine;
382 for ( const wxChar *pc = text; ; pc++ )
383 {
384 if ( *pc == _T('\n') || *pc == _T('\0') )
385 {
386 if ( curLine.empty() )
387 {
388 // we can't use GetTextExtent - it will return 0 for both width
389 // and height and an empty line should count in height
390 // calculation
391
392 // assume that this line has the same height as the previous
393 // one
394 if ( !heightLineDefault )
395 heightLineDefault = heightLine;
396
397 if ( !heightLineDefault )
398 {
399 // but we don't know it yet - choose something reasonable
400 GetTextExtent(_T("W"), NULL, &heightLineDefault,
401 NULL, NULL, font);
402 }
403
404 heightTextTotal += heightLineDefault;
405 }
406 else
407 {
408 GetTextExtent(curLine, &widthLine, &heightLine,
409 NULL, NULL, font);
410 if ( widthLine > widthTextMax )
411 widthTextMax = widthLine;
412 heightTextTotal += heightLine;
413 }
414
415 if ( *pc == _T('\n') )
416 {
417 curLine.clear();
418 }
419 else
420 {
421 // the end of string
422 break;
423 }
424 }
425 else
426 {
427 curLine += *pc;
428 }
429 }
430
431 if ( x )
432 *x = widthTextMax;
433 if ( y )
434 *y = heightTextTotal;
435 if ( h )
436 *h = heightLine;
437}
438
439void wxDCBase::DrawLabel(const wxString& text,
440 const wxBitmap& bitmap,
441 const wxRect& rect,
442 int alignment,
443 int indexAccel,
444 wxRect *rectBounding)
445{
446 // find the text position
447 wxCoord widthText, heightText, heightLine;
448 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
449
450 wxCoord width, height;
451 if ( bitmap.Ok() )
452 {
453 width = widthText + bitmap.GetWidth();
454 height = bitmap.GetHeight();
455 }
456 else // no bitmap
457 {
458 width = widthText;
459 height = heightText;
460 }
461
462 wxCoord x, y;
463 if ( alignment & wxALIGN_RIGHT )
464 {
465 x = rect.GetRight() - width;
466 }
467 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
468 {
469 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
470 }
471 else // alignment & wxALIGN_LEFT
472 {
473 x = rect.GetLeft();
474 }
475
476 if ( alignment & wxALIGN_BOTTOM )
477 {
478 y = rect.GetBottom() - height;
479 }
480 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
481 {
482 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
483 }
484 else // alignment & wxALIGN_TOP
485 {
486 y = rect.GetTop();
487 }
488
489 // draw the bitmap first
490 wxCoord x0 = x,
491 y0 = y,
492 width0 = width;
493 if ( bitmap.Ok() )
494 {
495 DrawBitmap(bitmap, x, y, TRUE /* use mask */);
496
497 wxCoord offset = bitmap.GetWidth() + 4;
498 x += offset;
499 width -= offset;
500
501 y += (height - heightText) / 2;
502 }
503
504 // we will draw the underscore under the accel char later
505 wxCoord startUnderscore = 0,
506 endUnderscore = 0,
507 yUnderscore = 0;
508
509 // split the string into lines and draw each of them separately
510 wxString curLine;
511 for ( const wxChar *pc = text; ; pc++ )
512 {
513 if ( *pc == _T('\n') || *pc == _T('\0') )
514 {
515 int xRealStart = x; // init it here to avoid compielr warnings
516
517 if ( !curLine.empty() )
518 {
519 // NB: can't test for !(alignment & wxALIGN_LEFT) because
520 // wxALIGN_LEFT is 0
521 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
522 {
523 wxCoord widthLine;
524 GetTextExtent(curLine, &widthLine, NULL);
525
526 if ( alignment & wxALIGN_RIGHT )
527 {
528 xRealStart += width - widthLine;
529 }
530 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
531 {
532 xRealStart += (width - widthLine) / 2;
533 }
534 }
535 //else: left aligned, nothing to do
536
537 DrawText(curLine, xRealStart, y);
538 }
539
540 y += heightLine;
541
542 // do we have underscore in this line? we can check yUnderscore
543 // because it is set below to just y + heightLine if we do
544 if ( y == yUnderscore )
545 {
546 // adjust the horz positions to account for the shift
547 startUnderscore += xRealStart;
548 endUnderscore += xRealStart;
549 }
550
551 if ( *pc == _T('\0') )
552 break;
553
554 curLine.clear();
555 }
556 else // not end of line
557 {
328bfc22 558 if ( pc - text.c_str() == indexAccel )
1e6feb95
VZ
559 {
560 // remeber to draw underscore here
561 GetTextExtent(curLine, &startUnderscore, NULL);
562 curLine += *pc;
563 GetTextExtent(curLine, &endUnderscore, NULL);
564
565 yUnderscore = y + heightLine;
566 }
567 else
568 {
569 curLine += *pc;
570 }
571 }
572 }
573
574 // draw the underscore if found
575 if ( startUnderscore != endUnderscore )
576 {
577 // it should be of the same colour as text
578 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
579
580 yUnderscore--;
581
582 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
583 }
584
585 // return bounding rect if requested
586 if ( rectBounding )
587 {
588 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
589 }
590
591 CalcBoundingBox(x0, y0);
592 CalcBoundingBox(x0 + width0, y0 + height);
593}
12bdd77c
JS
594
595/*
596Notes for wxWindows DrawEllipticArcRot(...)
597
598wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
599It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
600which are also new.
601
602All methods are generic, so they can be implemented in wxDCBase.
603DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
604methods like (WinCE) wxDC::DoDrawArc(...).
605
606CalculateEllipticPoints(...) fills a given list of wxPoints with some points
607of an elliptic arc. The algorithm is pixel-based: In every row (in flat
608parts) or every column (in steep parts) only one pixel is calculated.
609Trigonometric calculation (sin, cos, tan, atan) is only done if the
610starting angle is not equal to the ending angle. The calculation of the
611pixels is done using simple arithmetic only and should perform not too
612bad even on devices without floating point processor. I didn't test this yet.
613
614Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
615For instance: an ellipse rotated 180 degrees is drawn
616slightly different from the original.
617
618The points are then moved to an array and used to draw a polyline and/or polygon
619(with center added, the pie).
620The result looks quite similar to the native ellipse, only e few pixels differ.
621
622The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
623slower as DrawEllipse(...), which calls the native API.
624An rotated ellipse outside the clipping region takes nearly the same time,
625while an native ellipse outside takes nearly no time to draw.
626
627If you draw an arc with this new method, you will see the starting and ending angles
628are calculated properly.
629If you use DrawEllipticArc(...), you will see they are only correct for circles
630and not properly calculated for ellipses.
631
632Peter Lenhard
633p.lenhard@t-online.de
634*/
635
636#ifdef __WXWINCE__
637void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
638 wxCoord w, wxCoord h,
639 double sa, double ea, double angle )
640{
641 wxList list;
642
643 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
644 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
645
646 // Add center (for polygon/pie)
647 list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) );
648
649 // copy list into array and delete list elements
650 int n = list.Number();
651 wxPoint *points = new wxPoint[n];
652 int i = 0;
653 wxNode* node = 0;
654 for ( node = list.First(); node; node = node->Next(), i++ )
655 {
656 wxPoint *point = (wxPoint *)node->Data();
657 points[i].x = point->x;
658 points[i].y = point->y;
659 delete point;
660 }
661
662 // first draw the pie without pen, if necessary
63b9e659 663 if( GetBrush() != *wxTRANSPARENT_BRUSH )
12bdd77c
JS
664 {
665 wxPen tempPen( GetPen() );
666 SetPen( *wxTRANSPARENT_PEN );
667 DoDrawPolygon( n, points, 0, 0 );
668 SetPen( tempPen );
669 }
670
671 // then draw the arc without brush, if necessary
63b9e659 672 if( GetPen() != *wxTRANSPARENT_PEN )
12bdd77c
JS
673 {
674 // without center
675 DoDrawLines( n-1, points, 0, 0 );
676 }
677
678 delete [] points;
679
680} // DrawEllipticArcRot
681
682void wxDCBase::Rotate( wxList* points, double angle, wxPoint center )
683{
684 if( angle != 0.0 )
685 {
686 double pi(3.1415926536);
687 double dSinA = -sin(angle*2.0*pi/360.0);
688 double dCosA = cos(angle*2.0*pi/360.0);
689 for ( wxNode* node = points->First(); node; node = node->Next() )
690 {
691 wxPoint* point = (wxPoint*)node->Data();
692
693 // transform coordinates, if necessary
694 if( center.x ) point->x -= center.x;
695 if( center.y ) point->y -= center.y;
696
697 // calculate rotation, rounding simply by implicit cast to integer
698 int xTemp = point->x * dCosA - point->y * dSinA;
699 point->y = point->x * dSinA + point->y * dCosA;
700 point->x = xTemp;
701
702 // back transform coordinates, if necessary
703 if( center.x ) point->x += center.x;
704 if( center.y ) point->y += center.y;
705 }
706 }
707}
708
709void wxDCBase::CalculateEllipticPoints( wxList* points,
710 wxCoord xStart, wxCoord yStart,
711 wxCoord w, wxCoord h,
712 double sa, double ea )
713{
714 double pi = 3.1415926535;
715 double sar = 0;
716 double ear = 0;
717 int xsa = 0;
718 int ysa = 0;
719 int xea = 0;
720 int yea = 0;
721 int sq = 0;
722 int eq = 0;
723 bool bUseAngles = false;
724 if( w<0 ) w = -w;
725 if( h<0 ) h = -h;
726 // half-axes
727 wxCoord a = w/2;
728 wxCoord b = h/2;
729 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
730 int decrX = 0;
731 if( 2*a == w ) decrX = 1;
732 int decrY = 0;
733 if( 2*b == h ) decrY = 1;
734 // center
735 wxCoord xCenter = xStart + a;
736 wxCoord yCenter = yStart + b;
737 // calculate data for start and end, if necessary
738 if( sa != ea )
739 {
740 bUseAngles = true;
741 // normalisation of angles
742 while( sa<0 ) sa += 360;
743 while( ea<0 ) ea += 360;
744 while( sa>=360 ) sa -= 360;
745 while( ea>=360 ) ea -= 360;
746 // calculate quadrant numbers
747 if( sa > 270 ) sq = 3;
748 else if( sa > 180 ) sq = 2;
749 else if( sa > 90 ) sq = 1;
750 if( ea > 270 ) eq = 3;
751 else if( ea > 180 ) eq = 2;
752 else if( ea > 90 ) eq = 1;
753 sar = sa * pi / 180.0;
754 ear = ea * pi / 180.0;
755 // correct angle circle -> ellipse
756 sar = atan( -a/(double)b * tan( sar ) );
757 if ( sq == 1 || sq == 2 ) sar += pi;
758 ear = atan( -a/(double)b * tan( ear ) );
759 if ( eq == 1 || eq == 2 ) ear += pi;
760 // coordinates of points
761 xsa = xCenter + a * cos( sar );
762 if( sq == 0 || sq == 3 ) xsa -= decrX;
763 ysa = yCenter + b * sin( sar );
764 if( sq == 2 || sq == 3 ) ysa -= decrY;
765 xea = xCenter + a * cos( ear );
766 if( eq == 0 || eq == 3 ) xea -= decrX;
767 yea = yCenter + b * sin( ear );
768 if( eq == 2 || eq == 3 ) yea -= decrY;
769 } // if iUseAngles
770 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
771 double c1 = b * b;
772 double c2 = 2.0 / w;
773 c2 *= c2;
774 c2 *= c1;
775 wxCoord x = 0;
776 wxCoord y = b;
777 long x2 = 1;
778 long y2 = y*y;
779 long y2_old = 0;
780 long y_old = 0;
781 // Lists for quadrant 1 to 4
782 wxList pointsarray[4];
783 // Calculate points for first quadrant and set in all quadrants
784 for( x = 0; x <= a; ++x )
785 {
786 x2 = x2+x+x-1;
787 y2_old = y2;
788 y_old = y;
789 bool bNewPoint = false;
790 while( y2 > c1 - c2 * x2 && y > 0 )
791 {
792 bNewPoint = true;
793 y2 = y2-y-y+1;
794 --y;
795 }
796 // old y now to big: set point with old y, old x
797 if( bNewPoint && x>1)
798 {
799 int x1 = x - 1;
800 // remove points on the same line
801 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
802 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) );
803 pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
804 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
805 } // set point
806 } // calculate point
807
808 // Starting and/or ending points for the quadrants, first quadrant gets both.
809 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
810 pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) );
811 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) );
812 pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) );
813 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
814
815 // copy quadrants in original list
816 if( bUseAngles )
817 {
818 // Copy the right part of the points in the lists
819 // and delete the wxPoints, because they do not leave this method.
820 points->Append( (wxObject*) new wxPoint( xsa, ysa ) );
821 int q = sq;
822 bool bStarted = false;
823 bool bReady = false;
824 bool bForceTurn = ( sq == eq && sa > ea );
825 while( !bReady )
826 {
827 for( wxNode *node = pointsarray[q].First(); node; node = node->Next() )
828 {
829 // once: go to starting point in start quadrant
830 if( !bStarted &&
831 (
832 ( (wxPoint*) node->Data() )->x < xsa+1 && q <= 1
833 ||
834 ( (wxPoint*) node->Data() )->x > xsa-1 && q >= 2
835 )
836 )
837 {
838 bStarted = true;
839 }
840
841 // copy point, if not at ending point
842 if( bStarted )
843 {
844 if( q != eq || bForceTurn
845 ||
846 ( (wxPoint*) node->Data() )->x > xea+1 && q <= 1
847 ||
848 ( (wxPoint*) node->Data() )->x < xea-1 && q >= 2
849 )
850 {
851 // copy point
852 wxPoint* pPoint = new wxPoint( *((wxPoint*) node->Data() ) );
853 points->Append( (wxObject*) pPoint );
854 }
855 else if( q == eq && !bForceTurn || ( (wxPoint*) node->Data() )->x == xea)
856 {
857 bReady = true;
858 }
859 }
860 } // for node
861 ++q;
862 if( q > 3 ) q = 0;
863 bForceTurn = false;
864 bStarted = true;
865 } // while not bReady
866 points->Append( (wxObject*) new wxPoint( xea, yea ) );
867
868 // delete points
869 for( q = 0; q < 4; ++q )
870 {
871 for( wxNode *node = pointsarray[q].First(); node; node = node->Next() )
872 {
873 wxPoint *p = (wxPoint *)node->Data();
874 delete p;
875 }
876 }
877
878 }
879 else
880 {
881 // copy whole ellipse, wxPoints will be deleted outside
882 for( wxNode *node = pointsarray[0].First(); node; node = node->Next() )
883 {
884 wxObject *p = node->Data();
885 points->Append( p );
886 }
887 for( node = pointsarray[1].First(); node; node = node->Next() )
888 {
889 wxObject *p = node->Data();
890 points->Append( p );
891 }
892 for( node = pointsarray[2].First(); node; node = node->Next() )
893 {
894 wxObject *p = node->Data();
895 points->Append( p );
896 }
897 for( node = pointsarray[3].First(); node; node = node->Next() )
898 {
899 wxObject *p = node->Data();
900 points->Append( p );
901 }
902 } // not iUseAngles
903} // CalculateEllipticPoints
904
905#endif
906