1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        plotdraw.cpp
3 // Purpose:     wxPlotDrawer and friends
4 // Author:      John Labenski
5 // Modified by:
6 // Created:     8/27/2002
7 // Copyright:   (c) John Labenski
8 // Licence:     wxWindows license
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #ifdef __BORLANDC__
15     #pragma hdrstop
16 #endif
17 
18 #ifndef WX_PRECOMP
19     #include "wx/dcmemory.h"
20 #endif // WX_PRECOMP
21 
22 #include "wx/math.h"
23 
24 #include "wx/plotctrl/plotctrl.h"
25 #include "wx/plotctrl/plotdraw.h"
26 #include "wx/plotctrl/plotmark.h"
27 
28 #include <cmath>
29 #include <cfloat>
30 #include <climits>
31 
32 // MSVC hogs global namespace with these min/max macros - remove them
33 #ifdef max
34     #undef max
35 #endif
36 #ifdef min
37     #undef min
38 #endif
39 #ifdef GetYValue   // Visual Studio 7 defines this
40     #undef GetYValue
41 #endif
42 
43 #ifdef wxFinite
44 #undef wxFinite
45 #define wxFinite(x) std::isfinite(x)
46 #endif  // wxFinite
47 
48 #define LONG_TO_WXCOLOUR(c) wxColour((unsigned char)((c>>16)&0xFF), (unsigned char)((c>>8 )&0xFF), (unsigned char)((c)&0xFF))
49 #define WXCOLOUR_TO_LONG(c) ((c.Red()<<16)|(c.Green()<<8)|(c.Blue()))
50 
51 #define RINT(x) int((x) >= 0 ? ((x) + 0.5) : ((x) - 0.5))
52 
53 #if !wxCHECK_VERSION(2,5,0)
WXRECT2DDOUBLE_EQUAL(const wxRect2DDouble & r1,const wxRect2DDouble & r2)54     bool WXRECT2DDOUBLE_EQUAL(const wxRect2DDouble& r1, const wxRect2DDouble& r2)
55     {
56         return (r1.m_x == r1.m_x) && (r1.m_y == r1.m_y) &&
57                (r1.m_width == r1.m_width) && (r1.m_height == r1.m_height);
58     }
59 #else
60     #define WXRECT2DDOUBLE_EQUAL(r1, r2) ((r1) == (r2))
61 #endif // wxCHECK_VERSION(2,5,0)
62 
63 //-----------------------------------------------------------------------------
64 // Consts
65 //-----------------------------------------------------------------------------
66 
67 // Skip the wxWidgets drawing routines since they calc an unnecessary bounding rect
68 // You may turn this off by defining wxPLOT_FAST_GRAPHICS=0 to the compilier
69 #ifndef wxPLOT_FAST_GRAPHICS
70     #define wxPLOT_FAST_GRAPHICS 0
71 #endif // wxPLOT_FAST_GRAPHICS
72 
73 #if defined(__WXGTK__) && wxPLOT_FAST_GRAPHICS
74 
75 extern "C" {
76     #include <gdk/gdk.h>
77 }
78     #define INITIALIZE_FAST_GRAPHICS \
79         double dc_scale_x = 1, dc_scale_y = 1; \
80         dc->GetUserScale( &dc_scale_x, &dc_scale_y ); \
81         wxPoint dc_origin = dc->GetDeviceOrigin(); \
82         wxWindowDC *winDC = wxDynamicCast(dc, wxWindowDC); \
83         GdkWindow *window = NULL; \
84         GdkGC     *pen = NULL; \
85         if (winDC && (dc_scale_x == 1.0) && (dc_scale_y == 1.0) && (dc_origin == wxPoint(0,0))) \
86         { \
87             window = winDC->m_window; \
88             pen = winDC->m_penGC; \
89         }
90 
91     // inline void wxPLOT_DRAW_LINE(wxDC *dc, GdkWindow *win, GdkGC *pen, int x0, int y0, int x1, int y1)
92     #define wxPLOT_DRAW_LINE(dc, win, pen, x0, y0, x1, y1) \
93         if (win && pen) \
94             gdk_draw_line( win, pen, x0, y0, x1, y1 ); \
95         else \
96             dc->DrawLine( x0, y0, x1, y1 );
97 
98     // note : need to draw outline since the filled part isn't really a circle
99     //        gdk_draw_arc( win, pen, false, x0-2, y0-2, 4, 4, 0, 360*64 ); // false for outline, true for inside
100     //inline void wxPLOT_DRAW_CIRCLE(wxDC *dc, GdkWindow *win, GdkGC *pen, int x0, int y0)
101     #define wxPLOT_DRAW_ELLIPSE(dc, win, pen, x0, y0, w, h) \
102         if (win && pen) \
103             gdk_draw_arc( win, pen, false, (x0)-(w), (y0)-(h), (w)*2, (h)*2, 0, 360*64 );  \
104         else \
105             dc->DrawEllipse(x0, y0, w, h);
106 
107 #elif defined(__WXMSW__) && wxPLOT_FAST_GRAPHICS
108 
109     #define INITIALIZE_FAST_GRAPHICS \
110         double dc_scale_x = 1, dc_scale_y = 1; \
111         dc->GetUserScale( &dc_scale_x, &dc_scale_y ); \
112         wxPoint dc_origin = dc->GetDeviceOrigin(); \
113         HDC window = 0; \
114         if ((dc_scale_x == 1.0) && (dc_scale_y == 1.0) && (dc_origin == wxPoint(0,0))) \
115             window = (HDC)dc->GetHDC(); \
116         int pen = 0; pen = 0;  // no unused var warning
117 
118     //inline void wxPLOT_DRAW_LINE(wxDC *dc, HDC win, int pen, int x0, int y0, int x1, int y1)
119     #define wxPLOT_DRAW_LINE(dc, win, pen, x0, y0, x1, y1) \
120         if (win) \
121         { \
122             (void)MoveToEx(win, x0, y0, NULL);  \
123             (void)LineTo(win, x1, y1); \
124         } \
125         else \
126             dc->DrawLine( x0, y0, x1, y1 );
127 
128     //inline void wxPLOT_DRAW_CIRCLE(wxDC *dc, HDC win, int pen, int x0, int y0)
129     #define wxPLOT_DRAW_ELLIPSE(dc, win, pen, x0, y0, w, h) \
130         if (win) \
131             (void)Ellipse(win, (x0)-(w), (y0)-(w), (x0)+(w)*2, (y0)+(h)*2); \
132         else \
133             dc->DrawEllipse(x0, y0, w, h);
134 
135 #else // !wxPLOT_FAST_GRAPHICS or not gtk/msw
136 
137     #define INITIALIZE_FAST_GRAPHICS \
138         int window = 0; window = 0; \
139         int pen = 0; pen = 0;
140 
141     //inline void wxPLOT_DRAW_LINE(wxDC *dc, int win, int pen, int x0, int y0, int x1, int y1)
142     #define wxPLOT_DRAW_LINE(dc, win, pen, x0, y0, x1, y1) \
143         dc->DrawLine( x0, y0, x1, y1 );
144 
145     //inline void wxPLOT_DRAW_CIRCLE(wxDC *dc, int win, int pen, int x0, int y0)
146     #define wxPLOT_DRAW_ELLIPSE(dc, win, pen, x0, y0, w, h) \
147         dc->DrawEllipse(x0, y0, w, h);
148 
149 #endif // wxPLOT_FAST_GRAPHICS
150 
151 
152 // differs from wxRect2DDouble::Intersects by allowing for 0 width or height
wxPlotRect2DDoubleIntersects(const wxRect2DDouble & a,const wxRect2DDouble & b)153 inline bool wxPlotRect2DDoubleIntersects(const wxRect2DDouble &a, const wxRect2DDouble &b)
154 {
155     return (wxMax(a.m_x, b.m_x) <= wxMin(a.GetRight(), b.GetRight())) &&
156            (wxMax(a.m_y, b.m_y) <= wxMin(a.GetBottom(), b.GetBottom()));
157 }
158 
159 // same as wxPlotRect2DDouble::Contains, but doesn't convert to wxPoint2DDouble
wxPlotRect2DDoubleContains(double x,double y,const wxRect2DDouble & rect)160 inline bool wxPlotRect2DDoubleContains(double x, double y, const wxRect2DDouble &rect)
161 {
162     return ((x>=rect.m_x) && (y>=rect.m_y) && (x<=rect.GetRight()) && (y<=rect.GetBottom()));
163 }
164 
165 // differs from wxRect2DDouble::GetOutCode by swaping top and bottom for plot origin
166 //inline wxOutCode wxPlotRect2DDoubleOutCode( double x, double y, const wxRect2DDouble &rect )
167 //{
168 //    return wxOutCode((x < rect.m_x         ? wxOutLeft   :
169 //                     (x > rect.GetRight()  ? wxOutRight  : wxInside )) +
170 //                     (y < rect.m_y         ? wxOutTop    :
171 //                     (y > rect.GetBottom() ? wxOutBottom : wxInside )) );
172 //}
173 #define wxPlotRect2DDoubleOutCode( x, y, rect ) \
174            wxOutCode(((x) < rect.m_x         ? wxOutLeft   : \
175                      ((x) > rect.GetRight()  ? wxOutRight  : wxInside )) + \
176                      ((y) < rect.m_y         ? wxOutTop    : \
177                      ((y) > rect.GetBottom() ? wxOutBottom : wxInside )) )
178 
179 
180 // modified Cohen-Sutherland Algorithm for line clipping in at most two passes
181 //   the the original endless loop is too unstable
182 //   http://www.cc.gatech.edu/grads/h/Hao-wei.Hsieh/Haowei.Hsieh/code1.html for psuedo code
183 // The line connecting (x0,y0)-(x1,y1) is clipped to rect and which
184 //   points were clipped is returned.
185 
186 enum ClipLine_Type
187 {
188     ClippedNeither = 0x0000,
189     ClippedFirstX  = 0x0001,
190     ClippedFirstY  = 0x0002,
191     ClippedFirst   = ClippedFirstX | ClippedFirstY,
192     ClippedSecondX = 0x0010,
193     ClippedSecondY = 0x0020,
194     ClippedSecond  = ClippedSecondX | ClippedSecondY,
195     ClippedBoth    = ClippedFirst | ClippedSecond,
196     ClippedOut     = 0x0100   // no intersection, so can't clip
197 };
198 
ClipLineToRect(double & x0,double & y0,double & x1,double & y1,const wxRect2DDouble & rect)199 int ClipLineToRect( double &x0, double &y0,
200                     double &x1, double &y1,
201                     const wxRect2DDouble &rect )
202 {
203     if (!wxFinite(x0) || !wxFinite(y0) ||
204         !wxFinite(x1) || !wxFinite(y1)) return ClippedOut;
205 
206     wxOutCode out0 = wxPlotRect2DDoubleOutCode( x0, y0, rect );
207     wxOutCode out1 = wxPlotRect2DDoubleOutCode( x1, y1, rect );
208 
209     if ((out0 & out1) != wxInside) return ClippedOut;     // both outside on same side
210     if ((out0 | out1) == wxInside) return ClippedNeither; // both inside
211 
212     int ret = ClippedNeither;
213 
214     if (x0 == x1) // vertical line
215     {
216         if      (out0 & wxOutTop)    {y0 = rect.GetTop();    ret |= ClippedFirstY;}
217         else if (out0 & wxOutBottom) {y0 = rect.GetBottom(); ret |= ClippedFirstY;}
218         if      (out1 & wxOutTop)    {y1 = rect.GetTop();    ret |= ClippedSecondY;}
219         else if (out1 & wxOutBottom) {y1 = rect.GetBottom(); ret |= ClippedSecondY;}
220         return ret;
221     }
222     if (y0 == y1) // horiz line
223     {
224         if      (out0 & wxOutLeft)  {x0 = rect.GetLeft();  ret |= ClippedFirstX;}
225         else if (out0 & wxOutRight) {x0 = rect.GetRight(); ret |= ClippedFirstX;}
226         if      (out1 & wxOutLeft)  {x1 = rect.GetLeft();  ret |= ClippedSecondX;}
227         else if (out1 & wxOutRight) {x1 = rect.GetRight(); ret |= ClippedSecondX;}
228         return ret;
229     }
230 
231     double x = x0, y = y0;
232     wxOutCode out = out0;
233     int points_out = 2;
234     bool out0_outside = true;
235     if (out0 == wxInside)
236     {
237         out0_outside = false;
238         points_out = 1;
239         out = out1;
240     }
241     else if (out1 == wxInside)
242         points_out = 1;
243 
244     for (int i=0; i<points_out; i++)
245     {
246         if (out & wxOutTop)
247         {
248             y = rect.GetTop();
249             x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
250             out = wxPlotRect2DDoubleOutCode( x, y, rect );
251         }
252         else if (out & wxOutBottom)
253         {
254             y = rect.GetBottom();
255             x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
256             out = wxPlotRect2DDoubleOutCode( x, y, rect );
257         }
258         // check left and right
259         if (out & wxOutRight)
260         {
261             x = rect.GetRight();
262             y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
263             out = wxPlotRect2DDoubleOutCode( x, y, rect );
264         }
265         else if (out & wxOutLeft)
266         {
267             x = rect.GetLeft();
268             y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
269             out = wxPlotRect2DDoubleOutCode( x, y, rect );
270         }
271         // check top and bottom again
272         if (out & wxOutTop)
273         {
274             y = rect.GetTop();
275             x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
276             out = wxPlotRect2DDoubleOutCode( x, y, rect );
277         }
278         else if (out & wxOutBottom)
279         {
280             y = rect.GetBottom();
281             x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
282             out = wxPlotRect2DDoubleOutCode( x, y, rect );
283         }
284 
285         if (!wxFinite(x) || !wxFinite(y)) return ClippedOut;
286 
287         if ((i == 0) && out0_outside)
288         {
289             x0 = x;
290             y0 = y;
291             ret |= ClippedFirst;
292             out = out1;
293         }
294         else
295         {
296             x1 = x;
297             y1 = y;
298             ret |= ClippedSecond;
299             return ret;
300         }
301     }
302 
303     return ret;
304 }
305 
306 // ----------------------------------------------------------------------------
307 // wxWindows spline drawing code see dcbase.cpp - inlined
308 //
309 // usage - Create a SplineDrawer, Create(...), DrawSpline(x,y), EndSpline()
310 // ----------------------------------------------------------------------------
311 
312 #define SPLINE_STACK_DEPTH 20
313 #define THRESHOLD           4 // number of pixels between spline points
314 
315 #define SPLINE_PUSH(x1_, y1_, x2_, y2_, x3_, y3_, x4_, y4_) \
316     stack_top->x1 = x1_; stack_top->y1 = y1_; \
317     stack_top->x2 = x2_; stack_top->y2 = y2_; \
318     stack_top->x3 = x3_; stack_top->y3 = y3_; \
319     stack_top->x4 = x4_; stack_top->y4 = y4_; \
320     stack_top++; \
321     m_stack_count++;
322 
323 #define SPLINE_POP(x1_, y1_, x2_, y2_, x3_, y3_, x4_, y4_) \
324     stack_top--; \
325     m_stack_count--; \
326     x1_ = stack_top->x1; y1_ = stack_top->y1; \
327     x2_ = stack_top->x2; y2_ = stack_top->y2; \
328     x3_ = stack_top->x3; y3_ = stack_top->y3; \
329     x4_ = stack_top->x4; y4_ = stack_top->y4;
330 
331 class SplineDrawer
332 {
333 public:
SplineDrawer()334     SplineDrawer() : m_dc(NULL) { }
335     // the wxRect2DDouble rect is the allowed dc area in pixel coords
336     // wxRangeDoubleSelection is the ranges to use selPen, also in pixel coords
337     // x1_, y1_, x2_, y2_ are the first 2 points to draw
Create(wxDC * dc,const wxPen & curPen,const wxPen & selPen,const wxRect2DDouble & rect,wxRangeDoubleSelection * rangeSel,double x1_,double y1_,double x2_,double y2_)338     void Create(wxDC *dc, const wxPen &curPen, const wxPen &selPen,
339                 const wxRect2DDouble &rect, wxRangeDoubleSelection *rangeSel,
340                 double x1_, double y1_, double x2_, double y2_)
341     {
342         m_dc = dc;
343         wxCHECK_RET( dc, wxT("invalid window dc") );
344 
345         m_selPen   = selPen;
346         m_curPen   = curPen;
347         m_rangeSel = rangeSel;
348 
349         m_rect = rect;
350 
351         m_stack_count = 0;
352 
353         m_x1 = x1_;
354         m_y1 = y1_;
355         m_x2 = x2_;
356         m_y2 = y2_;
357         m_cx1 = (m_x1  + m_x2) / 2.0;
358         m_cy1 = (m_y1  + m_y2) / 2.0;
359         m_cx2 = (m_cx1 + m_x2) / 2.0;
360         m_cy2 = (m_cy1 + m_y2) / 2.0;
361 
362         m_last_x = m_x1;
363         m_last_y = m_y1;
364     }
365 
366     // actually do the drawing here
367     void DrawSpline(double x, double y);
368 
369     // After the last point call this to finish the drawing
EndSpline()370     void EndSpline()
371     {
372         wxCHECK_RET( m_dc, wxT("invalid window dc") );
373         if (ClipLineToRect(m_cx1, m_cy1, m_x2, m_y2, m_rect) != ClippedOut)
374             m_dc->DrawLine((int)m_cx1, (int)m_cy1, (int)m_x2, (int)m_y2);
375     }
376 
377 private:
378 
379     typedef struct SplineStack
380     {
381         double x1, y1, x2, y2, x3, y3, x4, y4;
382     } SplineStack;
383 
384     wxDC *m_dc;
385     wxRect2DDouble m_rect;
386 
387     SplineStack m_splineStack[SPLINE_STACK_DEPTH];
388     int m_stack_count;
389 
390     double m_cx1, m_cy1, m_cx2, m_cy2, m_cx3, m_cy3, m_cx4, m_cy4;
391     double m_x1, m_y1, m_x2, m_y2;
392     double m_last_x, m_last_y;
393 
394     wxPen m_selPen, m_curPen;
395     wxRangeDoubleSelection *m_rangeSel;
396 };
397 
DrawSpline(double x,double y)398 void SplineDrawer::DrawSpline( double x, double y )
399 {
400     wxCHECK_RET( m_dc, wxT("invalid window dc") );
401     wxPen oldPen = m_dc->GetPen();
402 
403     bool is_selected = (oldPen == m_selPen);
404 
405     m_x1 = m_x2;
406     m_y1 = m_y2;
407     m_x2 = x;
408     m_y2 = y;
409     m_cx4 = (m_x1 + m_x2) / 2.0;
410     m_cy4 = (m_y1 + m_y2) / 2.0;
411     m_cx3 = (m_x1 + m_cx4) / 2.0;
412     m_cy3 = (m_y1 + m_cy4) / 2.0;
413 
414     double xmid, ymid;
415     double xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4;
416 
417     SplineStack *stack_top = m_splineStack;
418     m_stack_count = 0;
419 
420     SPLINE_PUSH(m_cx1, m_cy1, m_cx2, m_cy2, m_cx3, m_cy3, m_cx4, m_cy4);
421 
422     while (m_stack_count > 0)
423     {
424         SPLINE_POP(xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4);
425 
426         xmid = (xx2 + xx3)/2.0;
427         ymid = (yy2 + yy3)/2.0;
428         if ((fabs(xx1 - xmid) < THRESHOLD) && (fabs(yy1 - ymid) < THRESHOLD) &&
429             (fabs(xmid - xx4) < THRESHOLD) && (fabs(ymid - yy4) < THRESHOLD))
430         {
431             // FIXME - is this really necessary, better safe than sorry?
432             double t1_last_x = m_last_x;
433             double t1_last_y = m_last_y;
434             double t1_xx1    = xx1;
435             double t1_yy1    = yy1;
436             if (ClipLineToRect(t1_last_x, t1_last_y, t1_xx1, t1_yy1, m_rect) != ClippedOut)
437             {
438                 if (m_rangeSel && (m_rangeSel->Contains((m_last_x + xx1)/2) != is_selected))
439                 {
440                     is_selected = is_selected ? false : true;
441                     if (is_selected)
442                         m_dc->SetPen(m_selPen);
443                     else
444                         m_dc->SetPen(m_curPen);
445                 }
446 
447                 m_dc->DrawLine((int)t1_last_x, (int)t1_last_y, (int)t1_xx1, (int)t1_yy1);
448             }
449 
450             double t2_xx1  = xx1;
451             double t2_yy1  = yy1;
452             double t2_xmid = xmid;
453             double t2_ymid = ymid;
454             if (ClipLineToRect(t2_xx1, t2_yy1, t2_xmid, t2_ymid, m_rect) != ClippedOut)
455             {
456                 if (m_rangeSel && (m_rangeSel->Contains((xx1+xmid)/2) != is_selected))
457                 {
458                     is_selected = is_selected ? false : true;
459                     if (is_selected)
460                         m_dc->SetPen(m_selPen);
461                     else
462                         m_dc->SetPen(m_curPen);
463                 }
464 
465                 m_dc->DrawLine((int)t2_xx1, (int)t2_yy1, (int)t2_xmid, (int)t2_ymid);
466             }
467 
468             m_last_x = xmid;
469             m_last_y = ymid;
470         }
471         else
472         {
473             wxCHECK_RET(m_stack_count < SPLINE_STACK_DEPTH - 2, wxT("Spline stack overflow"));
474             SPLINE_PUSH(xmid, ymid, (xmid + xx3)/2.0, (ymid + yy3)/2.0,
475                         (xx3 + xx4)/2.0, (yy3 + yy4)/2.0, xx4, yy4);
476             SPLINE_PUSH(xx1, yy1, (xx1 + xx2)/2.0, (yy1 + yy2)/2.0,
477                         (xx2 + xmid)/2.0, (yy2 + ymid)/2.0, xmid, ymid);
478         }
479     }
480 
481     m_cx1 = m_cx4;
482     m_cy1 = m_cy4;
483     m_cx2 = (m_cx1 + m_x2) / 2.0;
484     m_cy2 = (m_cy1 + m_y2) / 2.0;
485 
486     m_dc->SetPen(oldPen);
487 }
488 
489 //***************************************************************************
490 
491 
492 //-----------------------------------------------------------------------------
493 // wxPlotDrawerAxisBase
494 //-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerBase,wxObject)495 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerBase, wxObject)
496 
497 wxPlotDrawerAxisBase::wxPlotDrawerAxisBase(wxPlotCtrl* owner)
498                      :wxPlotDrawerBase(owner)
499 {
500     m_tickFont    = *wxNORMAL_FONT;
501     m_labelFont   = *wxSWISS_FONT;
502     m_tickColour  = wxGenericColour(0,0,0);
503     m_labelColour = wxGenericColour(0,0,0);
504 
505     m_tickPen         = wxGenericPen(m_tickColour, wxSOLID);
506     m_backgroundBrush = wxGenericBrush(wxGenericColour(255,255,255), wxSOLID);
507 }
508 
509 //-----------------------------------------------------------------------------
510 // wxPlotDrawerArea
511 //-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerArea,wxPlotDrawerBase)512 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerArea, wxPlotDrawerBase)
513 
514 void wxPlotDrawerArea::Draw(wxDC *dc, bool refresh)
515 {
516 }
517 
518 //-----------------------------------------------------------------------------
519 // wxPlotDrawerAxisBase
520 //-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerAxisBase,wxPlotDrawerBase)521 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerAxisBase, wxPlotDrawerBase)
522 
523 //-----------------------------------------------------------------------------
524 // wxPlotDrawerXAxis
525 //-----------------------------------------------------------------------------
526 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerXAxis, wxPlotDrawerAxisBase)
527 
528 void wxPlotDrawerXAxis::Draw(wxDC *dc, bool refresh)
529 {
530     wxCHECK_RET(dc, wxT("Invalid dc"));
531 
532     wxRect dcRect(GetDCRect());
533 
534     // Draw background
535     if (refresh)
536     {
537         dc->SetBrush(m_backgroundBrush.GetBrush());
538         dc->SetPen(*wxTRANSPARENT_PEN);
539         dc->DrawRectangle(dcRect);
540     }
541 
542     wxFont tickFont = m_tickFont;
543     if (m_font_scale != 1)
544         tickFont.SetPointSize( wxMax(2, RINT(tickFont.GetPointSize() * m_font_scale)) );
545 
546     wxPoint dcOrigin(dc->GetDeviceOrigin());
547     dc->SetDeviceOrigin(dcRect.x, dcRect.y);
548     dc->SetTextForeground( m_tickColour.GetColour() );
549     dc->SetFont( tickFont );
550 
551     wxString label;
552 
553     // center the text in the window
554     int x, y;
555     dc->GetTextExtent(wxT("5"), &x, &y);
556     int y_pos = (GetDCRect().height - y)/2 + 2; // FIXME I want to center this
557 //    double current = ceil(m_viewRect.GetLeft() / m_xAxisTick_step) * m_xAxisTick_step;
558     int i, count = m_tickPositions.GetCount();
559     for (i=0; i<count; i++)
560     {
561         dc->DrawText(m_tickLabels[i], m_tickPositions[i], y_pos);
562 
563 //        if (!IsFinite(current, wxT("axis label is not finite")))
564 //            break;
565 //        label.Printf( m_xAxisTickFormat.c_str(), current );
566 //        dc->DrawText(label, m_xAxisTicks[i], y_pos);
567 //        current += m_xAxisTick_step;
568     }
569 
570 #ifdef DRAW_BORDERS
571     // Test code for sizing to show the extent of the axes
572     dc->SetBrush( *wxTRANSPARENT_BRUSH );
573     dc->SetPen( wxPen(GetBorderColour(), 1, wxSOLID) );
574     dc->DrawRectangle(wxRect(wxPoint(0,0), clientSize));
575 #endif // DRAW_BORDERS
576 
577     dc->SetDeviceOrigin(dcOrigin.x, dcOrigin.y);
578 }
579 
580 //-----------------------------------------------------------------------------
581 // wxPlotDrawerYAxis
582 //-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerYAxis,wxPlotDrawerAxisBase)583 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerYAxis, wxPlotDrawerAxisBase)
584 
585 void wxPlotDrawerYAxis::Draw(wxDC *dc, bool refresh)
586 {
587     wxCHECK_RET(dc, wxT("Invalid dc"));
588 
589     wxRect dcRect(GetDCRect());
590 
591     // Draw background
592     if (refresh)
593     {
594         dc->SetBrush(m_backgroundBrush.GetBrush());
595         dc->SetPen(*wxTRANSPARENT_PEN);
596         dc->DrawRectangle(dcRect);
597     }
598 
599     wxFont tickFont = m_tickFont;
600     if (m_font_scale != 1)
601         tickFont.SetPointSize( wxMax(2, RINT(tickFont.GetPointSize() * m_font_scale)) );
602 
603     wxPoint dcOrigin(dc->GetDeviceOrigin());
604     dc->SetDeviceOrigin(dcRect.x, dcRect.y);
605     dc->SetTextForeground( m_tickColour.GetColour() );
606     dc->SetFont( tickFont );
607 
608     wxString label;
609 
610 //    double current = ceil(m_viewRect.GetTop() / m_yAxisTick_step) * m_yAxisTick_step;
611     int i, count = m_tickLabels.GetCount();
612     for (i=0; i<count; i++)
613     {
614         dc->DrawText( m_tickLabels[i], 2, m_tickPositions[i] );
615 
616 //        if (!IsFinite(current, wxT("axis label is not finite")))
617 //            break;
618 //        label.Printf( m_yAxisTickFormat.c_str(), current);
619 //        dc->DrawText( label, 2, m_yAxisTicks[i] );
620 //        current += m_yAxisTick_step;
621     }
622 
623 #ifdef DRAW_BORDERS
624     // Test code for sizing to show the extent of the axes
625     dc->SetBrush( *wxTRANSPARENT_BRUSH );
626     dc->SetPen( wxPen(GetBorderColour(), 1, wxSOLID) );
627     dc->DrawRectangle(wxRect(wxPoint(0,0), clientSize));
628 #endif // DRAW_BORDERS
629 
630     dc->SetDeviceOrigin(dcOrigin.x, dcOrigin.y);
631 }
632 
633 //-----------------------------------------------------------------------------
634 // wxPlotDrawerKey
635 //-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerKey,wxPlotDrawerBase)636 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerKey, wxPlotDrawerBase)
637 
638 wxPlotDrawerKey::wxPlotDrawerKey(wxPlotCtrl* owner)
639                 :wxPlotDrawerBase(owner)
640 {
641     m_font = *wxNORMAL_FONT;
642     m_fontColour = wxGenericColour(0, 0, 0);
643     m_keyPosition = wxPoint(100, 100);
644     m_border = 5;
645     m_key_inside = true;
646     m_key_line_width = 20;
647     m_key_line_margin = 5;
648 }
649 
Draw(wxDC * dc,const wxString & keyString_)650 void wxPlotDrawerKey::Draw(wxDC *dc, const wxString& keyString_)
651 {
652     wxCHECK_RET(dc && m_owner, wxT("Invalid dc"));
653 
654     if (keyString_.IsEmpty())
655         return;
656 
657     wxString keyString = keyString_;
658 
659 /*
660     // GTK - kills X if font size is too small
661     double x_scale = 1, y_scale = 1;
662     dc->GetUserScale( &x_scale, &y_scale );
663 
664     wxFont font = m_owner->GetKeyFont();
665     if (0 && x_scale != 1)
666     {
667         font.SetPointSize(wxMax(int(font.GetPointSize()/x_scale), 4));
668         if (!font.Ok())
669             font = GetKeyFont();
670     }
671 */
672 
673     wxFont keyFont = m_font;
674     if (m_font_scale != 1)
675         keyFont.SetPointSize( wxMax(2, RINT(keyFont.GetPointSize() * m_font_scale)) );
676 
677     int key_line_width  = RINT(m_key_line_width  * m_pen_scale);
678     int key_line_margin = RINT(m_key_line_margin * m_pen_scale);
679 
680     dc->SetFont(keyFont);
681     dc->SetTextForeground(m_fontColour.GetColour());
682 
683     wxRect keyRect;
684     int heightLine = 0;
685 
686     dc->GetMultiLineTextExtent(keyString, &keyRect.width, &keyRect.height, &heightLine);
687 
688     wxRect dcRect(GetDCRect());
689     wxSize areaSize = dcRect.GetSize();
690 
691     keyRect.x = 30 + int((m_keyPosition.x*.01)*areaSize.x);
692     keyRect.y = areaSize.y - int((m_keyPosition.y*.01)*areaSize.y);
693 
694     if (m_key_inside)
695     {
696         keyRect.x = wxMax(30, keyRect.x);
697         keyRect.x = wxMin(areaSize.x - keyRect.width - m_border, keyRect.GetRight());
698 
699         keyRect.y = wxMax(m_border, keyRect.y);
700         keyRect.y = wxMin(areaSize.y - keyRect.height - m_border, keyRect.y);
701     }
702 
703     int h = keyRect.y;
704     int i = 0;
705 
706     while (!keyString.IsEmpty())
707     {
708         wxString subkey = keyString.BeforeFirst(wxT('\n')).Strip(wxString::both);
709         keyString = keyString.AfterFirst(wxT('\n'));
710         if (subkey.IsEmpty()) break;
711 
712         if (m_owner && m_owner->GetCurve(i))
713         {
714             wxPen keyPen = m_owner->GetCurve(i)->GetPen(wxPLOTPEN_NORMAL).GetPen();
715             if (m_pen_scale != 1)
716                 keyPen.SetWidth(int(keyPen.GetWidth() * m_pen_scale));
717 
718             if(keyPen.GetWidth() < 3) keyPen.SetWidth(3);
719             dc->SetPen(keyPen);
720             dc->DrawLine(keyRect.x - (key_line_width + key_line_margin), h + heightLine/2,
721                         keyRect.x - key_line_margin, h + heightLine/2);
722         }
723 
724         dc->DrawText(subkey, keyRect.x, h);
725 
726         h += heightLine;
727         i++;
728     }
729 
730     dc->SetPen(wxNullPen);
731     dc->SetFont(wxNullFont);
732 }
733 
734 //-----------------------------------------------------------------------------
735 // wxPlotDrawerCurve
736 //-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerCurve,wxPlotDrawerBase)737 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerCurve, wxPlotDrawerBase)
738 
739 void wxPlotDrawerCurve::Draw(wxDC *dc, wxPlotCurve *curve, int curve_index)
740 {
741     wxCHECK_RET(dc && m_owner && curve && curve->Ok(), wxT("invalid curve"));
742     INITIALIZE_FAST_GRAPHICS
743 
744     wxRect dcRect(GetDCRect());
745 
746     int i, j0, j1;
747     double x0, y0, x1, y1, yy0, yy1;
748     x0 = m_owner->GetPlotCoordFromClientX(0);
749     y0 = yy0 = curve->GetY(x0);
750 
751     //wxRect2DDouble viewRect = m_viewRect;
752     wxRect2DDouble subViewRect = m_owner->GetPlotRectFromClientRect( dcRect );
753     //printf("curve rect %d %d %d %d\n", rect.x, rect.y, rect.width, rect.height); fflush(stdout);
754     //printf("curve subviewrect %lf %lf %lf %lf\n", subViewRect.m_x, subViewRect.m_y, subViewRect.m_width, subViewRect.m_height); fflush(stdout);
755 
756     int right = dcRect.GetRight();
757 
758     wxPen currentPen = (curve_index == m_owner->GetActiveIndex()) ? curve->GetPen(wxPLOTPEN_ACTIVE).GetPen()
759                                                                   : curve->GetPen(wxPLOTPEN_NORMAL).GetPen();
760     wxPen selectedPen = curve->GetPen(wxPLOTPEN_SELECTED).GetPen();
761 
762     if (m_pen_scale != 1)
763     {
764         currentPen.SetWidth(int(currentPen.GetWidth() * m_pen_scale));
765         selectedPen.SetWidth(int(selectedPen.GetWidth() * m_pen_scale));
766     }
767 
768     dc->SetPen(currentPen);
769 
770     const wxRangeDoubleSelection *ranges = m_owner->GetCurveSelection(curve_index);
771     bool selected = false;
772 
773     int clipped = ClippedNeither;
774 
775     for (i=dcRect.x; i<right; i++)
776     {
777         x1 = m_owner->GetPlotCoordFromClientX(i);
778         y1 = yy1 = curve->GetY(x1);
779 
780         clipped = ClipLineToRect(x0, yy0, x1, yy1, subViewRect);
781 
782         if (selected != ranges->Contains(x1))
783         {
784             if (selected)
785                 dc->SetPen(currentPen);
786             else
787                 dc->SetPen(selectedPen);
788 
789             selected = !selected;
790         }
791 
792         if (clipped != ClippedOut)
793         {
794             j0 = m_owner->GetClientCoordFromPlotY(yy0);
795             j1 = m_owner->GetClientCoordFromPlotY(yy1);
796             wxPLOT_DRAW_LINE(dc, window, pen, i-1, j0, i, j1);
797 
798             if (selected && !((clipped & ClippedSecond) != 0))
799             {
800                 wxPLOT_DRAW_ELLIPSE(dc, window, pen, i, j1, 2, 2);
801             }
802         }
803 
804         x0 = x1;
805         y0 = yy0 = y1;
806     }
807 
808     dc->SetPen(wxNullPen);
809 }
810 
811 //-----------------------------------------------------------------------------
812 // wxPlotDrawerDataCurve
813 //-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerDataCurve,wxPlotDrawerBase)814 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerDataCurve, wxPlotDrawerBase)
815 
816 void wxPlotDrawerDataCurve::Draw(wxDC *dc, wxPlotData* curve, int curve_index)
817 {
818     wxCHECK_RET(dc && m_owner && curve && curve->Ok(), wxT("invalid curve"));
819     INITIALIZE_FAST_GRAPHICS
820 
821     wxRect dcRect(GetDCRect());
822 
823     wxRect2DDouble viewRect( GetPlotViewRect() ); //m_viewRect );
824     wxRect2DDouble subViewRect( m_owner->GetPlotRectFromClientRect(dcRect) );
825     wxRect2DDouble curveRect( curve->GetBoundingRect() );
826     if (!wxPlotRect2DDoubleIntersects(curveRect, subViewRect)) return;
827 
828 /*  // FIXME - drawing symbol bitmaps in MSW is very slow
829     wxBitmap bitmap;
830     if (curve == GetActiveCurve())
831         bitmap = curve->GetSymbol(wxPLOTPEN_ACTIVE);
832     else
833         bitmap = curve->GetSymbol(wxPLOTPEN_NORMAL);
834 
835     if (!bitmap.Ok())
836     {
837         if (curve == GetActiveCurve())
838             bitmap = wxPlotSymbolCurrent;
839         else
840             bitmap = wxPlotSymbolNormal;
841     }
842 
843     int bitmapHalfWidth = bitmap.GetWidth()/2;
844     int bitmapHalfHeight = bitmap.GetHeight()/2;
845 */
846 
847     // find the starting and ending indexes into the data curve
848     int n, n_start, n_end;
849     bool x_ordered = curve->GetIsXOrdered();
850 
851     if (x_ordered)
852     {
853         n_start = curve->GetIndexFromX(subViewRect.GetLeft(), wxPlotData::index_floor);
854         n_end   = curve->GetIndexFromX(subViewRect.GetRight(), wxPlotData::index_ceil);
855         n_end++; // for statement comparison is <
856     }
857     else
858     {
859         n_start = 0;
860         n_end   = curve->GetCount();
861     }
862 
863     // set the pens to draw with
864     wxPen currentPen = (curve_index == m_owner->GetActiveIndex()) ? curve->GetPen(wxPLOTPEN_ACTIVE).GetPen()
865                                                                   : curve->GetPen(wxPLOTPEN_NORMAL).GetPen();
866     wxPen selectedPen = curve->GetPen(wxPLOTPEN_SELECTED).GetPen();
867     if (m_pen_scale != 1)
868     {
869         currentPen.SetWidth(int(currentPen.GetWidth() * m_pen_scale));
870         selectedPen.SetWidth(int(selectedPen.GetWidth() * m_pen_scale));
871     }
872 
873     dc->SetPen(currentPen);
874 
875     // handle the selected ranges and initialize the starting range
876     const wxArrayRangeInt &ranges = m_owner->GetDataCurveSelection(curve_index)->GetRangeArray();
877     int n_range = 0, range_count = ranges.GetCount();
878     int min_sel = -1, max_sel = -1;
879     for (n_range=0; n_range<range_count; n_range++)
880     {
881         const wxRangeInt& range = ranges[n_range];
882         if ((range.m_max >= n_start) || (range.m_min >= n_start))
883         {
884             min_sel = range.m_min;
885             max_sel = range.m_max;
886             if (range.Contains(n_start))
887                 dc->SetPen( selectedPen );
888 
889             break;
890         }
891     }
892 
893     // data variables
894     const double *x_data = &curve->GetXData()[n_start];
895     const double *y_data = &curve->GetYData()[n_start];
896 
897     int i0, j0, i1, j1;        // curve coords in pixels
898     double x0, y0, x1, y1;     // original curve coords
899     double xx0, yy0, xx1, yy1; // clipped curve coords
900 
901     x0 = *x_data;
902     y0 = *y_data;
903 
904     int clipped = ClippedNeither;
905 
906     bool draw_lines   = m_owner->GetDrawLines();
907     bool draw_symbols = m_owner->GetDrawSymbols();
908     bool draw_spline  = m_owner->GetDrawSpline();
909 
910     SplineDrawer sd;
911     wxRangeDoubleSelection dblRangeSel;
912 
913     if (draw_spline)
914     {
915         wxRangeDouble viewRange(viewRect.m_x, viewRect.GetRight());
916         wxRangeDouble dcRange(dcRect.x, dcRect.GetRight());
917 
918         for (int r = n_range; r < range_count; r++)
919         {
920             wxRangeDouble plotRange(curve->GetXValue(ranges[r].m_min),
921                                     curve->GetXValue(ranges[r].m_max));
922 
923             if (viewRange.Intersects(plotRange))
924             {
925                 double min_x = m_owner->GetClientCoordFromPlotX(plotRange.m_min);
926                 double max_x = m_owner->GetClientCoordFromPlotX(plotRange.m_max);
927                 dblRangeSel.SelectRange(wxRangeDouble(min_x, max_x));
928             }
929             else
930                 break;
931         }
932 
933         // spline starts 2 points back for smoothness
934         int s_start = n_start > 1 ? -2 : n_start > 0 ? -1 : 0;
935         sd.Create(dc, currentPen, selectedPen,
936                   wxRect2DDouble(dcRect.x, dcRect.y, dcRect.width, dcRect.height),
937                   &dblRangeSel,
938                   m_owner->GetClientCoordFromPlotX(x_data[s_start]),
939                   m_owner->GetClientCoordFromPlotY(y_data[s_start]),
940                   m_owner->GetClientCoordFromPlotX(x_data[s_start+1]),
941                   m_owner->GetClientCoordFromPlotY(y_data[s_start+1]));
942     }
943 
944     for (n = n_start; n < n_end; n++)
945     {
946         x1 = *x_data++;
947         y1 = *y_data++;
948 
949         if (draw_spline)
950             sd.DrawSpline(m_owner->GetClientCoordFromPlotX(x1),
951                           m_owner->GetClientCoordFromPlotY(y1));
952 
953         xx0 = x0; yy0 = y0; xx1 = x1; yy1 = y1;
954         clipped = ClipLineToRect(xx0, yy0, xx1, yy1, viewRect);
955         if (clipped != ClippedOut)
956         {
957             i0 = m_owner->GetClientCoordFromPlotX(xx0);
958             j0 = m_owner->GetClientCoordFromPlotY(yy0);
959             i1 = m_owner->GetClientCoordFromPlotX(xx1);
960             j1 = m_owner->GetClientCoordFromPlotY(yy1);
961 
962             if (draw_lines && ((i0 != i1) || (j0 != j1)))
963             {
964                 wxPLOT_DRAW_LINE(dc, window, pen, i0, j0, i1, j1);
965             }
966 
967             if (n == min_sel)
968                 dc->SetPen( selectedPen );
969 
970             if (draw_symbols && !((clipped & ClippedSecond) != 0) &&
971                 ((i0 != i1) || (j0 != j1) || (n == min_sel) || (n == n_start)))
972             {
973                 //dc->DrawBitmap( bitmap, i1 - bitmapHalfWidth, j1 - bitmapHalfHeight, true );
974                 wxPLOT_DRAW_ELLIPSE(dc, window, pen, i1, j1, 2, 2);
975             }
976         }
977         else if (n == min_sel)
978         {
979             dc->SetPen( selectedPen );
980         }
981 
982         if (n == max_sel)
983         {
984             dc->SetPen( currentPen );
985             if (n_range < range_count - 1)
986             {
987                 n_range++;
988                 min_sel = ranges[n_range].m_min;
989                 max_sel = ranges[n_range].m_max;
990             }
991         }
992 
993         x0 = x1;
994         y0 = y1;
995     }
996 
997     if (draw_spline)
998     {
999         // want an extra point at the end to smooth it out
1000         if (n_end < (int)curve->GetCount() - 1)
1001             sd.DrawSpline(m_owner->GetClientCoordFromPlotX(*x_data),
1002                           m_owner->GetClientCoordFromPlotY(*y_data));
1003 
1004         sd.EndSpline();
1005     }
1006 
1007     dc->SetPen(wxNullPen);
1008 }
1009 
1010 //-----------------------------------------------------------------------------
1011 // wxPlotDrawerMarkers
1012 //-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerMarker,wxPlotDrawerBase)1013 IMPLEMENT_ABSTRACT_CLASS(wxPlotDrawerMarker, wxPlotDrawerBase)
1014 
1015 void wxPlotDrawerMarker::Draw(wxDC *dc, const wxPlotMarker& marker)
1016 {
1017     // drawing multiple markers is faster, so just drawing a single one takes a hit
1018     wxArrayPlotMarker markers;
1019     markers.Add(marker);
1020     Draw(dc, markers);
1021 }
1022 
Draw(wxDC * dc,const wxArrayPlotMarker & markers)1023 void wxPlotDrawerMarker::Draw(wxDC *dc, const wxArrayPlotMarker& markers)
1024 {
1025     wxCHECK_RET(dc && m_owner, wxT("dc or owner"));
1026     INITIALIZE_FAST_GRAPHICS
1027 
1028     wxRect dcRect(GetDCRect());
1029     wxRect2DDouble subViewRect = m_owner->GetPlotRectFromClientRect( dcRect );
1030 
1031     double x0 = 0, y0 = 0, x1 = 0, y1 = 0;
1032     int n, count = markers.GetCount();
1033     for (n = 0; n < count; n++)
1034     {
1035         const wxPlotMarker &marker = markers[n];
1036         wxCHECK_RET(marker.Ok(), wxT("Invalid marker"));
1037         wxRect2DDouble r = marker.GetPlotRect();
1038         x0 = r.m_x;
1039         y0 = r.m_y;
1040         x1 = r.GetRight();
1041         y1 = r.GetBottom();
1042 
1043         if (marker.GetPen().Ok())
1044             dc->SetPen(marker.GetPen().GetPen());
1045         if (marker.GetBrush().Ok())
1046             dc->SetBrush(marker.GetBrush().GetBrush());
1047 
1048         // determine what to draw
1049         int marker_type = marker.GetMarkerType();
1050         wxSize size     = marker.GetSize();
1051 
1052         if (marker_type == wxPLOTMARKER_BITMAP)
1053         {
1054             wxBitmap bmp(marker.GetBitmap());
1055             int w = bmp.GetWidth(), h = bmp.GetHeight();
1056             // FIXME - add scaling and shifting later - maybe
1057             int i0 = m_owner->GetClientCoordFromPlotX(x0);
1058             int j0 = m_owner->GetClientCoordFromPlotY(y0);
1059             dc->DrawBitmap(bmp, RINT(i0 - w/2.0), RINT(j0 - h/2.0), true);
1060         }
1061         else if (marker_type == wxPLOTMARKER_LINE)
1062         {
1063             if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
1064             {
1065                 int i0 = m_owner->GetClientCoordFromPlotX(x0);
1066                 int j0 = m_owner->GetClientCoordFromPlotY(y0);
1067                 int i1 = m_owner->GetClientCoordFromPlotX(x1);
1068                 int j1 = m_owner->GetClientCoordFromPlotY(y1);
1069                 wxPLOT_DRAW_LINE(dc, window, pen, i0, j0, i1, j1);
1070             }
1071         }
1072         else if (marker_type == wxPLOTMARKER_ELLIPSE)
1073         {
1074             // fixed pixel size
1075             if ((size.x > 0) && (size.y > 0))
1076             {
1077                 if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
1078                 {
1079                     int i0 = m_owner->GetClientCoordFromPlotX(x0);
1080                     int j0 = m_owner->GetClientCoordFromPlotY(y0);
1081                     wxPLOT_DRAW_ELLIPSE(dc, window, pen, i0, j0, size.x, size.y);
1082                 }
1083             }
1084 /*
1085             else if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
1086             {
1087                 int i0 = m_owner->GetClientCoordFromPlotX(x0);
1088                 int j0 = m_owner->GetClientCoordFromPlotY(y0);
1089                 int i1 = m_owner->GetClientCoordFromPlotX(x1);
1090                 int j1 = m_owner->GetClientCoordFromPlotY(y1);
1091                 wxPLOT_DRAW_ELLIPSE(dc, window, pen, i0, j0, i1, j1);
1092             }
1093 */
1094         }
1095         else // figure out the rest
1096         {
1097             // we may ignore type if rect is in certain states
1098 
1099             bool is_horiz = r.m_width  < 0;
1100             bool is_vert  = r.m_height < 0;
1101 
1102             bool cross = is_horiz && is_vert;
1103 
1104             if (is_horiz)
1105             {
1106                 x0 = subViewRect.m_x - subViewRect.m_width; // push outside win
1107                 x1 = subViewRect.GetRight() + subViewRect.m_width;
1108             }
1109             if (is_vert)
1110             {
1111                 y0 = subViewRect.m_y - subViewRect.m_height;
1112                 y1 = subViewRect.GetBottom() + subViewRect.m_height;
1113             }
1114 
1115             if ((marker_type == wxPLOTMARKER_POINT) || ((x0 == x1) && (y0 == y1)))
1116             {
1117                 if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
1118                 {
1119                     int i0 = m_owner->GetClientCoordFromPlotX(x0);
1120                     int j0 = m_owner->GetClientCoordFromPlotY(y0);
1121                     dc->DrawPoint(i0, j0);
1122                 }
1123             }
1124             else if ((marker_type == wxPLOTMARKER_VERT_LINE) || ((x0 == x1) && (y0 != y1)))
1125             {
1126                 if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
1127                 {
1128                     int i0 = m_owner->GetClientCoordFromPlotX(x0);
1129                     int j0 = m_owner->GetClientCoordFromPlotY(y0);
1130                     int j1 = m_owner->GetClientCoordFromPlotY(y1);
1131                     wxPLOT_DRAW_LINE(dc, window, pen, i0, j0, i0, j1);
1132                 }
1133             }
1134             else if ((marker_type == wxPLOTMARKER_HORIZ_LINE) || ((y0 == y1) && (x0 != x1)))
1135             {
1136                 if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
1137                 {
1138                     int i0 = m_owner->GetClientCoordFromPlotX(x0);
1139                     int i1 = m_owner->GetClientCoordFromPlotX(x1);
1140                     int j0 = m_owner->GetClientCoordFromPlotY(y0);
1141                     wxPLOT_DRAW_LINE(dc, window, pen, i0, j0, i1, j0);
1142                 }
1143             }
1144             else if ((marker_type == wxPLOTMARKER_CROSS) || cross)
1145             {
1146 
1147 
1148             }
1149             else                                // rectangle
1150             {
1151                 wxRect2DDouble clippedRect(x0, y0, x1 - x0, y1 - y0);
1152                 clippedRect.Intersect(subViewRect);
1153                 int pen_width = dc->GetPen().GetWidth() + 2;
1154 
1155                 int i0 = m_owner->GetClientCoordFromPlotX(clippedRect.m_x);
1156                 int i1 = m_owner->GetClientCoordFromPlotX(clippedRect.GetRight());
1157                 int j0 = m_owner->GetClientCoordFromPlotY(clippedRect.m_y);
1158                 int j1 = m_owner->GetClientCoordFromPlotY(clippedRect.GetBottom());
1159                 if (r.m_x < subViewRect.m_x)  i0 -= pen_width;
1160                 if (r.m_y < subViewRect.m_y)  j0 -= pen_width;
1161                 if (r.GetRight()  > subViewRect.GetRight())  i1 += pen_width;
1162                 if (r.GetBottom() > subViewRect.GetBottom()) j1 += pen_width;
1163 
1164                 dc->SetClippingRegion(dcRect);
1165                 dc->DrawRectangle(i0, j0, i1 - i0 + 1, j1 - j0 + 1);
1166                 dc->DestroyClippingRegion();
1167             }
1168         }
1169     }
1170 }
1171