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