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