wxArt2D
dcdrawer.cpp
Go to the documentation of this file.
1 /*! \file artbase/src/dcdrawer.cpp
2  \author Klaas Holwerda
3 
4  Copyright: 2000-2004 (c) Klaas Holwerda
5 
6  Licence: wxWidgets Licence
7 
8  RCS-ID: $Id: dcdrawer.cpp,v 1.87 2009/10/06 18:40:31 titato Exp $
9 */
10 
11 
12 #include "a2dprec.h"
13 
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17 
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #include <wx/wfstream.h>
21 #include "wx/artbase/drawer2d.h"
22 #include "wx/artbase/stylebase.h"
23 #include "wx/artbase/dcdrawer.h"
24 
25 #if defined(__WXMSW__)
26 #include "wx/artbase/mswfont.h"
27 #endif
28 #endif
29 
30 #ifdef __WXMSW__
31  #include "wx/msw/dcclient.h"
32  #include "wx/msw/dcmemory.h"
33  #include "wx/msw/dcscreen.h"
34 #endif
35 
36 #ifdef __WXGTK3__
37  #include "wx/gtk/dc.h"
38 #elif defined __WXGTK20__
39  #include "wx/gtk/dcclient.h"
40 #elif defined(__WXGTK__)
41  #include "wx/gtk1/dcclient.h"
42  #include "wx/gtk1/dcmemory.h"
43  #include "wx/gtk1/dcscreen.h"
44 #endif
45 
46 #ifdef __WXMAC__
47  #include "wx/osx/dcclient.h"
48  #include "wx/osx/dcmemory.h"
49  #include "wx/osx/dcscreen.h"
50 #endif
51 
52 #ifdef __WXPM__
53  #include "wx/os2/dcclient.h"
54  #include "wx/os2/dcmemory.h"
55  #include "wx/os2/dcscreen.h"
56 #endif
57 
58 #ifdef __WXCOCOA__
59  #include "wx/cocoa/dcclient.h"
60  #include "wx/cocoa/dcmemory.h"
61  #include "wx/cocoa/dcscreen.h"
62 #endif
63 
64 #ifdef __WXMOTIF__
65  #include "wx/motif/dcclient.h"
66  #include "wx/motif/dcmemory.h"
67  #include "wx/motif/dcscreen.h"
68 #endif
69 
70 #ifdef __WXX11__
71  #include "wx/x11/dcclient.h"
72  #include "wx/x11/dcmemory.h"
73  #include "wx/x11/dcscreen.h"
74 #endif
75 
76 #ifdef __WXDFB__
77  #include "wx/dfb/dcclient.h"
78  #include "wx/dfb/dcmemory.h"
79  #include "wx/dfb/dcscreen.h"
80 #endif
81 
82 #if defined(__WXMSW__)
83 #include <wx/msw/private.h>
84 #elif defined(__WXGTK__)
85  #include <wx/dcps.h>
86 #endif
87 /*
88 #elif __WXGTK__
89 #include <gtk/gtk.h>
90 //#include <gdk/gdkrgb.h>
91 #include <wx/dcps.h>
92 #if wxCHECK_VERSION(2,9,0)
93 #include "wx/gtk/dcclient.h"
94 #else
95 #include "wx/gtk/win_gtk.h"
96 #endif
97 #endif
98 */
99 
100 #if wxART2D_USE_AGGDRAWER
101 #include "wx/aggdrawer/aggdrawer.h"
102 #endif
103 
104 
105 #if wxART2D_USE_FREETYPE
106 #include <ft2build.h>
107 #ifdef _MSC_VER
108 // Do not use the define include for MSVC, because of a bug with precompiled
109 // headers. See (freetype)/doc/INSTALL.ANY for (some) more information
110 #include <freetype/freetype.h>
111 #include <freetype/ftoutln.h>
112 #else // _MSC_VER
113 // This is the way it should be included.
114 #include FT_FREETYPE_H
115 #include FT_OUTLINE_H
116 #endif // _MSC_VER
117 #endif
118 
119 
120 IMPLEMENT_DYNAMIC_CLASS( a2dDcDrawer, a2dDrawer2D )
121 IMPLEMENT_DYNAMIC_CLASS( a2dMemDcDrawer, a2dDcDrawer )
122 
123 /*******************************************************************
124 a2dDcDrawer
125 ********************************************************************/
126 
127 a2dDcDrawer::a2dDcDrawer( const wxSize& size ): a2dDrawer2D( size )
128 {
129  m_externalDc = false;
130  m_renderDC = m_deviceDC = 0;
131  m_clip.Clear();
132 }
133 
134 a2dDcDrawer::a2dDcDrawer( int width, int height ): a2dDrawer2D( width, height )
135 {
136  m_externalDc = false;
137  m_renderDC = m_deviceDC = 0;
138  m_clip.Clear();
139 }
140 
142 {}
143 
145  : a2dDrawer2D( other )
146 {
147  m_externalDc = false;
148  m_renderDC = m_deviceDC = 0;
149  m_clip.Clear();
150 }
151 
153  : a2dDrawer2D( other )
154 {
155  m_externalDc = false;
156  m_renderDC = m_deviceDC = 0;
157  m_clip.Clear();
158 }
159 
161 {
162  wxASSERT_MSG( m_beginDraw_endDraw >= 0, wxT( "a2dDcDrawer, unbalanced BeginDraw EndDraw" ) );
163 
164  if ( m_beginDraw_endDraw == 0 )
165  {
166  if ( m_externalDc )
167  {
168  wxASSERT_MSG( m_renderDC != NULL, wxT( "a2dMemDcDrawer, wxClientDc not set yet" ) );
169  }
170  else
171  {
172  wxASSERT_MSG( m_renderDC == NULL, wxT( "a2dMemDcDrawer, unbalanced BeginDraw EndDraw" ) );
173 
174  if ( m_display )
175  {
176  m_deviceDC = new wxClientDC( m_display );
177  m_display->PrepareDC( *m_deviceDC );
178  }
180  }
181 
186  m_OpacityFactor = 255;
187  m_renderDC->SetMapMode( wxMM_TEXT );
188  }
190 }
191 
193 {
195 
196  wxASSERT_MSG( m_beginDraw_endDraw >= 0, wxT( "a2dDcDrawer, unbalanced BeginDraw EndDraw" ) );
197 
198  if ( m_beginDraw_endDraw == 0 )
199  {
200  wxASSERT_MSG( m_renderDC != NULL, wxT( "a2dDcDrawer, unbalanced BeginDraw EndDraw" ) );
201  if ( m_externalDc )
202  {
203  wxASSERT_MSG( true == m_externalDc, wxT( "a2dDcDrawer, wxClientDc not set yet" ) );
204  }
205  else
206  {
207  if ( m_display )
208  delete m_deviceDC;
209  }
210 
211  m_renderDC = m_deviceDC = NULL;
212  }
213 
214 }
215 
216 void a2dDcDrawer::SetBufferSize( int w, int h )
217 {
218  m_width = w;
219  m_height = h;
220 }
221 
222 wxBitmap a2dDcDrawer::GetSubBitmap( wxRect rect ) const
223 {
224 //klion
225 #ifdef __WXGTK__
226  wxFAIL_MSG( wxT( "a2dDcDrawer has no buffer" ) );
227 #endif
228  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
229 
230 #ifdef __WXGTK__
231  wxBitmap ret( rect.width, rect.height, 32 );
232 #else
233  wxBitmap ret( rect.width, rect.height, m_renderDC->GetDepth() );
234 #endif
235  wxASSERT_MSG( ret.Ok(), wxT( "GetSubImage error" ) );
236 
237  if ( m_renderDC )
238  {
239  //do NOT use getsubbitmap, renderDc is already set for the buffer therefor will not work properly
240  wxMemoryDC dcb;
241  dcb.SelectObject( ret );
242  dcb.Blit( 0, 0, rect.width, rect.height, m_renderDC, rect.x, rect.y, wxCOPY, false );
243  dcb.SelectObject( wxNullBitmap );
244  }
245  return ret;
246 }
247 
248 void a2dDcDrawer::SetRenderDC( wxDC* dc )
249 {
250  if ( dc == NULL )
251  {
252  m_externalDc = false;
253  m_renderDC = m_deviceDC = NULL;
254  }
255  else
256  {
257  m_externalDc = true;
258  m_renderDC = dc;
259  }
260 }
261 
262 void a2dDcDrawer::SetClippingRegion( a2dVertexList* points, bool spline, wxPolygonFillMode fillStyle )
263 {
264  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
265  unsigned int n = points->size();
266 
267  m_cpointsDouble.resize( n );
268 
269  unsigned int i = 0;
270  double x, y;
271  forEachIn( a2dVertexList, points )
272  {
273  a2dPoint2D point = ( *iter )->GetPoint();
274  //transform to device
275  GetUserToDeviceTransform().TransformPoint( point.m_x, point.m_y, x, y );
276  m_cpointsDouble[i].x = x;
277  m_cpointsDouble[i].y = y;
278  i++;
279  }
280 
281  if ( spline )
282  n = ConvertSplinedPolygon2( n );
283 
284  wxPoint* intpoints = _convertToIntPointCache( n, &m_cpointsDouble[0] );
285  m_clip = wxRegion( n, intpoints, fillStyle );
286 
287  wxCoord originX, originY;
288  m_renderDC->GetDeviceOrigin( &originX, &originY );
289  m_clip.Offset( originX, originY );
290  m_renderDC->DestroyClippingRegion();
291 #if wxCHECK_VERSION(2,9,0)
292  m_renderDC->SetDeviceClippingRegion( m_clip );
293 #else
294  m_renderDC->SetClippingRegion( m_clip );
295 #endif
296  m_clipboxdev = m_clip.GetBox();
297  m_clipboxdev.Offset( -originX, -originY );
299 }
300 
301 void a2dDcDrawer::ExtendAndPushClippingRegion( a2dVertexList* points, bool spline, wxPolygonFillMode fillStyle, a2dBooleanClip clipoperation )
302 {
303 
304  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
305 
306  wxRegion* push = new wxRegion( m_clip );
307 
308  m_clipregionlist.Insert( push );
309 
310  ExtendClippingRegion( points, spline, fillStyle, clipoperation );
311 }
312 
313 void a2dDcDrawer::ExtendClippingRegion( a2dVertexList* points, bool spline, wxPolygonFillMode WXUNUSED( fillStyle ), a2dBooleanClip clipoperation )
314 {
315  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
316 
317  wxRegion totaladd;
318  bool first = false;
319 
320  a2dBoundingBox devbox;
321  bool smallPoly = false;
322  unsigned int segments = ToDeviceLines( points, devbox, smallPoly );
323 
324  if ( segments == 0 )
325  return;
326 
327  if ( spline )
328  segments = ConvertSplinedPolygon2( segments );
329 
330  wxPoint* int_cpts = _convertToIntPointCache( segments, &m_cpointsDouble[0] );
331  wxRegion add = wxRegion( segments, int_cpts, wxWINDING_RULE );
332  wxCoord originX, originY;
333  m_renderDC->GetDeviceOrigin( &originX, &originY );
334  add.Offset( originX, originY );
335  if ( !first )
336  {
337  totaladd = add;
338  first = true;
339  }
340  else
341  totaladd.Union( add );
342 
343  if ( !m_clip.Empty() )
344  {
345  bool result;
346  switch ( clipoperation )
347  {
348  case a2dCLIP_AND:
349  result = m_clip.Intersect( totaladd );
350  break ;
351 
352  case a2dCLIP_OR:
353  result = m_clip.Union( totaladd );
354  break ;
355 
356  case a2dCLIP_XOR:
357  result = m_clip.Xor( totaladd );
358  break ;
359 
360  case a2dCLIP_DIFF:
361  result = m_clip.Subtract( totaladd );
362  break ;
363 
364  case a2dCLIP_COPY:
365  default:
366  m_clip = totaladd;
367  result = true;
368  break ;
369  }
370  if ( result )
371  {
372  m_renderDC->DestroyClippingRegion();
373 #if wxCHECK_VERSION(2,9,0)
374  m_renderDC->SetDeviceClippingRegion( m_clip );
375 #else
376  m_renderDC->SetClippingRegion( m_clip );
377 #endif
378  }
379  }
380  else
381  {
382  m_clip = totaladd;
383  m_renderDC->DestroyClippingRegion();
384 #if wxCHECK_VERSION(2,9,0)
385  m_renderDC->SetDeviceClippingRegion( m_clip );
386 #else
387  m_renderDC->SetClippingRegion( m_clip );
388 #endif
389  }
390 
391  m_clipboxdev = m_clip.GetBox();
392  m_clipboxdev.Offset( -originX, -originY );
394 }
395 
397 {
398  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
399  if ( !m_clipregionlist.GetCount() )
400  return;
401 
402  m_clip = *m_clipregionlist.GetFirst()->GetData();
403  delete m_clipregionlist.GetFirst()->GetData();
404  m_clipregionlist.DeleteNode( m_clipregionlist.GetFirst() );
405 
406  m_renderDC->DestroyClippingRegion();
407 #if wxCHECK_VERSION(2,9,0)
408  m_renderDC->SetDeviceClippingRegion( m_clip );
409 #else
410  m_renderDC->SetClippingRegion( m_clip );
411 #endif
412  m_clipboxdev = m_clip.GetBox();
413  wxCoord originX, originY;
414  m_renderDC->GetDeviceOrigin( &originX, &originY );
415  m_clipboxdev.Offset( -originX, -originY );
417 
418 }
419 
420 void a2dDcDrawer::SetClippingRegionDev( wxCoord minx, wxCoord miny, wxCoord width, wxCoord height )
421 {
422  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
423  m_clip = wxRegion( minx, miny, width, height );
424  wxCoord originX, originY;
425  m_renderDC->GetDeviceOrigin( &originX, &originY );
426  m_clip.Offset( originX, originY );
427  m_renderDC->DestroyClippingRegion();
428 #if wxCHECK_VERSION(2,9,0)
429  m_renderDC->SetDeviceClippingRegion( m_clip );
430 #else
431  m_renderDC->SetClippingRegion( m_clip );
432 #endif
433 
434  m_clipboxdev = wxRect( minx, miny, width, height );
436 }
437 
438 void a2dDcDrawer::SetClippingRegion( double minx, double miny, double maxx, double maxy )
439 {
440  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
441  int iminx = WorldToDeviceX( minx );
442  int iminy = WorldToDeviceY( miny );
443  int imaxx = WorldToDeviceX( maxx );
444  int imaxy = WorldToDeviceY( maxy );
445  if ( m_yaxis )
446  {
447  m_clip = wxRegion( iminx, imaxy, imaxx - iminx, iminy - imaxy );
448  m_clipboxdev = wxRect( iminx, imaxy, imaxx - iminx, iminy - imaxy );
449  }
450  else
451  {
452  m_clip = wxRegion( iminx, iminy, imaxx - iminx, imaxy - iminy );
453  m_clipboxdev = wxRect( iminx, iminy, imaxx - iminx, imaxy - iminy );
454  }
455 
457 
458  m_renderDC->DestroyClippingRegion();
459  wxCoord originX, originY;
460  m_renderDC->GetDeviceOrigin( &originX, &originY );
461  m_clip.Offset( originX, originY );
462 #if wxCHECK_VERSION(2,9,0)
463  m_renderDC->SetDeviceClippingRegion( m_clip );
464 #else
465  m_renderDC->SetClippingRegion( m_clip );
466 #endif
467 }
468 
470 {
471  m_clip.Clear();
472  if ( m_renderDC )
473  m_renderDC->DestroyClippingRegion();
474 
475  m_clipboxdev = wxRect( 0, 0, m_width, m_height );
477 }
478 
480 {
482  SetDrawerFill( *a2dBLACK_FILL ); //set to a sure state
485 }
486 
488 {
489  if ( m_renderDC )
490  {
491  if ( m_activestroke.GetStyle() == a2dSTROKE_TRANSPARENT )
492  {
493  m_renderDC->SetPen( *wxTRANSPARENT_PEN );
494  }
495  else if ( m_activestroke.IsNoStroke() )
496  {
497  m_renderDC->SetPen( *wxTRANSPARENT_PEN );
498  //nullpen gives assert in wxDC its pen (no ref data )
499  //m_renderDC->SetPen( *wxNullPen );
500  }
502  {
503  m_renderDC->SetPen( *wxBLACK_PEN );
504  }
505  else if ( m_activestroke.GetType() == a2dSTROKE_ONE_COLOUR )
506  {
507  int style;
508  switch( m_activestroke.GetStyle() )
509  {
510  case a2dSTROKE_SOLID: style = wxSOLID;
511  break;
512  case a2dSTROKE_TRANSPARENT: style = wxTRANSPARENT;
513  break;
514  case a2dSTROKE_DOT: style = wxDOT;
515  break;
516  case a2dSTROKE_DOT_DASH: style = wxDOT_DASH;
517  break;
518  case a2dSTROKE_LONG_DASH: style = wxLONG_DASH;
519  break;
520  case a2dSTROKE_SHORT_DASH: style = wxSHORT_DASH;
521  break;
522  case a2dSTROKE_BDIAGONAL_HATCH: style = wxBDIAGONAL_HATCH;
523  break;
524  case a2dSTROKE_CROSSDIAG_HATCH: style = wxCROSSDIAG_HATCH;
525  break;
526  case a2dSTROKE_FDIAGONAL_HATCH: style = wxFDIAGONAL_HATCH;
527  break;
528  case a2dSTROKE_CROSS_HATCH: style = wxCROSS_HATCH;
529  break;
530  case a2dSTROKE_HORIZONTAL_HATCH: style = wxHORIZONTAL_HATCH;
531  break;
532  case a2dSTROKE_VERTICAL_HATCH: style = wxVERTICAL_HATCH;
533  break;
534  case a2dSTROKE_STIPPLE: style = wxSTIPPLE;
535  break;
536  case a2dSTROKE_STIPPLE_MASK_OPAQUE: style = wxSTIPPLE_MASK_OPAQUE;
537  break;
538  default: style = wxSOLID;
539  }
540 
542  {
543  wxPen dcpen( m_activestroke.GetColour(), 0, style );
544  m_renderDC->SetPen( dcpen );
545  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
546  }
547  else
548  {
549  wxPen dcpen( m_activestroke.GetColour(), ( int ) m_activestroke.GetWidth(), style );
550  dcpen.SetJoin( m_activestroke.GetJoin() );
551  dcpen.SetCap( m_activestroke.GetCap() );
553  {
554  int widthDev = ( int ) WorldToDeviceXRel( m_activestroke.GetWidth() );
555  dcpen.SetWidth( widthDev );
556  }
557  m_renderDC->SetPen( dcpen );
558  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
559  }
560 
561  }
562  else if ( m_activestroke.GetType() == a2dSTROKE_BITMAP )
563  {
564  wxPen dcpen;
565 
567  dcpen = wxPen( m_activestroke.GetColour(), 0, wxBRUSHSTYLE_SOLID );
568  else
569  {
570  int width = ( int ) m_activestroke.GetWidth();
572  width = ( int )WorldToDeviceXRel( width );
573  dcpen = wxPen( m_activestroke.GetColour(), width, wxBRUSHSTYLE_SOLID );
574  dcpen.SetJoin( m_activestroke.GetJoin() );
575  dcpen.SetCap( m_activestroke.GetCap() );
576  }
577 
578 #if defined(__WXMSW__)
579  wxBrushStyle style;
580  switch( m_activestroke.GetStyle() )
581  {
582  case a2dSTROKE_STIPPLE:
583  style = wxBRUSHSTYLE_STIPPLE;
584  dcpen.SetStyle( style );
585  dcpen.SetStipple( m_activestroke.GetStipple() );
586  break;
589  if ( 0 ) //m_printingMode )
590  {
591  wxBitmap noMask = m_activestroke.GetStipple();
592  noMask.SetMask( NULL );
593  style = wxBRUSHSTYLE_STIPPLE;
594  dcpen.SetStyle( style );
595  dcpen.SetStipple( noMask );
596  }
597  else
598  {
599  style = wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE;
600  dcpen.SetStyle( style );
601  dcpen.SetStipple( m_activestroke.GetStipple() );
602  }
603  break;
604  default: style = wxBRUSHSTYLE_SOLID;
605  dcpen.SetStyle( style );
606  }
607 #endif
608 
609  m_renderDC->SetPen( dcpen );
610  m_renderDC->SetTextBackground( *wxBLACK );
611  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
612  }
613 
614  }
615 }
616 
618 {
619  if ( m_renderDC )
620  {
621  if ( !m_activefill.GetFilling() )
622  {
623  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
624  m_renderDC->SetTextBackground( *wxBLACK );
625  }
626  else if ( m_activefill.GetStyle() == a2dFILL_TRANSPARENT )
627  {
628  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
629  m_renderDC->SetTextBackground( *wxBLACK );
630  }
631  else if ( m_activefill.IsNoFill() )
632  {
633  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
634  //m_renderDC->SetBrush( wxNullBrush );
635  m_renderDC->SetTextBackground( *wxBLACK );
636  }
637  else if ( m_activefill.GetType() == a2dFILL_ONE_COLOUR )
638  {
639  wxBrush dcbrush;
640  wxBrushStyle style;
641  switch( m_activefill.GetStyle() )
642  {
643  case a2dFILL_TRANSPARENT:
644  style = wxBRUSHSTYLE_TRANSPARENT;
645  dcbrush.SetColour( m_activefill.GetColour() );
646  dcbrush.SetStyle( style );
647  break;
648  case a2dFILL_SOLID: style = wxBRUSHSTYLE_SOLID;
649  dcbrush.SetColour( m_activefill.GetColour() );
650  dcbrush.SetStyle( style );
651  break;
653  style = wxBRUSHSTYLE_BDIAGONAL_HATCH;
654  dcbrush.SetColour( m_activefill.GetColour() );
655  dcbrush.SetStyle( style );
656  break;
658  style = wxBRUSHSTYLE_CROSSDIAG_HATCH;
659  dcbrush.SetColour( m_activefill.GetColour() );
660  dcbrush.SetStyle( style );
661  break;
663  style = wxBRUSHSTYLE_FDIAGONAL_HATCH;
664  dcbrush.SetColour( m_activefill.GetColour() );
665  dcbrush.SetStyle( style );
666  break;
667  case a2dFILL_CROSS_HATCH:
668  style = wxBRUSHSTYLE_CROSS_HATCH;
669  dcbrush.SetColour( m_activefill.GetColour() );
670  dcbrush.SetStyle( style );
671  break;
673  style = wxBRUSHSTYLE_HORIZONTAL_HATCH;
674  dcbrush.SetColour( m_activefill.GetColour() );
675  dcbrush.SetStyle( style );
676  break;
678  style = wxBRUSHSTYLE_VERTICAL_HATCH;
679  dcbrush.SetColour( m_activefill.GetColour() );
680  dcbrush.SetStyle( style );
681  break;
682  default: style = wxBRUSHSTYLE_SOLID;
683  dcbrush.SetColour( m_activefill.GetColour() );
684  dcbrush.SetStyle( style );
685  }
686 
687  m_renderDC->SetBrush( dcbrush );
688  m_renderDC->SetTextBackground( m_activefill.GetColour() );
689  }
690  else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
691  {
692  wxBrush dcbrush;
693  wxBrushStyle style;
694  switch( m_activefill.GetStyle() )
695  {
696  case a2dFILL_TRANSPARENT:
697  style = wxBRUSHSTYLE_TRANSPARENT;
698  dcbrush.SetColour( m_activefill.GetColour() );
699  dcbrush.SetStyle( style );
700  break;
702  style = wxBRUSHSTYLE_BDIAGONAL_HATCH;
703  dcbrush.SetColour( m_activefill.GetColour() );
704  dcbrush.SetStyle( style );
705  break;
707  style = wxBRUSHSTYLE_CROSSDIAG_HATCH;
708  dcbrush.SetColour( m_activefill.GetColour() );
709  dcbrush.SetStyle( style );
710  break;
712  style = wxBRUSHSTYLE_FDIAGONAL_HATCH;
713  dcbrush.SetColour( m_activefill.GetColour() );
714  dcbrush.SetStyle( style );
715  break;
717  style = wxBRUSHSTYLE_CROSS_HATCH;
718  dcbrush.SetColour( m_activefill.GetColour() );
719  dcbrush.SetStyle( style );
720  break;
722  style = wxBRUSHSTYLE_HORIZONTAL_HATCH;
723  dcbrush.SetColour( m_activefill.GetColour() );
724  dcbrush.SetStyle( style );
725  break;
727  style = wxBRUSHSTYLE_VERTICAL_HATCH;
728  dcbrush.SetColour( m_activefill.GetColour() );
729  dcbrush.SetStyle( style );
730  break;
731  default:
732  style = wxBRUSHSTYLE_SOLID;
733  dcbrush.SetColour( m_activefill.GetColour() );
734  dcbrush.SetStyle( style );
735  }
736 
737  m_renderDC->SetBrush( dcbrush );
738  m_renderDC->SetTextBackground( m_activefill.GetColour() );
739  }
740  else if ( m_activefill.GetType() == a2dFILL_BITMAP )
741  {
742  wxBrush dcbrush;
743  wxBrushStyle style;
744  switch( m_activefill.GetStyle() )
745  {
746  case a2dFILL_STIPPLE:
747  style = wxBRUSHSTYLE_STIPPLE;
748  dcbrush.SetColour( m_activefill.GetColour() );
749  dcbrush.SetStipple( m_activefill.GetStipple() );
750  dcbrush.SetStyle( style );
751  break;
754  if ( 0 ) //m_printingMode )
755  {
756  wxBitmap noMask = m_activefill.GetStipple();
757  noMask.SetMask( NULL );
758  style = wxBRUSHSTYLE_STIPPLE;
759  dcbrush.SetColour( m_activefill.GetColour() );
760  dcbrush.SetStipple( noMask );
761  }
762  else
763  {
764  style = wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE;
765  dcbrush.SetColour( m_activefill.GetColour() );
766  dcbrush.SetStipple( m_activefill.GetStipple() );
767  }
768  dcbrush.SetStyle( style );
769  break;
770  default: style = wxBRUSHSTYLE_SOLID;
771  dcbrush.SetColour( m_activefill.GetColour() );
772  dcbrush.SetStyle( style );
773  }
774 
775  m_renderDC->SetBrush( dcbrush );
776  m_renderDC->SetTextBackground( m_activefill.GetColour() );
777  }
778  }
779 }
780 
781 void a2dDcDrawer::DoSetDrawStyle( a2dDrawStyle drawstyle )
782 {
783  m_drawstyle = drawstyle;
784 
785  switch( drawstyle )
786  {
787  case a2dWIREFRAME_INVERT:
790  SetLogicalFunction( wxINVERT );
791  break;
792 
793  case a2dWIREFRAME:
796  SetLogicalFunction( wxCOPY );
797  break;
798 
802  SetLogicalFunction( wxCOPY );
803  break;
804 
808  SetLogicalFunction( wxINVERT );
809  break;
810 
811  case a2dFILLED:
814  SetLogicalFunction( wxCOPY );
815  break;
816 
817  case a2dFIX_STYLE:
818  //preserve this
824 
825  // don't adjust style
826  SetLogicalFunction( wxCOPY );
827  break;
828 
829  case a2dFIX_STYLE_INVERT:
830  // don't adjust style
831  SetLogicalFunction( wxINVERT );
832  break;
833 
834  default:
835  wxASSERT( 0 );
836  }
837 }
838 
839 
840 void a2dDcDrawer::DrawImage( const wxImage& imagein, double x, double y, double width, double height, wxUint8 Opacity )
841 {
842  if ( m_disableDrawing )
843  return;
844 
845  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
846 
847  wxPoint centr( ( int ) width / 2, ( int ) height / 2 ); //this doesn't make any difference (BUG?)
848  //anyway the rotation center is the middle of the image
849 
850  double angle = GetTransform().GetRotation();
851 
852  wxImage image = imagein;
853 
854  if ( fabs( angle ) > 0.5 /*degree*/ )
855  {
856  image.SetMask( true );
857  if ( m_yaxis )
858  image = imagein.Rotate( angle / 180.0 * wxPI, centr, true, NULL );
859  else
860  image = imagein.Rotate( -angle / 180.0 * wxPI, centr, true, NULL );
861  }
862 
863  int devicew, deviceh;
864  devicew = WorldToDeviceXRel( GetTransform().Get_scaleX() * width );
865  deviceh = abs( WorldToDeviceYRel( GetTransform().Get_scaleY() * height ) );
866 
867  double hx, hy;
868  GetUserToDeviceTransform().TransformPoint( x, y, hx, hy );
869  int devicex = ( int ) ( hx - devicew / 2.0 ); //devicex of projected (imaginairy) image
870  int devicey = ( int ) ( hy - deviceh / 2.0 ); //devicey of projected (imaginairy) image
871 
872  // for drawing transparency
873  bool imgHasMask = image.HasMask();
874 
875  if ( devicew == 0 || deviceh == 0 )
876  return;
877 
878  double sx = image.GetWidth() / ( double ) devicew;
879  double sy = image.GetHeight() / ( double ) deviceh;
880 
881  //don't scale what we do not need, therefore get a subimage
882  wxRect clipped = m_clipboxdev;
883  clipped.Intersect( wxRect( devicex, devicey, devicew, deviceh ) );
884  int deviceClipX = clipped.GetX();
885  int deviceClipY = clipped.GetY();
886  int deviceClipW = clipped.GetWidth();
887  int deviceClipH = clipped.GetHeight();
888  // translate/rescale this to image coordinates
889  clipped.SetX( ( int ) ( ( clipped.GetX() - devicex ) * sx ) );
890  clipped.SetY( ( int ) ( ( clipped.GetY() - devicey ) * sy ) );
891  clipped.SetWidth( ( int ) ( clipped.GetWidth() * sx ) );
892  clipped.SetHeight( ( int ) ( clipped.GetHeight() * sy ) );
893 
894  //if the subimage image is so small (e.g. extreme zoomin), just draw a rectangle
895  if ( clipped.GetWidth() < 1 || clipped.GetHeight() < 1 )
896  {
897  m_renderDC->DrawRectangle( devicex, devicey, devicew, deviceh );
898  return;
899  }
900 
901  if ( deviceClipW != devicew || deviceClipH != deviceh )
902  image = image.GetSubImage( clipped );
903 
904  // now we first scale to screen projected size, often limits the amount of pixels to draw
905  // when size is smaller then original pixel size.
906  image.Rescale( deviceClipW, deviceClipH );//, wxIMAGE_QUALITY_HIGH );
907 
908  // we can not draw images, so first make it a bitmap, slow !
909  wxBitmap Bitmap( image );
910 
911  if ( m_drawstyle == a2dFILLED )
912  {
913  wxMemoryDC MemoryDc;
914  MemoryDc.SelectObject( Bitmap );
915  // Copy the pre-stretched bitmap to the display device.
916  m_renderDC->Blit( deviceClipX, deviceClipY, deviceClipW, deviceClipH, &MemoryDc, 0, 0, wxCOPY, imgHasMask );
917  }
918  else
919  {
920  m_renderDC->DrawRectangle( devicex, devicey, devicew, deviceh );
921  }
922  /*
923  image.Rescale( devicew, deviceh );
924 
925  // we can not draw images, so first make it a bitmap, slow !
926  wxBitmap Bitmap( image );
927 
928  if ( m_drawstyle == a2dFILLED )
929  {
930  wxMemoryDC MemoryDc;
931  MemoryDc.SelectObject( Bitmap );
932  // Copy the pre-stretched bitmap to the display device.
933  m_renderDC->Blit( devicex, devicey, devicew, deviceh, &MemoryDc, 0, 0, wxCOPY, imgHasMask );
934  }
935  else
936  {
937  m_renderDC->DrawRectangle( devicex, devicey, devicew, deviceh );
938  }
939  */
940 }
941 
942 void a2dDcDrawer::SetLogicalFunction( wxRasterOperationMode function )
943 {
944 #if __WXGTK__
945  if ( m_renderDC && !wxDynamicCast( m_renderDC, wxPostScriptDC ) )
946  m_renderDC->SetLogicalFunction( function );
947 #else
948  if ( m_renderDC )
949  m_renderDC->SetLogicalFunction( function );
950 #endif
951 }
952 
953 /*
954 void a2dDcDrawer::DrawImage( const wxImage& imagein, double x, double y, double width, double height, wxUint8 Opacity )
955 {
956  if ( m_disableDrawing )
957  return;
958 
959  wxASSERT_MSG( m_renderDC, wxT("no renderDc set") );
960 
961  wxPoint centr( (int) width/2, (int) height/2); //this doesn't make any difference (BUG?)
962  //anyway the rotation center is the middle of the image
963 
964  double angle = m_usertoworld.GetRotation();
965 
966  wxImage image = imagein;
967 
968  if ( angle != 0)
969  {
970  if ( m_yaxis )
971  image = imagein.Rotate( angle/180.0 * wxPI, centr, true, NULL );
972  else
973  image = imagein.Rotate(-angle/180.0 * wxPI, centr, true, NULL );
974  }
975 
976  int orgdevicew,devicew,orgdeviceh,deviceh;
977  int imagew = image.GetWidth();
978  int imageh = image.GetHeight();
979  orgdevicew = devicew = WorldToDeviceXRel( m_usertoworld.Get_scaleX()*width );
980  orgdeviceh = deviceh = abs(WorldToDeviceYRel( m_usertoworld.Get_scaleY()*height ));
981 
982  double hx,hy;
983  GetUserToDeviceTransform().TransformPoint( x, y, hx, hy );
984  int devicex = (int) (hx - devicew/2.0); //devicex of projected (imaginairy) image
985  int devicey = (int) (hy - deviceh/2.0); //devicey of projected (imaginairy) image
986 
987  int clipx;
988  int clipy;
989  int clipwidth;
990  int clipheight;
991  m_clip.GetBox(clipx, clipy, clipwidth, clipheight);
992 
993  int mindx=0; //start in projected (imaginairy) image
994  int mindy=0; //start in projected (imaginiairy) image
995 
996  // clip to clipping area
997  if (devicex < clipx)
998  {
999  mindx = clipx-devicex;
1000  devicew -= clipx-devicex;
1001  }
1002  if (devicew <= 0) return;
1003 
1004  if (devicey < clipy)
1005  {
1006  mindy = clipy-devicey;
1007  deviceh -= clipy-devicey;
1008  }
1009  if (deviceh <= 0) return;
1010 
1011  if (devicex+orgdevicew >= clipx+clipwidth)
1012  {
1013  devicew -= devicex + orgdevicew - (clipx + clipwidth);
1014  }
1015  if (devicew <= 0) return;
1016 
1017  if (devicey+orgdeviceh >= clipy+clipheight)
1018  {
1019  deviceh -= devicey + orgdeviceh - (clipy + clipheight);
1020  }
1021  if (deviceh <= 0) return;
1022 
1023  //now the projected image to be drawn at the given width and height in world coordinates,
1024  //is clipped to the current clip rectangle.
1025  //Depending on the projection size and the actual size of the image,
1026  //we decide to draw ALL pixels in the projected part of the image,
1027  //or we draw the pixels from the original image as rectangles.
1028 
1029 
1030  int pixelwidth = (int) (orgdevicew/(double)imagew );
1031 
1032  // for drawing transparency
1033  bool imgHasMask = image.HasMask();
1034 
1035  //i don't know what the optimum is but at least 2 or higher
1036  if ( pixelwidth > 50000)
1037  {
1038  unsigned char rMask = ' ';
1039  unsigned char gMask = ' ';
1040  unsigned char bMask = ' ';
1041 
1042  // if image has a mask, we ask for the rgb value of mask
1043  if (imgHasMask)
1044  {
1045  rMask = image.GetMaskRed();
1046  gMask = image.GetMaskGreen();
1047  bMask = image.GetMaskBlue();
1048  }
1049 
1050  wxBrush pixelbrush;
1051  m_renderDC->SetPen( *wxTRANSPARENT_PEN );
1052  // We do (x, y) -> (x, y)*oldSize/newSize
1053  for ( long j = mindy; j < mindy+deviceh; j+=pixelwidth )
1054  {
1055  long yimage = (j * imageh) / orgdeviceh;
1056 
1057  for ( long i = mindx; i < mindx+devicew; i+=pixelwidth )
1058  {
1059  long ximage = (i * imagew) / orgdevicew;
1060 
1061  unsigned char r = image.GetRed(ximage,yimage);
1062  unsigned char g = image.GetGreen(ximage,yimage);
1063  unsigned char b = image.GetBlue(ximage,yimage);
1064 
1065  // Drawing is only necessary if we don't draw transparent
1066  if (!(imgHasMask && r == rMask && g == gMask && b == bMask) )
1067  {
1068  wxColour gradcol(r, g, b);
1069  pixelbrush.SetColour(gradcol);
1070  m_renderDC->SetBrush(pixelbrush);
1071  DevDrawRectangle( devicex + i , devicey + j, pixelwidth, pixelwidth);
1072  }
1073  }
1074  }
1075  //restore since drawer should not change fill or stroke itself
1076  SetDrawerStroke( m_currentstroke );
1077  SetDrawerFill( m_activefill );
1078  }
1079  else
1080  {
1081 
1082  wxRect SubImageRect( (mindx * imagew) / orgdevicew,
1083  (mindy * imageh) / orgdeviceh,
1084  (devicew * imagew) / orgdevicew,
1085  (deviceh * imageh) / orgdeviceh
1086  );
1087 
1088  if ( SubImageRect.GetHeight() <= 0 || SubImageRect.GetWidth() <= 0 )
1089  return;
1090 
1091  wxImage SubImage = image.GetSubImage(SubImageRect);
1092  // Scale it properly.
1093  SubImage.Rescale( devicew, deviceh);
1094  // Generate a bitmap and a memory device context and select the bitmap
1095  // into the memory device context.
1096  wxBitmap Bitmap( SubImage );
1097 
1098  wxMemoryDC MemoryDc;
1099  MemoryDc.SelectObject(Bitmap);
1100  // Copy the pre-stretched bitmap to the display device.
1101  m_renderDC->Blit( devicex + mindx, devicey + mindy,
1102  devicew, deviceh,
1103  &MemoryDc, 0, 0, wxCOPY, imgHasMask);
1104 
1105  // / *
1106  // We do (x, y) -> (x, y)*oldSize/newSize
1107  for ( long j = mindy; j < mindy+deviceh; j++ )
1108  {
1109  long yimage = (j * imageh) / orgdeviceh;
1110 
1111  for ( long i = mindx; i < mindx+devicew; i++ )
1112  {
1113  long ximage = (i * imagew) / orgdevicew;
1114 
1115  unsigned char r = image.GetRed(ximage,yimage);
1116  unsigned char g = image.GetGreen(ximage,yimage);
1117  unsigned char b = image.GetBlue(ximage,yimage);
1118 
1119  DeviceDrawPixel( devicex + i , devicey + j, r, g, b);
1120  }
1121  }
1122  ///
1123  }
1124 }
1125 */
1126 
1127 
1128 void a2dDcDrawer::DrawImage( const a2dImageRGBA& image, double x, double y, double width, double height, wxUint8 Opacity )
1129 {
1130  if ( m_disableDrawing )
1131  return;
1132 
1133  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
1134 
1135  wxPoint centr( ( int ) width / 2, ( int ) height / 2 ); //this doesn't make any difference (BUG?)
1136  //anyway the rotation center is the middle of the image
1137 
1138  int devicew, deviceh;
1139  devicew = WorldToDeviceXRel( GetTransform().Get_scaleX() * width );
1140  deviceh = abs( WorldToDeviceYRel( GetTransform().Get_scaleY() * height ) );
1141 
1142  double hx, hy;
1143  GetUserToDeviceTransform().TransformPoint( x, y, hx, hy );
1144  int devicex = ( int ) ( hx - devicew / 2.0 ); //devicex of projected (imaginairy) image
1145  int devicey = ( int ) ( hy - deviceh / 2.0 ); //devicey of projected (imaginairy) image
1146 
1147  int clipx;
1148  int clipy;
1149  int clipwidth;
1150  int clipheight;
1151  m_clip.GetBox( clipx, clipy, clipwidth, clipheight );
1152 
1153 
1154 
1155  if ( devicew == 0 || deviceh == 0 )
1156  return;
1157  /*
1158  // now we first scale to screen projected size, often limits the amount of pixels to draw
1159  // when size is smaller then original pixel size.
1160  image.Rescale( devicew, deviceh);
1161 
1162  // we can not draw images, so first make it a bitmap, slow !
1163  wxBitmap Bitmap( image );
1164 
1165  if ( m_drawstyle == a2dFILLED )
1166  {
1167  wxMemoryDC MemoryDc;
1168  MemoryDc.SelectObject(Bitmap);
1169  // Copy the pre-stretched bitmap to the display device.
1170  m_renderDC->Blit( devicex, devicey, devicew, deviceh, &MemoryDc, 0, 0, wxCOPY, imgHasMask);
1171  }
1172  else
1173  {
1174  m_renderDC->DrawRectangle( devicex, devicey, devicew, deviceh );
1175  }
1176  */
1177 }
1178 
1180 {
1181  if ( m_disableDrawing )
1182  return;
1183 
1184  unsigned int segments = 0;
1185 
1186  double tstep = 1 / ( double ) SPLINE_STEP;
1187  unsigned int i;
1188  for ( i = 0; i < path->size(); i++ )
1189  {
1190  a2dVpathSegmentPtr seg = path->operator[]( i );
1191  switch ( seg->GetType() )
1192  {
1193  case a2dPATHSEG_CBCURVETO:
1195  segments += SPLINE_STEP;
1196  break;
1197 
1198  case a2dPATHSEG_QBCURVETO:
1200  segments += SPLINE_STEP;
1201  break;
1202 
1203  case a2dPATHSEG_ARCTO:
1205  {
1206  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
1207 
1208  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1209 
1210  if ( cseg->CalcR( path->operator[]( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1211  {
1212  double dphi;
1213  unsigned int circlesegments;
1214  double radiusDev = m_usertodevice.TransformDistance( radius );
1215  Aberration( m_displayaberration, phit, radiusDev , dphi, circlesegments );
1216  segments += circlesegments + 1;
1217  }
1218  else
1219  segments ++;
1220  }
1221  break;
1222  default:
1223  segments++;
1224 
1225  }
1226  }
1227 
1228  //TODO memory error because of wrong calculation of segments?? for the moment *2 to be save
1229  m_cpointsDouble.resize( segments * 2 );
1230 
1231  double x, y;
1232  bool move = false;
1233  int count = 0;
1234  bool nostrokeparts = false;
1235 
1236  //first draw as much as possible ( nostroke parts may stop this first round )
1237  for ( i = 0; i < path->size(); i++ )
1238  {
1239  a2dVpathSegmentPtr seg = path->operator[]( i );
1240  switch ( seg->GetType() )
1241  {
1242  case a2dPATHSEG_MOVETO:
1243  if ( count == 0 )
1244  {
1245  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
1246  m_cpointsDouble[count].x = x;
1247  m_cpointsDouble[count].y = y;
1248  count++;
1249  }
1250  else
1251  {
1252  i--;
1253  move = true;
1254  }
1255  break;
1256 
1257  case a2dPATHSEG_LINETO:
1258  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
1259  m_cpointsDouble[count].x = x;
1260  m_cpointsDouble[count].y = y;
1261  count++;
1262  break;
1264  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
1265  m_cpointsDouble[count].x = x;
1266  m_cpointsDouble[count].y = y;
1267  count++;
1268  nostrokeparts = true;
1269  break;
1270 
1272  nostrokeparts = true;
1273  case a2dPATHSEG_CBCURVETO:
1274  {
1275  double xw, yw;
1276 
1277  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
1278  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
1279  a2dVpathCBCurveSegment* cseg = ( a2dVpathCBCurveSegment* ) seg.Get();
1280 
1281  int step;
1282  double t = 0;
1283  for ( step = 0; step <= SPLINE_STEP; step++ )
1284  {
1285  xw = xwl * pow( 1 - t, 3 ) + cseg->m_x2 * pow( 1 - t, 2 ) * t * 3 + cseg->m_x3 * ( 1 - t ) * t * t * 3 + cseg->m_x1 * pow( t, 3 );
1286  yw = ywl * pow( 1 - t, 3 ) + cseg->m_y2 * pow( 1 - t, 2 ) * t * 3 + cseg->m_y3 * ( 1 - t ) * t * t * 3 + cseg->m_y1 * pow( t, 3 );
1287  m_usertodevice.TransformPoint( xw, yw, x, y );
1288  m_cpointsDouble[count].x = x;
1289  m_cpointsDouble[count].y = y;
1290  count++;
1291  t = t + tstep;
1292  }
1293  }
1294  break;
1295 
1297  nostrokeparts = true;
1298  case a2dPATHSEG_QBCURVETO:
1299  {
1300  double xw, yw;
1301 
1302  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
1303  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
1304  a2dVpathQBCurveSegment* cseg = ( a2dVpathQBCurveSegment* ) seg.Get();
1305 
1306  int step;
1307  double t = 0;
1308  for ( step = 0; step <= SPLINE_STEP; step++ )
1309  {
1310  xw = xwl * pow( 1 - t, 2 ) + cseg->m_x2 * ( 1 - t ) * t * 2 + cseg->m_x1 * pow( t, 2 );
1311  yw = ywl * pow( 1 - t, 2 ) + cseg->m_y2 * ( 1 - t ) * t * 2 + cseg->m_y1 * pow( t, 2 );
1312  m_usertodevice.TransformPoint( xw, yw, x, y );
1313  m_cpointsDouble[count].x = x;
1314  m_cpointsDouble[count].y = y;
1315  count++;
1316  t = t + tstep;
1317  }
1318  }
1319  break;
1320 
1322  nostrokeparts = true;
1323  case a2dPATHSEG_ARCTO:
1324  {
1325  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
1326 
1327  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1328 
1329  if ( cseg->CalcR( path->operator[]( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1330  {
1331  double dphi;
1332  unsigned int segments;
1333  double radiusDev = m_usertodevice.TransformDistance( radius );
1334  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
1335 
1336  double theta = beginrad;
1337  unsigned int step;
1338 
1339  double x, y;
1340  for ( step = 0; step < segments + 1; step++ )
1341  {
1342  m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
1343  m_cpointsDouble[count].x = x;
1344  m_cpointsDouble[count].y = y;
1345  count++;
1346  theta = theta + dphi;
1347  }
1348  }
1349  else
1350  {
1351  double x, y;
1352  m_usertodevice.TransformPoint( cseg->m_x1, cseg->m_y1, x, y );
1353  m_cpointsDouble[count].x = x;
1354  m_cpointsDouble[count].y = y;
1355  count++;
1356  }
1357  }
1358  default:
1359  break;
1360  break;
1361  }
1362 
1363  if ( move )
1364  {
1365  DeviceDrawLines( count, false );
1366  move = false;
1367  count = 0;
1368  }
1369  else if ( seg->GetClose() != a2dPATHSEG_END_OPEN )
1370  {
1371  if ( nostrokeparts || seg->GetClose() == a2dPATHSEG_END_CLOSED_NOSTROKE )
1372  {
1373  a2dStroke stroke = m_activestroke;
1375  DeviceDrawPolygon( count, false, wxODDEVEN_RULE );
1376  SetDrawerStroke( stroke );
1377  nostrokeparts = true;
1378  }
1379  else
1380  {
1381  DeviceDrawPolygon( count, false, wxODDEVEN_RULE );
1382  }
1383 
1384  move = false;
1385  count = 0;
1386  }
1387  else if ( i == path->size() - 1 ) //last segment?
1388  {
1389  DeviceDrawLines( count, false );
1390  }
1391  }
1392 
1393  if ( nostrokeparts )
1394  {
1395  move = false;
1396  count = 0;
1397  nostrokeparts = false;
1398 
1399  double lastmovex = 0;
1400  double lastmovey = 0;
1401 
1402  for ( i = 0; i < path->size(); i++ )
1403  {
1404  a2dVpathSegmentPtr seg = path->operator[]( i );
1405  switch ( seg->GetType() )
1406  {
1407  case a2dPATHSEG_MOVETO:
1408  if ( count == 0 )
1409  {
1410  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
1411  m_cpointsDouble[count].x = x;
1412  m_cpointsDouble[count].y = y;
1413  lastmovex = m_cpointsDouble[count].x;
1414  lastmovey = m_cpointsDouble[count].y;
1415  count++;
1416  }
1417  else
1418  {
1419  i--;
1420  move = true;
1421  }
1422  break;
1423 
1424  case a2dPATHSEG_LINETO:
1425  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
1426  m_cpointsDouble[count].x = x;
1427  m_cpointsDouble[count].y = y;
1428  count++;
1429  break;
1430 
1435  if ( count == 0 )
1436  {
1437  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
1438  m_cpointsDouble[count].x = x;
1439  m_cpointsDouble[count].y = y;
1440  count++;
1441  }
1442  else
1443  {
1444  i--;
1445  nostrokeparts = true;
1446  }
1447  break;
1448 
1449  case a2dPATHSEG_CBCURVETO:
1450  {
1451  double xw, yw;
1452 
1453  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
1454  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
1455  a2dVpathCBCurveSegment* cseg = ( a2dVpathCBCurveSegment* ) seg.Get();
1456 
1457  int step;
1458  double t = 0;
1459  for ( step = 0; step <= SPLINE_STEP; step++ )
1460  {
1461  xw = xwl * pow( 1 - t, 3 ) + cseg->m_x2 * pow( 1 - t, 2 ) * t * 3 + cseg->m_x3 * ( 1 - t ) * t * t * 3 + cseg->m_x1 * pow( t, 3 );
1462  yw = ywl * pow( 1 - t, 3 ) + cseg->m_y2 * pow( 1 - t, 2 ) * t * 3 + cseg->m_y3 * ( 1 - t ) * t * t * 3 + cseg->m_y1 * pow( t, 3 );
1463  m_usertodevice.TransformPoint( xw, yw, x, y );
1464  m_cpointsDouble[count].x = x;
1465  m_cpointsDouble[count].y = y;
1466  count++;
1467  t = t + tstep;
1468  }
1469  }
1470  break;
1471 
1472  case a2dPATHSEG_QBCURVETO:
1473  {
1474  double xw, yw;
1475 
1476  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
1477  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
1478  a2dVpathQBCurveSegment* cseg = ( a2dVpathQBCurveSegment* ) seg.Get();
1479 
1480  int step;
1481  double t = 0;
1482  for ( step = 0; step <= SPLINE_STEP; step++ )
1483  {
1484  xw = xwl * pow( 1 - t, 2 ) + cseg->m_x2 * ( 1 - t ) * t * 2 + cseg->m_x1 * pow( t, 2 );
1485  yw = ywl * pow( 1 - t, 2 ) + cseg->m_y2 * ( 1 - t ) * t * 2 + cseg->m_y1 * pow( t, 2 );
1486  m_usertodevice.TransformPoint( xw, yw, x, y );
1487  m_cpointsDouble[count].x = x;
1488  m_cpointsDouble[count].y = y;
1489  count++;
1490  t = t + tstep;
1491  }
1492  }
1493  break;
1494 
1495  case a2dPATHSEG_ARCTO:
1496  {
1497  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
1498 
1499  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1500 
1501  if ( cseg->CalcR( path->operator[]( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1502  {
1503  double dphi;
1504  unsigned int segments;
1505  double radiusDev = m_usertodevice.TransformDistance( radius );
1506  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
1507 
1508  double theta = beginrad;
1509  unsigned int step;
1510 
1511  double x, y;
1512  for ( step = 0; step < segments + 1; step++ )
1513  {
1514  m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
1515  m_cpointsDouble[count].x = x;
1516  m_cpointsDouble[count].y = y;
1517  count++;
1518  theta = theta + dphi;
1519  }
1520  }
1521  else
1522  {
1523  double x, y;
1524  m_usertodevice.TransformPoint( cseg->m_x1, cseg->m_y1, x, y );
1525  m_cpointsDouble[count].x = x;
1526  m_cpointsDouble[count].y = y;
1527  count++;
1528  }
1529  }
1530  default:
1531  break;
1532 
1533  break;
1534  }
1535 
1536  if ( move || nostrokeparts )
1537  {
1538  DeviceDrawLines( count, false );
1539  move = false;
1540  nostrokeparts = false;
1541  count = 0;
1542  }
1543  else if ( seg->GetClose() != a2dPATHSEG_END_OPEN )
1544  {
1545  if ( seg->GetClose() == a2dPATHSEG_END_CLOSED )
1546  {
1547  m_cpointsDouble[count].x = lastmovex;
1548  m_cpointsDouble[count].y = lastmovey;
1549  count++;
1550  }
1551  DeviceDrawLines( count, false );
1552  nostrokeparts = false;
1553  move = false;
1554  count = 0;
1555  }
1556  else if ( i == path->size() )
1557  {
1558  DeviceDrawLines( count, false );
1559  }
1560  }
1561  }
1562 
1563 }
1564 
1565 void a2dDcDrawer::DrawPolyPolygon( a2dListOfa2dVertexList polylist, wxPolygonFillMode fillStyle )
1566 {
1567  if ( m_disableDrawing )
1568  return;
1569 
1570  a2dBoundingBox devbox;
1571  bool smallPoly = false;
1572  int j = 0;
1573  int totalsize = 0;
1574  std::vector<int> pcount;
1575  pcount.resize( polylist.size() );
1576 
1577  m_cpointsInt.clear();
1578  for( a2dListOfa2dVertexList::iterator iterp = polylist.begin(); iterp != polylist.end(); iterp++ )
1579  {
1580  int segments = ToDeviceLines( ( *iterp ).Get(), devbox, smallPoly );
1581  pcount[ j++ ] = segments;
1582  m_cpointsInt.resize( totalsize + segments );
1583  // Convert to integer coords by rounding
1584  for ( int i = 0; i < segments; i++ )
1585  {
1586  m_cpointsInt[ totalsize + i ].x = Round( m_cpointsDouble[i].x );
1587  m_cpointsInt[ totalsize + i ].y = Round( m_cpointsDouble[i].y );
1588  }
1589  totalsize += segments;
1590  }
1591 
1592  if ( m_cpointsInt.size() == 0 )
1593  return;
1594 
1595  m_renderDC->DrawPolyPolygon( j, &pcount[0], &m_cpointsInt[0], 0, 0, fillStyle );
1596 
1597 }
1598 
1599 void a2dDcDrawer::DrawCircle( double xc, double yc, double radius )
1600 {
1601  if ( m_disableDrawing )
1602  return;
1603 
1604  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR ||
1607  {
1608  }
1609  else if ( m_usertodevice.IsIdentity() )
1610  {
1611  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
1612  m_renderDC->DrawCircle( Round( xc ), Round( yc ), Round( radius ) );
1613  return;
1614  }
1615 
1616  if ( radius == 0 )
1617  {
1618  double x, y;
1619  m_usertodevice.TransformPoint( xc, yc, x, y );
1620  m_renderDC->DrawPoint( Round( x ), Round( y ) );
1621  return;
1622  }
1623 
1624  if ( m_activefill.GetType() != a2dFILL_GRADIENT_FILL_LINEAR &&
1627  )
1628  {
1629  /* draw native (hardware accelerated) circle/ellipse when possible.
1630  Special cases, where native circles may apply:
1631  only rotated if: m(0,0) == m(1,1) && m(1,0) == m(0,1)
1632  stretched and not rotated: m(0,1) == 0.0 && m(1,0) == 0.0;
1633  stretched and 90deg rotated: m(0,0) == 0.0 && m(1,1) == 0.0;
1634  */
1635  double m00 = fabs( m_usertodevice.GetValue( 0, 0 ) );
1636  double m11 = fabs( m_usertodevice.GetValue( 1, 1 ) );
1637  double m10 = fabs( m_usertodevice.GetValue( 1, 0 ) );
1638  double m01 = fabs( m_usertodevice.GetValue( 0, 1 ) );
1639 
1640  /* the use of == in the next statement is valid, even though it is a comparision between doubles.
1641  This is because when no shearing/stretching has taken place, the values have had exactly
1642  the same values and multiplications. Therefore these are exactly equal.
1643  */
1644  if ( m00 == m11 && m10 == m01 )
1645  {
1646  // only rotated
1647  double x, y;
1648  m_usertodevice.TransformPoint( xc, yc, x, y );
1649 #if defined(__WXMSW__)
1650  m_renderDC->DrawCircle( Round( x ), Round( y ), Round( _hypot( m00, m01 ) * radius ) );
1651 #else
1652  m_renderDC->DrawCircle( Round( x ), Round( y ), Round( hypot( m00, m01 ) * radius ) );
1653 #endif
1654  }
1655  else if ( ( 100.0 * m10 < m00 ) && ( 100.0 * m01 < m11 ) )
1656  {
1657  // since checking for == is dangerous with doubles, a check for small angles is used instead
1658  // 100 * m10 < m00 actually means: rotation angle < 0.5 degrees
1659 
1660  // stretched but not rotated
1661  double x, y, rx, ry;
1662  m_usertodevice.TransformPoint( xc, yc, x, y );
1663  rx = m00 * radius;
1664  ry = m11 * radius;
1665  m_renderDC->DrawEllipse( Round( x - rx ), Round( y - ry ), Round( 2.0 * rx ), Round( 2.0 * ry ) );
1666  }
1667  else if ( ( 100.0 * m00 < m10 ) && ( 100.0 * m11 < m01 ) )
1668  {
1669  // stretched and 90 degrees rotated
1670  double x, y, rx, ry;
1671  m_usertodevice.TransformPoint( xc, yc, x, y );
1672  rx = m10 * radius;
1673  ry = m01 * radius;
1674  m_renderDC->DrawEllipse( Round( x - rx ), Round( y - ry ), Round( 2.0 * rx ), Round( 2.0 * ry ) );
1675  }
1676  else
1677  {
1678  // use a polygon ellipse.
1679  DrawEllipse( xc, yc, 2.0 * radius, 2.0 * radius );
1680  }
1681  }
1682  else
1683  {
1684  // use a polygon ellipse.
1685  a2dDrawer2D::DrawEllipse( xc, yc, 2.0 * radius, 2.0 * radius );
1686  }
1687 }
1688 
1689 void a2dDcDrawer::DrawEllipse( double xc, double yc, double width, double height )
1690 {
1691  if ( m_disableDrawing )
1692  return;
1693 
1694  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR ||
1697  {
1698  a2dDrawer2D::DrawEllipse( xc, yc, width, height );
1699  }
1700  else if ( m_usertodevice.IsIdentity() )
1701  {
1702  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
1703  m_renderDC->DrawEllipse( Round( xc - width / 2.0 ), Round( yc - height / 2.0 ), Round( width ), Round( height ) );
1704  }
1705  else
1706  a2dDrawer2D::DrawEllipse( xc, yc, width, height );
1707 }
1708 
1709 void a2dDcDrawer::DrawLine( double x1, double y1, double x2, double y2 )
1710 {
1711  if ( m_disableDrawing )
1712  return;
1713 
1714  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR ||
1717  {
1718  a2dDrawer2D::DrawLine( x1, y1, x2, y2 );
1719  }
1720  else if ( m_usertodevice.IsIdentity() )
1721  {
1722  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
1723  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y2 ) );
1724  }
1725  else
1726  a2dDrawer2D::DrawLine( x1, y1, x2, y2 );
1727 }
1728 
1729 
1730 void a2dDcDrawer::DrawRoundedRectangle( double x, double y, double width, double height, double radius, bool pixelsize )
1731 {
1732  if ( m_disableDrawing )
1733  return;
1734 
1735  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR ||
1738  {
1739  a2dDrawer2D::DrawRoundedRectangle( x, y, width, height, radius, pixelsize );
1740  }
1741  else if ( m_usertodevice.IsIdentity() )
1742  {
1743  if ( pixelsize )
1744  {
1745  width = DeviceToWorldXRel( width );
1746  height = DeviceToWorldYRel( height );
1747  radius = DeviceToWorldXRel( radius );
1748  if( m_yaxis )
1749  height = -height;
1750  }
1751 
1752  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
1753  m_renderDC->DrawRoundedRectangle( Round( x ), Round( y ), Round( width ), Round( height ), Round( radius ) );
1754  }
1755  else
1756  a2dDrawer2D::DrawRoundedRectangle( x, y, width, height, radius, pixelsize );
1757 }
1758 
1759 void a2dDcDrawer::DrawPoint( double xc, double yc )
1760 {
1761  if ( m_disableDrawing )
1762  return;
1763 
1764  double xt, yt;
1765  GetUserToDeviceTransform().TransformPoint( xc, yc, xt, yt );
1767 
1768  //m_renderDC->DrawPoint( Round( xt ), Round( yt ) );
1769 }
1770 
1771 void a2dDcDrawer::DeviceDrawPolygon( unsigned int n, bool spline, wxPolygonFillMode fillStyle )
1772 {
1773  if ( m_disableDrawing )
1774  return;
1775 
1776  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
1777 
1778  if ( spline )
1779  n = ConvertSplinedPolygon2( n );
1780 
1781  wxPoint* int_cpts = _convertToIntPointCache( n, &m_cpointsDouble[0] );
1782 
1783  // filter the no filling, in order to draw polylines instead
1784  if ( IsStrokeOnly() )
1785  {
1786  if ( n == 2 )
1787  {
1788  //Draw polyline instead
1789  m_renderDC->DrawLines( n, int_cpts );
1790  // in invert mode do not draw the line back since it will result in drawing nothing.
1792  m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n - 1].x, int_cpts[n - 1].y );
1793  }
1794  else
1795  {
1796  // i assume drawpolygon makes effective use of the fact that the polygon is transparent/not filled,
1797  // drawing just lines shows no difference in speed on MSW
1798 #if defined(__WXMSW__)
1799 #if wxCHECK_VERSION(2,9,0)
1800  wxMSWDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
1801  WXHDC hdc = dcimpl->GetHDC();
1802 #else
1803  WXHDC hdc = m_renderDC->GetHDC();
1804 #endif
1805  SetPolyFillMode( ( struct HDC__* ) hdc, fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING );
1806  //prevent to do things that are not needed (like bbox calculation and checking things)
1807  //This way is the most direct and fastest possible manner to draw a polygon using API
1808  ( void )Polygon( ( struct HDC__* ) hdc, ( POINT* )int_cpts, n );
1809 //#elif __WXGTK__
1810 #else
1811  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1812 #endif
1813 
1814  }
1815  }
1817  {
1818  FillPolygon( n, &m_cpointsDouble[0] );
1819 
1820  if ( IsStroked() )
1821  {
1822  m_renderDC->DrawLines( n, int_cpts );
1823  m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n - 1].x, int_cpts[n - 1].y );
1824  }
1825  }
1826  else if ( m_activefill.GetType() == a2dFILL_BITMAP && m_activefill.GetStyle() == a2dFILL_STIPPLE_MASK_OPAQUE_TRANSPARENT )
1827  {
1828 #if defined(__WXMSW__)
1829  m_renderDC->SetTextForeground( *wxBLACK );
1830  m_renderDC->SetTextBackground( *wxWHITE );
1831  m_renderDC->SetLogicalFunction( wxAND_INVERT );
1832 
1833  //the above
1834  COLORREF colFgOld, colBgOld;
1835 
1836 #if wxCHECK_VERSION(2,9,0)
1837  wxMSWDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
1838  WXHDC hdc = dcimpl->GetHDC();
1839 #else
1840  WXHDC hdc = m_renderDC->GetHDC();
1841 #endif
1842 
1843  colBgOld = ::GetBkColor( ( struct HDC__* ) hdc );
1844  colFgOld = ::GetTextColor( ( struct HDC__* ) hdc );
1845 
1846  //just the opposite from what is expected see help on pattern brush
1847  // 1 in mask becomes bk color
1848  ::SetBkColor( ( struct HDC__* ) hdc, m_renderDC->GetTextForeground().GetPixel() );
1849  //just the opposite from what is expected
1850  // 0 in mask becomes text color
1851  ::SetTextColor( ( struct HDC__* ) hdc, m_renderDC->GetTextBackground().GetPixel() );
1852 
1853  int prev = SetPolyFillMode( ( struct HDC__* ) hdc, WINDING );
1854  ( void )Polygon( ( struct HDC__* ) hdc, ( POINT* )int_cpts, n );
1855 
1856  // Set background and foreground colors for fill pattern
1857  //the previous blacked out pixels are now merged with the layer color
1858  //while the non blacked out pixels stay as they are.
1859  m_renderDC->SetTextForeground( *wxBLACK );
1860  //now define what will be the color of the fillpattern parts that are not transparent
1861  m_renderDC->SetTextBackground( m_activefill.GetColour() );
1862  m_renderDC->SetLogicalFunction( wxOR );
1863 
1864  //just the opposite from what is expected see help on pattern brush
1865  // 1 in mask becomes bk color
1866  ::SetBkColor( ( struct HDC__* ) hdc, m_renderDC->GetTextForeground().GetPixel() );
1867  //just the opposite from what is expected
1868  // 0 in mask becomes text color
1869  ::SetTextColor( ( struct HDC__* ) hdc, m_renderDC->GetTextBackground().GetPixel() );
1870  ( void )Polygon( ( struct HDC__* ) hdc, ( POINT* )int_cpts, n );
1871  SetPolyFillMode( ( struct HDC__* ) hdc, prev );
1872 
1873  // restore the colours we changed
1874  ::SetBkMode( ( struct HDC__* ) hdc, TRANSPARENT );
1875  ::SetTextColor( ( struct HDC__* ) hdc, colFgOld );
1876  ::SetBkColor( ( struct HDC__* ) hdc, colBgOld );
1877 
1878  m_renderDC->SetLogicalFunction( wxCOPY );
1879  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
1880  m_renderDC->SetTextBackground( m_activefill.GetColour() );
1881 
1882  //now do the stroke drawing
1883  if ( IsStroked() )
1884  {
1885  m_renderDC->DrawLines( n, int_cpts );
1886  m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n - 1].x, int_cpts[n - 1].y );
1887  }
1888 
1889 //#elif __WXGTK__
1890 #else
1891 
1892  if ( !wxDynamicCast( m_renderDC, wxPostScriptDC ) )
1893  {
1894  wxPen dcpen( m_activestroke.GetColour(), ( int ) m_activestroke.GetWidth(), wxSOLID );
1895  if ( !m_activestroke.GetPixelStroke() )
1896  dcpen.SetWidth( ( int )WorldToDeviceXRel( m_activestroke.GetWidth() ) );
1897  m_renderDC->SetPen( dcpen );
1898 
1899  m_renderDC->SetTextForeground( *wxBLACK );
1900  m_renderDC->SetTextBackground( *wxWHITE );
1901  m_renderDC->SetLogicalFunction( wxAND_INVERT );
1902  // BLACK OUT the opaque pixels and leave the rest as is
1903  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1904  // Set background and foreground colors for fill pattern
1905  //the previous blacked out pixels are now merged with the layer color
1906  //while the non blacked out pixels stay as they are.
1907  m_renderDC->SetTextForeground( *wxBLACK );
1908  //now define what will be the color of the fillpattern parts that are not transparent
1909  m_renderDC->SetTextBackground( m_activefill.GetColour() );
1910  m_renderDC->SetLogicalFunction( wxOR );
1911  //don't understand how but the outline is also depending on logicalfunction
1913  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1914  m_renderDC->SetLogicalFunction( wxCOPY );
1915  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
1916  m_renderDC->SetTextBackground( m_activefill.GetColour() );
1917  }
1918  else
1919  {
1920  wxPen dcpen( m_activestroke.GetColour(), ( int ) m_activestroke.GetWidth(), wxSOLID );
1921  if ( !m_activestroke.GetPixelStroke() )
1922  dcpen.SetWidth( ( int )WorldToDeviceXRel( m_activestroke.GetWidth() ) );
1923  m_renderDC->SetPen( dcpen );
1924 
1925  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1926  }
1927  //now do the stroke drawing
1928  if ( IsStroked() )
1929  {
1930  m_renderDC->DrawLines( n, int_cpts );
1931  m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n - 1].x, int_cpts[n - 1].y );
1932  }
1933 #endif
1934  }
1935  else if ( m_activefill.GetType() == a2dFILL_BITMAP &&
1936  ( m_activefill.GetStyle() == a2dFILL_STIPPLE ||
1938  )
1939  {
1940  m_renderDC->SetTextForeground( m_activefill.GetColour() );
1941  m_renderDC->SetTextBackground( m_activefill.GetColour2() );
1942  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1943  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
1944  m_renderDC->SetTextBackground( m_activefill.GetColour() );
1945  }
1946  else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
1947  {
1948  wxBrush dcbrush( m_activefill.GetColour2() );
1949  wxBrush cur_dcbrush = m_renderDC->GetBrush();
1950  m_renderDC->SetBrush( dcbrush );
1951  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1952  m_renderDC->SetBrush( cur_dcbrush );
1953  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1954  }
1955  else
1956  {
1957 #if defined(__WXMSW__)
1958  //prevent to do think that are not needed (like bbox calculation and checking things)
1959  //This way is the most direct and fastest possible manner to draw a polygon using API
1960 
1961  //SetPolyFillMode((struct HDC__ *) hdc,fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
1962  //(void)Polygon((struct HDC__ *) hdc, (POINT*)int_cpts, n);
1963  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1964 //#elif __WXGTK__
1965 #else
1966  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
1967 #endif
1968  }
1969 
1970  if ( IsStroked() && m_activestroke.GetType() == a2dSTROKE_OBJECT )
1971  {
1972  //we must make a copy of the device points now because recursive call
1973  //can be made in here, which will change the points stored in the drawer.
1974  //First point repeated extra since it is for outline
1975  wxRealPoint* copy = new wxRealPoint[n + 1];
1976  memcpy( copy, &m_cpointsDouble[0], n * sizeof( wxRealPoint ) );
1977  copy[n].x = m_cpointsDouble[0].x;
1978  copy[n].y = m_cpointsDouble[0].y;
1979 
1980  //!todo m_activestroke->Render( this, m_clipboxworld, n + 1, copy );
1981  delete [] copy;
1982  }
1983 }
1984 
1985 void a2dDcDrawer::DeviceDrawLines( unsigned int n, bool spline )
1986 {
1987  if ( m_disableDrawing )
1988  return;
1989 
1990  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
1991  if ( spline )
1992  n = ConvertSplinedPolyline2( n );
1993 
1994  wxPoint* int_cpts = _convertToIntPointCache( n, &m_cpointsDouble[0] );
1995 
1996  if ( n == 1 )
1997  m_renderDC->DrawCircle( int_cpts[0].x, int_cpts[0].y, 2 );
1998 // m_renderDC->DrawPoint( int_cpts[0].x, int_cpts[0].y );
1999  else
2000  {
2001  m_renderDC->DrawLines( n, int_cpts );
2002 #if defined(__WXMSW__)
2003  // Windows does not draw the last pixel if the pensize is 1.
2004  // especially disturbing for stroke fonts.
2005  if ( n > 1 && m_renderDC->GetPen().GetWidth() == 1 )
2006  m_renderDC->DrawPoint( int_cpts[n - 1].x, int_cpts[n - 1].y );
2007 #endif
2008  }
2009 }
2010 
2011 void a2dDcDrawer::DeviceDrawLine( double x1, double y1, double x2, double y2 )
2012 {
2013  if ( m_disableDrawing )
2014  return;
2015 
2016  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
2017 
2018  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y2 ) );
2019 }
2020 
2021 void a2dDcDrawer::DeviceDrawHorizontalLine( int x1, int y1, int x2, bool use_stroke_color )
2022 {
2023  if ( m_disableDrawing )
2024  return;
2025 
2026  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
2027 
2028  wxColour color;
2029  if ( use_stroke_color )
2030  {
2031  wxPen pen = m_renderDC->GetPen();
2033  m_renderDC->SetPen( wxPen( color ) );
2034  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y1 ) );
2035  m_renderDC->SetPen( pen );
2036  }
2037  else
2038  {
2039  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y1 ) );
2040  }
2041 }
2042 
2043 void a2dDcDrawer::DeviceDrawVerticalLine( int x1, int y1, int y2, bool use_stroke_color )
2044 {
2045  if ( m_disableDrawing )
2046  return;
2047 
2048  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
2049 
2050  wxColour color;
2051  if ( use_stroke_color )
2052  {
2053  wxPen pen = m_renderDC->GetPen();
2055  m_renderDC->SetPen( wxPen( color ) );
2056  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x1 ), Round( y2 ) );
2057  m_renderDC->SetPen( pen );
2058  }
2059  else
2060  {
2061  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x1 ), Round( y2 ) );
2062  }
2063 }
2064 
2065 void a2dDcDrawer::DeviceDrawPixel( int x1, int y1, unsigned char r, unsigned char g, unsigned char b , unsigned char a )
2066 {
2067 #if defined(__WXMSW__)
2068 #if wxCHECK_VERSION(2,9,0)
2069  wxMSWDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
2070  WXHDC hdc = dcimpl->GetHDC();
2071 #else
2072  WXHDC hdc = m_renderDC->GetHDC();
2073 #endif
2074  ::SetPixelV( ( struct HDC__* )hdc, x1, y1, RGB( r, g, b ) );
2075 #elif __WXGTK__
2076 
2077 #if wxCHECK_VERSION(2,9,1)
2078  m_renderDC->DrawPoint( x1, y1 );
2079 /*
2080  wxWindowDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxWindowDCImpl );
2081  GdkWindow* gtkwin = dcimpl->GetGDKWindow();
2082  if ( gtkwin )
2083  gdk_draw_point( gtkwin, dcimpl->m_penGC, x1, y1 );
2084 */
2085 #else
2086  wxColour col( r, g, b );
2087  col.CalcPixel( ( ( wxWindowDC* )m_renderDC )->m_cmap );
2088  gdk_gc_set_foreground( ( ( wxWindowDC* )m_renderDC )->m_penGC, col.GetColor() );
2089  gdk_draw_point( ( ( wxWindowDC* ) m_renderDC )->m_window, ( ( wxWindowDC* )m_renderDC )->m_penGC, x1, y1 );
2090 #endif
2091 
2092 #else
2093 
2094 #endif
2095 }
2096 
2097 void a2dDcDrawer::DeviceDrawBitmap( const wxBitmap& bmp, double x, double y, bool useMask )
2098 {
2099  if ( m_disableDrawing )
2100  return;
2101 
2102  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
2104  {
2105  m_renderDC->DrawRectangle( Round( x ), Round( y ), bmp.GetWidth(), bmp.GetHeight() );
2106  }
2107  else
2108  m_renderDC->DrawBitmap( bmp, Round( x ), Round( y ), useMask );
2109 }
2110 
2111 void a2dDcDrawer::DrawCharDc( wxChar c )
2112 {
2113  double x, y;
2114  x = y = 0.0;
2115  double dx, dy;
2116  double angle = GetUserToDeviceTransform().GetRotation();
2118  //round to integer pixel important when text is drawn small
2119  m_renderDC->DrawRotatedText( wxString( c ), Round( dx ), Round( dy ), -angle );
2120 }
2121 
2122 void a2dDcDrawer::DrawTextDc( const wxString& text, double x, double y )
2123 {
2124  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
2125  double dx = GetUserToDeviceTransform().GetValue( 1, 0 );
2126  double dy = GetUserToDeviceTransform().GetValue( 1, 1 );
2127 
2128  // Get font size in device units
2129  unsigned int fontsize;
2130  fontsize = ( unsigned int ) fabs( m_currentfont.GetSize() * sqrt( dx * dx + dy * dy ) );
2131  if ( fontsize < 1 )
2132  fontsize = 1;
2133  m_currentfont.GetFont().SetPointSize( fontsize );
2134 
2135  m_renderDC->SetFont( m_currentfont.GetFont() );
2136  m_renderDC->SetBackgroundMode( wxTRANSPARENT );
2137  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
2138 
2139  // When text editing, text extends are different.
2140  // When possible drawn directly as a string
2141  // Understand that wxDc text cannot be scaled in x different from y,
2142  // and therefore scaling will only work correctly if that is taken into account.
2143  // Meaning matrix should have scaling in both x and y eqaul when using wxDC text.
2144  if ( m_forceNormalizedFont || ! GetUserToDeviceTransform().IsTranslateScaleIso() )
2145  {
2146  // a2dFont can be drawn as freetype if found ttf font file
2147  //DrawTextGeneric( text, x, y, ( void ( a2dDrawer2D::* )( wxChar ) ) & a2dDcDrawer::DrawCharFreetype );
2148  DrawTextGeneric( text, x, y, ( void ( a2dDrawer2D::* )( wxChar ) ) & a2dDcDrawer::DrawCharDc );
2149  }
2150  else
2151  {
2152  // mirror text, depending on y-axis orientation
2153  const double h = m_currentfont.GetLineHeight();
2154  x = y = 0.0;
2155  double angle = GetUserToDeviceTransform().GetRotation();
2157  m_renderDC->DrawRotatedText( text, ( int ) dx, ( int ) dy, -angle );
2158  }
2159 }
2160 
2161 #if wxART2D_USE_FREETYPE
2162 extern FT_Library g_freetypeLibrary;
2163 
2164 //! used in freetype rendering
2165 typedef struct
2166 {
2167  wxColour colour;
2168  int xmin, ymax, ymin;
2169  int stride;
2170  int height;
2171  int descent;
2172  unsigned char* buf;
2173 }
2174 a2dSpanData;
2175 
2176 //! used in freetype rendering
2177 static void a2dSpanFuncGray( int y, int count, FT_Span* spans, a2dSpanData* user )
2178 {
2179  unsigned int alpha, invalpha, len;
2180  // although colours are chars, using ints is faster in multiplications.
2181  unsigned int r, g, b, rpm, gpm, bpm;
2182  r = user->colour.Red();
2183  g = user->colour.Green();
2184  b = user->colour.Blue();
2185 
2186  unsigned char* buf, *buf2;
2187  buf = user->buf + ( user->ymax - y ) * user->stride - user->xmin * 3;
2188  do
2189  {
2190  buf2 = buf + spans->x * 3;
2191  len = spans->len;
2192  alpha = spans->coverage;
2193  if ( alpha == 255 )
2194  {
2195  while( len )
2196  {
2197  // do not try to replace by *buf2++ = r, etc.
2198  // it turns out that this code actually is faster (for x86).
2199 #ifdef __WXGTK__
2200  buf2[0] = r;
2201  buf2[1] = g;
2202  buf2[2] = b;
2203 #else
2204  buf2[0] = b;
2205  buf2[1] = g;
2206  buf2[2] = r;
2207 #endif
2208  buf2 += 3;
2209  len--;
2210  }
2211  }
2212  else
2213  {
2214  rpm = r * alpha;
2215  gpm = g * alpha;
2216  bpm = b * alpha;
2217  invalpha = 255 - alpha;
2218  while( len )
2219  {
2220  // do not try to replace by *buf2++ = ..., etc.
2221  // it turns out that this code actually is faster (for x86).
2222 #ifdef __WXGTK__
2223  buf2[0] = ( buf2[0] * invalpha + rpm ) / 255;
2224  buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
2225  buf2[2] = ( buf2[2] * invalpha + bpm ) / 255;
2226 #else
2227  buf2[0] = ( buf2[0] * invalpha + bpm ) / 255;
2228  buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
2229  buf2[2] = ( buf2[2] * invalpha + rpm ) / 255;
2230 #endif
2231  buf2 += 3;
2232  len--;
2233  }
2234  }
2235  spans++;
2236  }
2237  while ( --count );
2238 }
2239 
2240 
2241 
2242 //! used in freetype rendering
2243 static void a2dSpanFuncGrayStrImage( int y, int count, FT_Span* spans, a2dSpanData* user )
2244 {
2245  unsigned int alpha, invalpha, len;
2246  // although colours are chars, using ints is faster in multiplications.
2247  unsigned int r, g, b, rpm, gpm, bpm;
2248  r = user->colour.Red();
2249  g = user->colour.Green();
2250  b = user->colour.Blue();
2251 
2252  unsigned char* buf, *buf2;
2253  buf = user->buf + ( user->height - user->descent - y ) * user->stride + user->xmin * 3;
2254  //To mirror use: buf = user->buf + ( user->descent + y ) * user->stride + user->xmin * 3;
2255  do
2256  {
2257  buf2 = buf + spans->x * 3;
2258  len = spans->len;
2259  alpha = spans->coverage;
2260  if ( alpha == 255 )
2261  {
2262  while( len )
2263  {
2264  // do not try to replace by *buf2++ = r, etc.
2265  // it turns out that this code actually is faster (for x86).
2266 #ifdef __WXGTK__
2267  buf2[0] = r;
2268  buf2[1] = g;
2269  buf2[2] = b;
2270 #else
2271  buf2[0] = b;
2272  buf2[1] = g;
2273  buf2[2] = r;
2274 #endif
2275  buf2 += 3;
2276  len--;
2277  }
2278  }
2279  else
2280  {
2281  rpm = r * alpha;
2282  gpm = g * alpha;
2283  bpm = b * alpha;
2284  invalpha = 255 - alpha;
2285  while( len )
2286  {
2287  // do not try to replace by *buf2++ = ..., etc.
2288  // it turns out that this code actually is faster (for x86).
2289 #ifdef __WXGTK__
2290  buf2[0] = ( buf2[0] * invalpha + rpm ) / 255;
2291  buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
2292  buf2[2] = ( buf2[2] * invalpha + bpm ) / 255;
2293 #else
2294  buf2[0] = ( buf2[0] * invalpha + bpm ) / 255;
2295  buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
2296  buf2[2] = ( buf2[2] * invalpha + rpm ) / 255;
2297 #endif
2298  buf2 += 3;
2299  len--;
2300  }
2301  }
2302  spans++;
2303  }
2304  while ( --count );
2305 }
2306 
2307 #endif
2308 
2310 {
2311  double x, y;
2312  x = y = 0.0;
2313 
2314  if ( m_disableDrawing )
2315  return;
2316 
2317  // scale font to size
2318  // mirror text, depending on y-axis orientation
2319  const double h = m_currentfont.GetLineHeight();
2320 
2321 #if wxART2D_USE_FREETYPE
2322  a2dAffineMatrix affine;
2323  if ( !GetYaxis() )
2324  {
2325  //affine.Translate( 0.0, -h );
2326  //affine.Mirror( true, false );
2327  }
2328  // position text, works but only translation done.
2329  //affine.Scale( scale );
2330  //affine.Translate( x, y );
2331 
2332  a2dVpath vpath;
2333  m_currentfont.GetVpath( c, vpath, affine );
2334 
2335  // save context
2336  PushTransform( affine );
2337 
2338  // the resulting vector path contains contours and holes.
2339  // Like character 'O' contains on contour and one hole.
2340  // Contours are clockwise, while holes or counter clockwise.
2341  // Using PolyPolygon, we can draw such polygons correctly.
2342  //DrawVpath( &vpath );
2343 
2344  //Text is drawn filled with the current pen.
2345  //Brush is used earlier to draw a rectangular background.
2346 
2348  wxBrush dcbrush( color );
2349  wxBrush cur_dcbrush = m_renderDC->GetBrush();
2350  m_renderDC->SetBrush( dcbrush );
2351  wxPen dcpen = *wxTRANSPARENT_PEN;// wxNullPen;//wxPen( color, 0 );
2352  wxPen cur_dcpen = m_renderDC->GetPen();
2353  m_renderDC->SetPen( dcpen );
2354 
2355  a2dListOfa2dVertexList onlyPolygons;
2356  vpath.ConvertToPolygon( onlyPolygons, false );
2357  DrawPolyPolygon( onlyPolygons );
2358 
2359  m_renderDC->SetBrush( cur_dcbrush );
2360  m_renderDC->SetPen( cur_dcpen );
2361 
2362  // restore context
2363  PopTransform();
2364 #else // wxART2D_USE_FREETYPE
2366 #endif // wxART2D_USE_FREETYPE
2367 }
2368 
2369 
2370 void a2dDcDrawer::DeviceDrawAnnotation( const wxString& text, wxCoord x, wxCoord y, const wxFont& font )
2371 {
2372  if ( m_disableDrawing )
2373  return;
2374 
2375  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
2376 
2377  m_renderDC->SetFont( font );
2378  wxCoord w, h;
2379  m_renderDC->GetTextExtent( text, &w, &h );
2380  m_renderDC->SetPen( *wxBLACK_PEN );
2381  m_renderDC->SetBrush( *wxCYAN_BRUSH );
2382  m_renderDC->DrawRectangle( x - 1, y - 1, w + 2, h + 2 );
2383  m_renderDC->SetTextBackground( *wxCYAN );
2384  m_renderDC->SetTextForeground( *wxBLACK );
2385  m_renderDC->DrawText( text, x, y );
2386 }
2387 
2388 void a2dDcDrawer::BlitBuffer( wxRect WXUNUSED( rect ), const wxPoint& WXUNUSED( bufferpos ) )
2389 {
2390  //wxFAIL_MSG( wxT( "not useful here" ) );
2391 }
2392 
2393 void a2dDcDrawer::BlitBuffer( wxDC* WXUNUSED( dc ), wxRect WXUNUSED( rect ), const wxPoint& WXUNUSED( bufferpos ) )
2394 {
2395  //wxFAIL_MSG( wxT( "not useful here" ) );
2396 }
2397 
2398 /*******************************************************************
2399 a2dMemDcDrawer
2400 ********************************************************************/
2401 
2402 a2dMemDcDrawer::a2dMemDcDrawer( const wxSize& size ): a2dDcDrawer( size )
2403 {
2404  m_buffer = wxBitmap( m_width, m_height );
2405 #if defined(__WXMSW__)
2406  m_hdc1 = ::GetDC( NULL );
2407  m_hdc2 = ::CreateCompatibleDC( m_hdc1 );
2408 #endif
2409 }
2410 
2411 a2dMemDcDrawer::a2dMemDcDrawer( int width, int height ): a2dDcDrawer( width, height )
2412 {
2413  m_buffer = wxBitmap( width, height );
2414 #if defined(__WXMSW__)
2415  m_hdc1 = ::GetDC( NULL );
2416  m_hdc2 = ::CreateCompatibleDC( m_hdc1 );
2417 #endif
2418 }
2419 
2421 {
2422 #if defined(__WXMSW__)
2423  ::DeleteDC( m_hdc1 );
2424  ::ReleaseDC( NULL, m_hdc2 );
2425 #endif // defined( __WXMSW__ )
2426 }
2427 
2429  : a2dDcDrawer( other )
2430 {
2431  m_buffer = other.m_buffer;
2432 #if defined(__WXMSW__)
2433  m_hdc1 = ::GetDC( NULL );
2434  m_hdc2 = ::CreateCompatibleDC( m_hdc1 );
2435 #endif
2436 }
2437 
2439 {
2440  wxASSERT_MSG( m_beginDraw_endDraw >= 0, wxT( "a2dMemDcDrawer, unbalanced BeginDraw EndDraw" ) );
2441 
2442  if ( m_beginDraw_endDraw == 0 )
2443  {
2444  if ( m_externalDc )
2445  {
2446  wxASSERT_MSG( m_renderDC != NULL, wxT( "a2dMemDcDrawer, wxClientDc not set yet" ) );
2447  }
2448  else
2449  {
2450  wxASSERT_MSG( m_renderDC == NULL, wxT( "a2dMemDcDrawer, unbalanced BeginDraw EndDraw" ) );
2451  m_memdc = new wxMemoryDC();
2452  m_memdc->SelectObject( m_buffer );
2453  m_renderDC = m_memdc;
2454  }
2455 
2458 
2460 
2462 
2463  m_renderDC->SetMapMode( wxMM_TEXT );
2464 
2465  if ( m_display )
2466  {
2467  m_deviceDC = new wxClientDC( m_display );
2468  m_display->PrepareDC( *m_deviceDC );
2469  }
2470  }
2471 
2473 }
2474 
2476 {
2478 
2479  wxASSERT_MSG( m_renderDC != NULL, wxT( "a2dMemDcDrawer, unbalanced BeginDraw EndDraw" ) );
2480  wxASSERT_MSG( m_beginDraw_endDraw >= 0, wxT( "a2dMemDcDrawer, unbalanced BeginDraw EndDraw" ) );
2481 
2482  if ( m_beginDraw_endDraw == 0 )
2483  {
2484  wxASSERT_MSG( m_renderDC != NULL, wxT( "a2dDcDrawer, unbalanced BeginDraw EndDraw" ) );
2485  if ( m_externalDc )
2486  {
2487  wxASSERT_MSG( m_renderDC != NULL, wxT( "a2dDcDrawer, wxClientDc not set yet" ) );
2488  }
2489  else
2490  {
2491  m_memdc->SelectObject( wxNullBitmap );
2492  delete m_memdc;
2493  }
2494  if ( m_display )
2495  delete m_deviceDC;
2496  m_renderDC = m_deviceDC = NULL;
2497  }
2498 }
2499 
2500 void a2dMemDcDrawer::SetBufferSize( int w, int h )
2501 {
2502  m_width = w;
2503  m_height = h;
2504  wxBitmap helpbuf = wxBitmap( w, h );
2505 
2506  //make sure to preserve what was in the old buffer bitmap,
2507  //to prevent the need for total redraws
2508  m_mdc1.SelectObject( m_buffer );
2509  m_mdc2.SelectObject( helpbuf );
2510  m_mdc2.Blit( 0, 0, w, h, &m_mdc1, 0, 0 );
2511  m_mdc1.SelectObject( wxNullBitmap );
2512  m_mdc2.SelectObject( wxNullBitmap );
2513 
2514  m_buffer = helpbuf;
2515 }
2516 
2517 void a2dMemDcDrawer::DrawPolygon( const a2dVertexList* list, bool spline, wxPolygonFillMode fillStyle )
2518 {
2519  if ( m_disableDrawing )
2520  return;
2521 
2522  a2dDrawer2D::DrawPolygon( list, spline, fillStyle );
2523 }
2524 
2525 void a2dMemDcDrawer::DeviceDrawPolygon( unsigned int n, bool spline, wxPolygonFillMode fillStyle )
2526 {
2527  a2dDcDrawer::DeviceDrawPolygon( n, spline, fillStyle );
2528 }
2529 
2530 wxBitmap a2dMemDcDrawer::GetSubBitmap( wxRect rect ) const
2531 {
2532  wxBitmap ret( rect.width, rect.height, m_buffer.GetDepth() );
2533  wxASSERT_MSG( ret.Ok(), wxT( "GetSubImage error" ) );
2534 
2535  if ( m_renderDC )
2536  {
2537  //do NOT use getsubbitmap, renderDc is already set for the buffer therefor will not work properly
2538  m_mdc1.SelectObject( ret );
2539  m_mdc1.Blit( 0, 0, rect.width, rect.height, m_renderDC, rect.x, rect.y, wxCOPY, false );
2540  m_mdc1.SelectObject( wxNullBitmap );
2541  }
2542  else
2543  {
2544  m_mdc2.SelectObject( const_cast<wxBitmap&>( m_buffer ) );
2545 
2546  //do NOT use getsubbitmap, renderDc is already set for the buffer therefore will not work properly
2547  m_mdc1.SelectObject( ret );
2548  m_mdc1.Blit( 0, 0, rect.width, rect.height, &m_mdc2, rect.x, rect.y, wxCOPY, false );
2549  m_mdc1.SelectObject( wxNullBitmap );
2550 
2551  m_mdc2.SelectObject( wxNullBitmap );
2552  }
2553 
2554  return ret;
2555 }
2556 
2557 void a2dMemDcDrawer::CopyIntoBuffer( const wxBitmap& bitm )
2558 {
2559  m_buffer = bitm;
2560 }
2561 
2562 void a2dMemDcDrawer::BlitBuffer( wxDC* dc, wxRect rect, const wxPoint& bufferpos )
2563 {
2564  // clip to buffer
2565  if ( rect.x < 0 )
2566  {
2567  rect.width += rect.x;
2568  rect.x = 0;
2569  }
2570  if ( rect.width <= 0 ) return;
2571 
2572  if ( rect.y < 0 )
2573  {
2574  rect.height += rect.y;
2575  rect.y = 0;
2576  }
2577  if ( rect.height <= 0 ) return;
2578 
2579  if ( rect.x + rect.width > m_width )
2580  {
2581  rect.width = m_width - rect.x;
2582  }
2583  if ( rect.width <= 0 ) return;
2584 
2585  if ( rect.y + rect.height > m_height )
2586  {
2587  rect.height = m_height - rect.y;
2588  }
2589  if ( rect.height <= 0 ) return;
2590 
2591  if ( !m_renderDC )
2592  {
2593  m_mdc1.SelectObject( m_buffer );
2594 
2595  dc->Blit( rect.x - bufferpos.x, rect.y - bufferpos.y, rect.width, rect.height, &m_mdc1, rect.x, rect.y, wxCOPY, false );
2596 
2597  m_mdc1.SelectObject( wxNullBitmap );
2598  }
2599  else
2600  {
2601  dc->Blit( rect.x - bufferpos.x, rect.y - bufferpos.y, rect.width, rect.height, m_renderDC, rect.x, rect.y, wxCOPY, false );
2602  }
2603 
2604 }
2605 
2606 void a2dMemDcDrawer::BlitBuffer( wxRect rect, const wxPoint& bufferpos )
2607 {
2608  BeginDraw();
2609  BlitBuffer( m_deviceDC, rect, bufferpos );
2610  EndDraw();
2611 }
2612 
2613 void a2dMemDcDrawer::ShiftBuffer( int dxy, bool yshift )
2614 {
2615  int bw = GetBuffer().GetWidth();
2616  int bh = GetBuffer().GetHeight();
2617  if ( yshift )
2618  {
2619  if ( dxy > 0 && dxy < bh )
2620  {
2621  wxRect rect( 0, 0, bw, bh - dxy );
2622  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2623  m_mdc1.SelectObject( m_buffer );
2624  m_mdc1.DrawBitmap( sub_bitmap, 0, dxy, true );
2625  m_mdc1.SelectObject( wxNullBitmap );
2626  }
2627  else if ( dxy < 0 && dxy > -bh )
2628  {
2629  wxRect rect( 0, -dxy, bw, bh + dxy );
2630  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2631  m_mdc1.SelectObject( m_buffer );
2632  m_mdc1.DrawBitmap( sub_bitmap, 0, 0, true );
2633  m_mdc1.SelectObject( wxNullBitmap );
2634  }
2635  else
2636  wxFAIL_MSG( wxT( "you can only shift within height of buffer" ) );
2637 
2638  }
2639  else
2640  {
2641  if ( dxy > 0 && dxy < bw )
2642  {
2643  wxRect rect( 0, 0, bw - dxy, bh );
2644  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2645  m_mdc1.SelectObject( m_buffer );
2646  m_mdc1.DrawBitmap( sub_bitmap, dxy, 0, true );
2647  m_mdc1.SelectObject( wxNullBitmap );
2648  }
2649  else if ( dxy < 0 && dxy > -bw )
2650  {
2651  wxRect rect( -dxy, 0, bw + dxy, bh );
2652  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2653  m_mdc1.SelectObject( m_buffer );
2654  m_mdc1.DrawBitmap( sub_bitmap, 0, 0, true );
2655  m_mdc1.SelectObject( wxNullBitmap );
2656  }
2657  else
2658  wxFAIL_MSG( wxT( "you can only shift within width of buffer" ) );
2659  }
2660 }
2661 
2662 void a2dMemDcDrawer::DrawImage( const wxImage& image, double x, double y, double width, double height, wxUint8 Opacity )
2663 {
2664 #if wxART2D_USE_AGGDRAWER
2665  if ( m_disableDrawing )
2666  return;
2667 
2668  if ( width == 0 || height == 0 )
2669  return;
2670 
2671  if ( m_drawstyle == a2dFILLED )
2672  {
2673  double angle = GetTransform().GetRotation();
2674 
2675  //if ( fabs( fmod(angle,90) ) > 0.5 )
2676  if ( fabs( angle ) > 0.5 || Opacity != 255 )
2677  {
2678  //stop current drawer, to release its m_memdc on m_buffer
2679  if ( !m_externalDc )
2680  {
2681  m_memdc->SelectObject( wxNullBitmap );
2682  }
2683  //EndDraw();
2684 
2685  a2dAggDrawer aggDrawer = a2dAggDrawer( m_buffer );
2686  aggDrawer.SetYaxis( m_yaxis );
2687  aggDrawer.SetTransform( GetTransform() );
2688  aggDrawer.SetMappingMatrix( GetMappingMatrix() );
2689  aggDrawer.SetDrawerFill( m_activefill );
2690  aggDrawer.SetDrawerStroke( m_activestroke );
2691  aggDrawer.SetDrawStyle( m_drawstyle );
2692  aggDrawer.BeginDraw();
2694  aggDrawer.DrawImage( image, x , y, width, height, Opacity );
2695  aggDrawer.EndDraw();
2696 
2697  m_buffer = aggDrawer.GetBuffer();
2698 
2699  //continue current drawer
2700  if ( !m_externalDc )
2701  {
2702  m_memdc->SelectObject( m_buffer );
2703  }
2704  //BeginDraw();
2705  }
2706  else
2707  a2dDcDrawer::DrawImage( image, x, y, width, height, Opacity );
2708  }
2709  else
2710  {
2711  DrawCenterRoundedRectangle( x, y, width, height, 0 );
2712  }
2713 #else
2714  a2dDcDrawer::DrawImage( image, x, y, width, height, Opacity );
2715 #endif
2716 }
2717 
2718 void a2dMemDcDrawer::DrawImage( const a2dImageRGBA& image, double x, double y, double width, double height, wxUint8 Opacity )
2719 {
2720 #if wxART2D_USE_AGGDRAWER
2721  if ( m_disableDrawing )
2722  return;
2723 
2724  if ( width == 0 || height == 0 )
2725  return;
2726 
2727  if ( m_drawstyle == a2dFILLED )
2728  {
2729  double angle = GetTransform().GetRotation();
2730 
2731  //if ( fabs( fmod(angle,90) ) > 0.5 )
2732  if ( 1 ) // fabs(angle) > 0.5 || Opacity != 255 )
2733  {
2734  //stop current drawer, to release its m_memdc on m_buffer
2735  if ( !m_externalDc )
2736  {
2737  m_memdc->SelectObject( wxNullBitmap );
2738  }
2739  //EndDraw();
2740 
2741  a2dAggDrawer aggDrawer = a2dAggDrawer( m_buffer );
2742  aggDrawer.SetYaxis( m_yaxis );
2743  aggDrawer.SetTransform( GetTransform() );
2744  aggDrawer.SetMappingMatrix( GetMappingMatrix() );
2745  aggDrawer.SetDrawerFill( m_activefill );
2746  aggDrawer.SetDrawerStroke( m_activestroke );
2747  aggDrawer.SetDrawStyle( m_drawstyle );
2748  aggDrawer.BeginDraw();
2750  aggDrawer.DrawImage( image, x , y, width, height );
2751  aggDrawer.EndDraw();
2752 
2753  m_buffer = aggDrawer.GetBuffer();
2754 
2755  //continue current drawer
2756  if ( !m_externalDc )
2757  {
2758  m_memdc->SelectObject( m_buffer );
2759  }
2760  //BeginDraw();
2761  }
2762  else
2763  a2dDcDrawer::DrawImage( image, x, y, width, height, Opacity );
2764  }
2765  else
2766  {
2767  DrawRoundedRectangle( x, y, width, height, 0 );
2768  }
2769 #else
2770  a2dDcDrawer::DrawImage( image, x, y, width, height, Opacity );
2771 #endif
2772 }
2773 
2774 #define BBOX_GLYPH_EXTEND 1
2775 
2776 //#undef __WXMSW__
2777 
2778 void DrawCharFreetypeHorizontal( wxColour col, const a2dGlyph* a2dglyph, unsigned char* buf, int bufwidth, int bufheight, wxChar c, int dx, int deviceDescent, FT_BBox bbox )
2779 {
2780  // Use next to test on screen a2dDcDrawer vpath drawing for printing.
2781  //a2dDcDrawer::DrawCharFreetype( c );
2782  //return;
2783 
2784 #if wxART2D_USE_FREETYPE
2785 
2786  FT_Glyph image = a2dglyph->m_glyph;
2787 
2788  // If size == 0, nothing has to be drawn.
2789  if ( bbox.xMax - bbox.xMin <= 0 || bbox.yMax - bbox.yMin <= 0 )
2790  {
2791  return;
2792  }
2793 
2794  // Render glyph to an image
2795  if ( image->format == FT_GLYPH_FORMAT_OUTLINE )
2796  {
2797  a2dSpanData spandata;
2798  spandata.colour = col;
2799  spandata.xmin = dx;
2800  spandata.height = bufheight;
2801  spandata.descent = deviceDescent;
2802  spandata.ymin = bbox.yMin;
2803  spandata.ymax = bbox.yMax;
2804  spandata.stride = bufwidth * 3;
2805 #if defined(__WXMSW__)
2806  // calculate image stride ( = w + padding )
2807  spandata.stride = ( spandata.stride + sizeof( DWORD ) - 1 ) / sizeof( DWORD ) * sizeof( DWORD );
2808 #endif // defined( __WXMSW__ )
2809  spandata.buf = buf;
2810  wxASSERT( spandata.buf != NULL );
2811 
2812  FT_Raster_Params params;
2813  params.target = NULL;
2814  params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT | FT_RASTER_FLAG_CLIP;
2815  params.gray_spans = ( FT_SpanFunc ) & a2dSpanFuncGrayStrImage;
2816  params.black_spans = NULL;
2817  params.bit_test = ( FT_Raster_BitTest_Func ) NULL;
2818  params.bit_set = ( FT_Raster_BitSet_Func ) NULL;
2819  params.user = &spandata;
2820  params.clip_box = bbox;
2821 
2822  FT_Outline& outline = ( ( FT_OutlineGlyph ) image )->outline;
2823  if ( FT_Outline_Render( g_freetypeLibrary, &outline, &params ) == 0 )
2824  {
2825  }
2826  }
2827  else if ( image->format == FT_GLYPH_FORMAT_BITMAP )
2828  {
2829  wxFAIL_MSG( _( "Non vector bitmap fonts are not supported" ) );
2830  }
2831  else
2832  wxFAIL_MSG( _( "Non vector fonts are not supported" ) );
2833 
2834 #else // wxART2D_USE_FREETYPE
2835  DrawCharUnknown( c );
2836 #endif // wxART2D_USE_FREETYPE
2837 }
2838 
2839 void a2dMemDcDrawer::DrawTextFreetype( const wxString& text, double x, double y )
2840 {
2841  // if text font is normalized, or we have on even scaled and/or rotated text, we go for
2842  // no device draw of text
2843 
2844  if ( m_forceNormalizedFont || ! GetUserToDeviceTransform().IsTranslateScaleIso() )
2845  {
2846  DrawTextGeneric( text, x, y, ( void ( a2dDrawer2D::* )( wxChar ) ) & a2dDrawer2D::DrawCharFreetypeCb );
2847  return;
2848  }
2849 
2850  // Draw text at device height using hinting and all, so small size text looks fine.
2851  const double h = m_currentfont.GetLineHeight();
2852  bool textwasvisible = false;
2853 
2855 
2856  double hdx, hdy;
2857  int yBboxMinY;
2858  GetUserToDeviceTransform().TransformPoint( 0.0, 0.0, hdx, hdy );
2859  yBboxMinY = Round( hdy );
2860 
2861  // x,y on lower-left point of bbox.
2862  // Add offset, to put anchor at text start
2863  double worldDescent = m_currentfont.GetDescent();
2864  m_usertodevice *= a2dAffineMatrix( 0.0, worldDescent );
2865 
2866  // scale = m_currentfont.GetSize() / deviceh;
2867  const a2dGlyph* a2dglyphprev = NULL;
2868 
2869  wxColour stroke = GetDrawerStroke().GetColour();
2870 
2871  if ( 1 )
2872  {
2873  int dx, dy;
2874  m_usertodevice.TransformPoint( 0.0, 0.0, hdx, hdy );
2875  dx = Round( hdx ); dy = Round( hdy );
2876  //dx += 1; //Draw text one pixel to the right, relative to xmin boundingbox
2877  // See also void a2dFontFreetypeData::GetTextExtent on how world bbox right side is compensated.
2878 
2879  // compensate 0 pixel at low y, and high y 1 pixel, 1 extra here.
2880  wxUint16 deviceh = ( wxUint16 ) ceil( m_usertodevice.TransformDistance( h ) ) + 1;
2881  wxUint16 deviceDescent = ( wxUint16 ) ceil( m_usertodevice.TransformDistance( worldDescent ) ) + 1; // one lower
2882 
2883  int dxrel = 0;
2884 
2885  // first how long in x is the image we need.
2886 #if wxUSE_UNICODE
2887  const wxStringCharType *cp(text.wx_str());
2888 #else
2889  const wxChar* cp(text.c_str());
2890 #endif // wxUSE_UNICODE
2891  wxChar c = 0;
2892  size_t n = text.Length();
2893  for ( size_t i = 0; i < n; i++ )
2894  {
2895  c = *cp++;
2896  const a2dGlyph* a2dglyph = m_currentfont.GetGlyphFreetype( c );
2897  // The glyph is now grid fitted and hinted.
2898  if( !a2dglyph )
2899  return;
2900 
2901  if ( i > 0 )
2902  {
2903  FT_Face face = a2dglyph->m_face;
2904  FT_Vector kern;
2905  FT_Get_Kerning( a2dglyph->m_face, a2dglyphprev->m_index, a2dglyph->m_index, FT_KERNING_DEFAULT, &kern );
2906  dxrel += ( int ) ( kern.x / 64.0 );
2907 
2908  if ( a2dglyphprev->m_rsb - a2dglyph->m_lsb >= 32 )
2909  dxrel -= 1;
2910  else if ( a2dglyphprev->m_rsb - a2dglyph->m_lsb < -32 )
2911  dxrel += 1;
2912  }
2913  a2dglyphprev = a2dglyph;
2914  FT_Glyph glyphimage = a2dglyph->m_glyph;
2915 
2916  FT_BBox bbox;
2917  FT_Glyph_Get_CBox( glyphimage, FT_GLYPH_BBOX_PIXELS, &bbox );
2918 
2919  int advance = ( int ) ( glyphimage->advance.x / 64.0 );
2920  dxrel += advance;
2921  }
2922  int cheat = 2;
2923  int devicew = dxrel + cheat; //this should make sure the text fits in the bitmap,but does not influence rendering itself or its bbox.
2924 
2925  wxRect stringBbox( dx, yBboxMinY - deviceh, devicew, deviceh + cheat);
2926  if ( stringBbox.GetWidth() == 0 || stringBbox.GetHeight() == 0 )
2927  return;
2928 
2929  wxBitmap sub_bitmap = GetSubBitmap( stringBbox );
2930 
2931  unsigned char* buf;
2932 
2933  #if defined(__WXMSW__)
2934  BITMAPINFO bi;
2935  bi.bmiHeader.biSize = sizeof( bi.bmiHeader );
2936  bi.bmiHeader.biWidth = devicew;
2937  bi.bmiHeader.biHeight = -deviceh;
2938  bi.bmiHeader.biPlanes = 1;
2939  bi.bmiHeader.biBitCount = 24;
2940  bi.bmiHeader.biCompression = BI_RGB;
2941  bi.bmiHeader.biSizeImage = 0;
2942  bi.bmiHeader.biClrUsed = 0;
2943  bi.bmiHeader.biClrImportant = 0;
2944 
2945  HBITMAP hbitmap = ( HBITMAP ) sub_bitmap.GetHBITMAP();
2946  buf = ( unsigned char* ) malloc( ( 3 * devicew + sizeof( DWORD ) - 1 ) / sizeof( DWORD ) * sizeof( DWORD ) * (deviceh + 1) );
2947  ::GetDIBits( m_hdc2, hbitmap, 0, deviceh, buf, &bi, DIB_RGB_COLORS );
2948  #else // defined( __WXMSW__ )
2949  wxImage strImage( sub_bitmap.ConvertToImage() );
2950  buf = strImage.GetData();
2951  //strImage.Clear( 204 );
2952  #endif // defined( __WXMSW__ )
2953 
2954  dxrel = 0;
2955 #if wxUSE_UNICODE
2956  cp = text.wx_str();
2957 #else
2958  cp = text.c_str();
2959 #endif // wxUSE_UNICODE
2960  for ( size_t i = 0; i < n; i++ )
2961  {
2962  c = *cp++;
2963  const a2dGlyph* a2dglyph = m_currentfont.GetGlyphFreetype( c );
2964  // The glyph is now grid fitted and hinted.
2965  if( !a2dglyph )
2966  return;
2967 
2968  if ( i > 0 )
2969  {
2970  FT_Face face = a2dglyph->m_face;
2971  FT_Vector kern;
2972  FT_Get_Kerning( a2dglyph->m_face, a2dglyphprev->m_index, a2dglyph->m_index, FT_KERNING_DEFAULT, &kern );
2973  dxrel += ( int ) ( kern.x / 64.0 );
2974 
2975  if ( a2dglyphprev->m_rsb - a2dglyph->m_lsb >= 32 )
2976  dxrel -= 1;
2977  else if ( a2dglyphprev->m_rsb - a2dglyph->m_lsb < -32 )
2978  dxrel += 1;
2979 
2980  }
2981  a2dglyphprev = a2dglyph;
2982 
2983  FT_Glyph glyphimage = a2dglyph->m_glyph;
2984 
2985  FT_BBox bbox;
2986  FT_Glyph_Get_CBox( glyphimage, FT_GLYPH_BBOX_PIXELS, &bbox );
2987  int px = dx + dxrel + bbox.xMin;
2988  int py = dy - bbox.yMax;
2989  int wbox = bbox.xMax - bbox.xMin;
2990  int hbox = bbox.yMax - bbox.yMin;
2991 
2992  int advance = ( int ) ( glyphimage->advance.x / 64.0 );
2993 
2994  if ( wbox || hbox )
2995  {
2996  wxRect bboxglyph( px, py, wbox, hbox );
2997  //bboxglyph.Inflate( 1 ); //if not, some redrawpixels missed.
2998 
2999  // check character bounding box in device coordinates
3000  // To optimize take take text height and advance width to check if characters needs to be drawn.
3001  // If not, the rest of the string is outside the clipping rectangle for sure.
3002  // With just the glyph boundingbox this is not possible, and each character needs to be checked separately
3003  wxRect bboxd( px, yBboxMinY - deviceh, advance, deviceh );
3004 
3005  // if character is not outside clipping box, draw it.
3006  if ( m_clipboxdev.Intersects( bboxd ) )
3007  {
3008  if ( m_clipboxdev.Intersects( bboxglyph ) )
3009  {
3010  DrawCharFreetypeHorizontal( stroke, a2dglyph, buf, devicew, deviceh, c, dxrel, deviceDescent, bbox );
3011  }
3012  textwasvisible = true;
3013  }
3014  else if ( textwasvisible )
3015  {
3016  //wxLogDebug("NO bboxd x=%d, y=%d w=%d h=%d", bboxd.GetLeft(), bboxd.GetTop(), bboxd.GetWidth(), bboxd.GetHeight() );
3017  // If characters of a string had been visible, and this character is not
3018  // visible, then so will all succeeding. i.o.w. we can stop drawing.
3019  break;
3020  }
3021  }
3022  dxrel += advance;
3023  }
3024 
3025  {
3026  #if defined( __WXMSW__ )
3027  ::SetDIBits( m_hdc2, hbitmap, 0, deviceh, buf, &bi, DIB_RGB_COLORS );
3028  free( buf );
3029  #else // defined( __WXMSW__ )
3030  wxBitmap sub_bitmap( strImage );
3031  #endif // defined( __WXMSW__ )
3032 
3033  // drawn in this image
3034  DeviceDrawBitmap( sub_bitmap, dx, yBboxMinY - deviceh );
3035  }
3036 /*
3037  wxPen pen = m_renderDC->GetPen();
3038  wxBrush brush = m_renderDC->GetBrush();
3039  wxColour color( 5, 50, 255, 0 );
3040  m_renderDC->SetPen( wxPen( color ) );
3041  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
3042  m_renderDC->DrawRectangle( dx, yBboxMinY, dxrel, -deviceh);
3043  m_renderDC->SetPen( pen );
3044  m_renderDC->SetBrush( brush );
3045 */
3046 
3047  }
3048  //EVENTUALLY get rid of this
3049  else
3050  {
3051  // compensate 1 pixel at low y, and high y also 1 pixel, 2 extra here.
3052  wxUint16 deviceh = ( wxUint16 ) ceil( m_usertodevice.TransformDistance( h ) ) + 2;
3053  wxUint16 deviceDescent = ( wxUint16 ) ceil( m_usertodevice.TransformDistance( worldDescent ) ) + 1; // one lower
3054 
3055  int dx, dy;
3056  m_usertodevice.TransformPoint( 0.0, 0.0, hdx, hdy );
3057  dx = Round( hdx ); dy = Round( hdy );
3058 
3059  yBboxMinY -= 1; // compensate 1 pixel lower
3060  dy -= 1; // compensate 1 pixel lower
3061  int dxrel = 0;
3062  bool textwasvisible = false;
3063 
3064  wxChar c = 0;
3065  size_t n = text.Length();
3066  for ( size_t i = 0; i < n; i++ )
3067  {
3068  const wxChar oldc = c;
3069  c = text[i];
3070  const a2dGlyph* a2dglyph = m_currentfont.GetGlyphFreetype( c );
3071  // The glyph is now grid fitted and hinted.
3072  if( !a2dglyph )
3073  return;
3074 
3075  if ( i > 0 )
3076  {
3077  FT_Face face = a2dglyph->m_face;
3078  FT_Vector kern;
3079  FT_Get_Kerning( a2dglyph->m_face, a2dglyphprev->m_index, a2dglyph->m_index, FT_KERNING_DEFAULT, &kern );
3080  dxrel += ( int ) ( kern.x / 64.0 );
3081 
3082  if ( a2dglyphprev->m_rsb - a2dglyph->m_lsb >= 32 )
3083  dxrel -= 1;
3084  else if ( a2dglyphprev->m_rsb - a2dglyph->m_lsb < -32 )
3085  dxrel += 1;
3086 
3087  }
3088  a2dglyphprev = a2dglyph;
3089 
3090 
3091  FT_Glyph glyphimage = a2dglyph->m_glyph;
3092 
3093  FT_BBox bbox;
3094  FT_Glyph_Get_CBox( glyphimage, FT_GLYPH_BBOX_PIXELS, &bbox );
3095  int px = dx + dxrel + bbox.xMin;
3096  int py = dy - bbox.yMax;
3097  int wbox = bbox.xMax - bbox.xMin;
3098  int hbox = bbox.yMax - bbox.yMin;
3099 
3100  int advance = ( int ) ( glyphimage->advance.x / 64.0 );
3101 
3102  wxRect bboxglyph( px, py, wbox, hbox );
3103  bboxglyph.Inflate( 1 ); //if not, some redrawpixels missed.
3104 
3105  // check character bounding box in device coordinates
3106  // To optimize take take text height and advance width to define is charecters needs to be drawn.
3107  // If not, the rest of the string is outside the clipping rectangle for sure.
3108  // With just the glyph boundingbox this is not possible, and each character needs to be checked separately
3109  wxRect bboxd( px, yBboxMinY - deviceh, advance, deviceh );
3110 
3111  // if character is not outside clipping box, draw it.
3112  if ( m_clipboxdev.Intersects( bboxd ) )
3113  {
3114  if ( m_clipboxdev.Intersects( bboxglyph ) )
3115  {
3116  FT_Vector vec;
3117  FT_Matrix trans_matrix;
3118  //Scale in x and y is the same, and there is a translation, No rotation.
3119  // The size/scale is already loaded in the text glyph.
3120  /*
3121  double angle = GetUserToDeviceTransform().GetRotation();
3122  // set up transform (a rotation here)
3123  trans_matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
3124  trans_matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
3125  trans_matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
3126  trans_matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
3127  */
3128 
3129  trans_matrix.xx = ( FT_Fixed )( 0x10000L );
3130  trans_matrix.xy = ( FT_Fixed )( 0 );
3131  trans_matrix.yx = ( FT_Fixed )( 0 );
3132  trans_matrix.yy = ( FT_Fixed )( 0x10000L );
3133  vec.x = 0;
3134  vec.y = 0;
3135 
3136  DrawCharFreetype( stroke, c, dx + dxrel, dy, trans_matrix, vec );
3137  }
3138  textwasvisible = true;
3139  }
3140  else if ( textwasvisible )
3141  {
3142  //wxLogDebug("NO bboxd x=%d, y=%d w=%d h=%d", bboxd.GetLeft(), bboxd.GetTop(), bboxd.GetWidth(), bboxd.GetHeight() );
3143  // If characters of a string had been visible, and this character is not
3144  // visible, then so will all succeeding. i.o.w. we can stop drawing.
3145  break;
3146  }
3147  dxrel += advance;
3148  //wdx += m_currentfont.GetWidth( c );
3149  }
3150 
3151  /* DEBUG bbox in device coordinates
3152  wxPen pen = m_renderDC->GetPen();
3153  wxBrush brush = m_renderDC->GetBrush();
3154  wxColour color( 245, 150, 255, 0 );
3155  m_renderDC->SetPen( wxPen( color ) );
3156  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
3157  m_renderDC->DrawRectangle( floor( hdx ) , yBboxMinY, dxrel, -deviceh);
3158  m_renderDC->SetPen( pen );
3159  m_renderDC->SetBrush( brush );
3160  */
3161 
3162  }
3163 
3164 }
3165 
3167 {
3168 #if wxART2D_USE_FREETYPE
3169  // Add offset, to put anchor on lower-left point of bbox.
3170  double wdx, wdy;
3172 
3173  int dx = Round( wdx );
3174  int dy = Round( wdy );
3175  //int dx = ( wdx );
3176  //int dy = ( wdy );
3177 
3178  FT_Matrix trans_matrix;
3179  FT_Vector vec;
3180  if ( 1 ) // ! GetUserToDeviceTransform().IsTranslateScaleIso() )
3181  {
3182  // Generate affine, to scale character from normalized to real size.
3183  a2dAffineMatrix glyphPos;
3184  glyphPos.Scale( m_currentfont.GetSize() / m_currentfont.GetDeviceHeight() );
3185  a2dAffineMatrix glyphToDevice = GetUserToDeviceTransform() * glyphPos;
3186 
3187  // Transform glyph and scale it to device coordinates. Also correct for sub-pixel drawing.
3188  trans_matrix.xx = ( FT_Fixed ) ( glyphToDevice.GetValue( 0, 0 ) * 0x10000 );
3189  trans_matrix.xy = ( FT_Fixed ) ( glyphToDevice.GetValue( 1, 0 ) * 0x10000 );
3190  trans_matrix.yx = ( FT_Fixed ) ( -glyphToDevice.GetValue( 0, 1 ) * 0x10000 );
3191  trans_matrix.yy = ( FT_Fixed ) ( -glyphToDevice.GetValue( 1, 1 ) * 0x10000 );
3192  vec.x = ( int ) ( ( wdx - dx ) * 64.0 );
3193  vec.y = ( int ) ( ( wdy - dy ) * -64.0 );
3194  }
3195  else
3196  {
3197  trans_matrix.xx = ( FT_Fixed )( 0x10000L );
3198  trans_matrix.xy = ( FT_Fixed )( 0 );
3199  trans_matrix.yx = ( FT_Fixed )( 0 );
3200  trans_matrix.yy = ( FT_Fixed )( 0x10000L );
3201  vec.x = 0;
3202  vec.y = 0;
3203  }
3204 
3205  wxColour stroke = GetDrawerStroke().GetColour();
3206  DrawCharFreetype( stroke, c, dx, dy, trans_matrix, vec );
3207 #else // wxART2D_USE_FREETYPE
3208  DrawCharUnknown( c );
3209 #endif // wxART2D_USE_FREETYPE
3210 
3211 }
3212 
3213 //! \bug EW: DrawCharFreetype crashes when zoomed in extremely far.
3214 void a2dMemDcDrawer::DrawCharFreetype( wxColour col, wxChar c, int dx, int dy, FT_Matrix trans_matrix, FT_Vector vec )
3215 {
3216  // Use next to test on screen a2dDcDrawer vpath drawing for printing.
3217  //a2dDcDrawer::DrawCharFreetype( c );
3218  //return;
3219 
3220 #if wxART2D_USE_FREETYPE
3221 
3222  // Get the glyph and make a copy of it
3223  const a2dGlyph* a2dglyph = m_currentfont.GetGlyphFreetype( c );
3224  // The glyph is now grid fitted and hinted.
3225  if( !a2dglyph )
3226  return;
3227  FT_Glyph image;
3228  if ( FT_Glyph_Copy( a2dglyph->m_glyph, &image ) != 0 )
3229  return;
3230 
3231  // we need to round to make sure the bitmap is shifted only an integer pixel quantity
3232  // translating grid fitted/hinted outline should be N pixels.
3233 
3234  if ( FT_Glyph_Transform( image, &trans_matrix, &vec ) != 0 )
3235  {
3236  wxFAIL_MSG( _( "glyph transform wrong" ) );
3237  FT_Done_Glyph( image );
3238  return;
3239  }
3240 
3241  // Get bounding box of the area which should be drawn.
3242  FT_BBox bbox;
3243  FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_PIXELS, &bbox );
3244 
3245  // WHY: The text boundingbox is used to position and align text to draw.
3246  // This can round to a pixel more or less, coming from world coordinates.
3247  // It depends on the redraw area how the overlap of the glyph is rounded.
3248  // And therefore some small part of the text that should be (re)drawn in the clipping rectangle, is not.
3249  // SOLUTION:
3250  // We assume the device clipping box is set to redraw part of the canvas.
3251  // The glyph bounding box part, which overlaps the redraw area (device clipping box),
3252  // should be redrawn.
3253  // It does not hurt to extend the overlap part a bit, as long as it is inside the device clipping box.
3254  // We extend the boundingbox of a glyph, to make sure a bit more is drawn than needed.
3255  // Since it is still clipped to the device clipping box, the result is that a bit more is drawn
3256  // only inside the clipbox. This helps to get rid of the "famous BIT BUGS".
3257  /*
3258  bbox.xMin -= BBOX_GLYPH_EXTEND;
3259  bbox.xMax += BBOX_GLYPH_EXTEND;
3260  bbox.yMin -= BBOX_GLYPH_EXTEND;
3261  bbox.yMax += BBOX_GLYPH_EXTEND;
3262  */
3263  // clip against clipbox.
3264  if ( m_clipboxdev.GetLeft() > dx + bbox.xMin )
3265  bbox.xMin = m_clipboxdev.GetLeft() - dx;
3266  if ( m_clipboxdev.GetRight() < dx + bbox.xMax )
3267  bbox.xMax = m_clipboxdev.GetRight() - dx;
3268 
3269  if ( m_clipboxdev.GetTop() >= dy - bbox.yMax )
3270  bbox.yMax = dy - m_clipboxdev.GetTop();
3271  if ( m_clipboxdev.GetBottom() < dy - bbox.yMin )
3272  bbox.yMin = dy - m_clipboxdev.GetBottom();
3273 
3274  // If size == 0, nothing has to be drawn.
3275  if ( bbox.xMax - bbox.xMin <= 0 || bbox.yMax - bbox.yMin <= 0 )
3276  {
3277  FT_Done_Glyph( image );
3278  return;
3279  }
3280 
3281  // this i (KLAAS) do not understand, it seems we do need one line more.
3282  bbox.yMax += 1;
3283  //bbox.xMax += 1;
3284 
3285  //glyph boundingbox is clipped as if placed at right position, but not placed at device coordinate.
3286  //De bitmap we will render is (0,0,w,h) as bbox
3287 
3288  int px = dx + bbox.xMin;
3289  int py = dy - bbox.yMax;
3290  int w = bbox.xMax - bbox.xMin + 1;
3291  int h = bbox.yMax - bbox.yMin + 1;
3292  /* TO DEBUG
3293  //draw randum colours for glyph rectangle to see, what and where.
3294  wxPen pen = m_renderDC->GetPen();
3295  wxBrush brush = m_renderDC->GetBrush();
3296  wxColour color( 5, 50, 255, 0 );
3297  //wxColour color2( 20, 30, 120, 0 );
3298  wxColour color2( rand()%254,rand()%254,rand()%254, 30 );
3299  //m_renderDC->SetPen( wxPen( color ) );
3300  //wxColour color2 = pen.GetColour();
3301  m_renderDC->SetPen(*wxTRANSPARENT_PEN );
3302  m_renderDC->SetBrush( wxBrush( color2 ) );
3303  m_renderDC->SetPen( wxPen( color ) );
3304  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
3305  m_renderDC->DrawRectangle( px, py, w, h);
3306  m_renderDC->SetPen( color );
3307  m_renderDC->SetBrush( brush );
3308  */
3309  // Obtain background image
3310  wxRect absarea2( px, py, w, h );
3311  wxBitmap sub_bitmap = GetSubBitmap( absarea2 );
3312 #if defined(__WXMSW__)
3313  BITMAPINFO bi;
3314  bi.bmiHeader.biSize = sizeof( bi.bmiHeader );
3315  bi.bmiHeader.biWidth = w;
3316  bi.bmiHeader.biHeight = -h;
3317  bi.bmiHeader.biPlanes = 1;
3318  bi.bmiHeader.biBitCount = 24;
3319  bi.bmiHeader.biCompression = BI_RGB;
3320  bi.bmiHeader.biSizeImage = 0;
3321  bi.bmiHeader.biClrUsed = 0;
3322  bi.bmiHeader.biClrImportant = 0;
3323 
3324  HBITMAP hbitmap = ( HBITMAP ) sub_bitmap.GetHBITMAP();
3325  unsigned char* buf = ( unsigned char* ) malloc( ( 3 * w + sizeof( DWORD ) - 1 ) / sizeof( DWORD ) * sizeof( DWORD ) * h );
3326  ::GetDIBits( m_hdc2, hbitmap, 0, h, buf, &bi, DIB_RGB_COLORS );
3327 #else // defined( __WXMSW__ )
3328  wxImage wximage( sub_bitmap.ConvertToImage() );
3329 #endif // defined( __WXMSW__ )
3330 
3331  // Render glyph to an image
3332  if ( image->format == FT_GLYPH_FORMAT_OUTLINE )
3333  {
3334  a2dSpanData spandata;
3335  spandata.colour = col;
3336  spandata.xmin = bbox.xMin;
3337  spandata.ymax = bbox.yMax;
3338  spandata.stride = w * 3;
3339 #if defined(__WXMSW__)
3340  // calculate image stride ( = w + padding )
3341  spandata.stride = ( spandata.stride + sizeof( DWORD ) - 1 ) / sizeof( DWORD ) * sizeof( DWORD );
3342  spandata.buf = buf;
3343 #else // defined( __WXMSW__ )
3344  spandata.buf = wximage.GetData();
3345 #endif // defined( __WXMSW__ )
3346  wxASSERT( spandata.buf != NULL );
3347 
3348  FT_Raster_Params params;
3349  params.target = NULL;
3350  params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT | FT_RASTER_FLAG_CLIP;
3351  params.gray_spans = ( FT_SpanFunc ) & a2dSpanFuncGray;
3352  params.black_spans = NULL;
3353  params.bit_test = ( FT_Raster_BitTest_Func ) NULL;
3354  params.bit_set = ( FT_Raster_BitSet_Func ) NULL;
3355  params.user = &spandata;
3356  params.clip_box = bbox;
3357 
3358  FT_Outline& outline = ( ( FT_OutlineGlyph ) image )->outline;
3359  if ( FT_Outline_Render( g_freetypeLibrary, &outline, &params ) == 0 )
3360  {
3361 #if defined( __WXMSW__ )
3362  ::SetDIBits( m_hdc2, hbitmap, 0, h, buf, &bi, DIB_RGB_COLORS );
3363 #else // defined( __WXMSW__ )
3364  wxBitmap sub_bitmap( wximage );
3365 #endif // defined( __WXMSW__ )
3366  DeviceDrawBitmap( sub_bitmap, px, py );
3367  }
3368  }
3369 
3370  else
3371  wxFAIL_MSG( _( "Non vector fonts are not supported" ) );
3372 
3373 #if defined(__WXMSW__)
3374  free( buf );
3375 #endif // defined( __WXMSW__ )
3376 
3377  FT_Done_Glyph( image );
3378 #else // wxART2D_USE_FREETYPE
3379  DrawCharUnknown( c );
3380 #endif // wxART2D_USE_FREETYPE
3381 }
3382 
3383 
3384 #if wxART2D_USE_GRAPHICS_CONTEXT
3385 
3386 IMPLEMENT_DYNAMIC_CLASS( a2dGcDrawer, a2dGcBaseDrawer )
3387 
3388 /*******************************************************************
3389 a2dGcDrawer
3390 ********************************************************************/
3391 
3392 void a2dGcDrawer::InitContext()
3393 {
3394  m_externalDc = false;
3395  m_clip.Clear();
3396  m_buffer = wxBitmap( m_width, m_height );
3397  m_memdc.SelectObject( m_buffer );
3398  m_render = new a2dRenderer();
3399  m_context = ( a2dDcContext* ) ( ( a2dRenderer* )m_render )->CreateContext( &m_memdc, &m_buffer );
3400 }
3401 
3402 a2dGcDrawer::a2dGcDrawer( const wxSize& size ): a2dGcBaseDrawer( size.GetWidth(), size.GetHeight() )
3403 {
3404  InitContext();
3405 }
3406 
3407 a2dGcDrawer::a2dGcDrawer( int width, int height ): a2dGcBaseDrawer( width, height )
3408 {
3409  InitContext();
3410 }
3411 
3412 a2dGcDrawer::a2dGcDrawer( const a2dGcDrawer& other )
3413  : a2dGcBaseDrawer( other )
3414 {
3415  InitContext();
3416 }
3417 
3418 a2dGcDrawer::a2dGcDrawer( const a2dDrawer2D& other )
3419  : a2dGcBaseDrawer( other )
3420 {
3421  InitContext();
3422 }
3423 
3424 a2dGcDrawer::~a2dGcDrawer()
3425 {
3426  delete m_context;
3427  delete m_render;
3428  m_memdc.SelectObject( wxNullBitmap );
3429 }
3430 
3431 wxBitmap a2dGcDrawer::GetBuffer() const
3432 {
3433  return m_buffer;
3434 }
3435 
3436 void a2dGcDrawer::BeginDraw()
3437 {
3438  wxASSERT_MSG( m_beginDraw_endDraw >= 0, wxT( "a2dMemDcDrawer, unbalanced BeginDraw EndDraw" ) );
3439 
3440  if ( m_beginDraw_endDraw == 0 )
3441  {
3442  m_memdc.SelectObject( m_buffer );
3443 
3444  SetDrawerFill( m_currentfill );
3445  SetDrawerStroke( m_currentstroke );
3446 
3447  DestroyClippingRegion();
3448 
3449  SetDrawStyle( m_drawstyle );
3450 
3451  m_memdc.SetMapMode( wxMM_TEXT );
3452  }
3453 
3454  m_beginDraw_endDraw++;
3455 }
3456 
3457 void a2dGcDrawer::EndDraw()
3458 {
3459  m_beginDraw_endDraw--;
3460 
3461  wxASSERT_MSG( m_beginDraw_endDraw >= 0, wxT( "a2dMemDcDrawer, unbalanced BeginDraw EndDraw" ) );
3462 
3463  if ( m_beginDraw_endDraw == 0 )
3464  {
3465  m_memdc.SelectObject( wxNullBitmap );
3466  }
3467 }
3468 
3469 void a2dGcDrawer::SetBufferSize( int w, int h )
3470 {
3471  m_width = w;
3472  m_height = h;
3473  wxBitmap helpbuf = wxBitmap( w, h );
3474 
3475  //make sure to preserve what was in the old buffer bitmap,
3476  //to prevent the need for total redraws
3477  wxMemoryDC mdch;
3478  mdch.SelectObject( helpbuf );
3479  mdch.Blit( 0, 0, w, h, &m_memdc, 0, 0 );
3480  mdch.SelectObject( wxNullBitmap );
3481 
3482  m_memdc.SelectObject( wxNullBitmap );
3483  m_buffer = helpbuf;
3484  m_memdc.SelectObject( m_buffer );
3485  delete m_context;
3486  m_context = ( a2dDcContext* ) ( ( a2dRenderer* )m_render )->CreateContext( &m_memdc, &m_buffer );
3487 }
3488 
3489 wxBitmap a2dGcDrawer::GetSubBitmap( wxRect rect ) const
3490 {
3491  wxBitmap ret( rect.width, rect.height, m_buffer.GetDepth() );
3492  wxASSERT_MSG( ret.Ok(), wxT( "GetSubImage error" ) );
3493 
3494  //do NOT use getsubbitmap, renderDc is already set for the buffer therefor will not work properly
3495  wxMemoryDC dcb;
3496  dcb.SelectObject( ret );
3497  dcb.Blit( 0, 0, rect.width, rect.height, const_cast<wxMemoryDC*>( &m_memdc ), rect.x, rect.y, wxCOPY, false );
3498  dcb.SelectObject( wxNullBitmap );
3499 
3500  return ret;
3501 }
3502 
3503 void a2dGcDrawer::BlitBuffer( wxDC* dc, wxRect rect, const wxPoint& bufferpos )
3504 {
3505  // clip to buffer
3506  if ( rect.x < 0 )
3507  {
3508  rect.width += rect.x;
3509  rect.x = 0;
3510  }
3511  if ( rect.width <= 0 ) return;
3512 
3513  if ( rect.y < 0 )
3514  {
3515  rect.height += rect.y;
3516  rect.y = 0;
3517  }
3518  if ( rect.height <= 0 ) return;
3519 
3520  if ( rect.x + rect.width > m_width )
3521  {
3522  rect.width = m_width - rect.x;
3523  }
3524  if ( rect.width <= 0 ) return;
3525 
3526  if ( rect.y + rect.height > m_height )
3527  {
3528  rect.height = m_height - rect.y;
3529  }
3530  if ( rect.height <= 0 ) return;
3531 
3532  dc->Blit( rect.x - bufferpos.x, rect.y - bufferpos.y, rect.width, rect.height, &m_memdc, rect.x, rect.y, wxCOPY, false );
3533 }
3534 
3535 void a2dGcDrawer::ShiftBuffer( int dxy, bool yshift )
3536 {
3537  int bw = GetBuffer().GetWidth();
3538  int bh = GetBuffer().GetHeight();
3539  if ( yshift )
3540  {
3541  if ( dxy > 0 && dxy < bh )
3542  {
3543  wxRect rect( 0, 0, bw, bh - dxy );
3544  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
3545  wxMemoryDC m_mdc1;
3546  m_mdc1.SelectObject( m_buffer );
3547  m_mdc1.DrawBitmap( sub_bitmap, 0, dxy, true );
3548  m_mdc1.SelectObject( wxNullBitmap );
3549  }
3550  else if ( dxy < 0 && dxy > -bh )
3551  {
3552  wxRect rect( 0, -dxy, bw, bh + dxy );
3553  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
3554  wxMemoryDC m_mdc1;
3555  m_mdc1.SelectObject( m_buffer );
3556  m_mdc1.DrawBitmap( sub_bitmap, 0, 0, true );
3557  m_mdc1.SelectObject( wxNullBitmap );
3558  }
3559  else
3560  wxFAIL_MSG( wxT( "you can only shift within height of buffer" ) );
3561 
3562  }
3563  else
3564  {
3565  if ( dxy > 0 && dxy < bw )
3566  {
3567  wxRect rect( 0, 0, bw - dxy, bh );
3568  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
3569  wxMemoryDC m_mdc1;
3570  m_mdc1.SelectObject( m_buffer );
3571  m_mdc1.DrawBitmap( sub_bitmap, dxy, 0, true );
3572  m_mdc1.SelectObject( wxNullBitmap );
3573  }
3574  else if ( dxy < 0 && dxy > -bw )
3575  {
3576  wxRect rect( -dxy, 0, bw + dxy, bh );
3577  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
3578  wxMemoryDC m_mdc1;
3579  m_mdc1.SelectObject( m_buffer );
3580  m_mdc1.DrawBitmap( sub_bitmap, 0, 0, true );
3581  m_mdc1.SelectObject( wxNullBitmap );
3582  }
3583  else
3584  wxFAIL_MSG( wxT( "you can only shift within width of buffer" ) );
3585  }
3586 }
3587 
3588 void a2dGcDrawer::SetYaxis( bool up )
3589 {
3590  a2dDrawer2D::SetYaxis( up );
3591  //a2dContext* context = (a2dContext*) m_context;
3592  //context->SetYaxis( up );
3593 }
3594 
3595 void a2dGcDrawer::DoSetActiveFont( const a2dFont& font )
3596 {
3597  a2dContext* context = ( a2dContext* ) m_context;
3598  a2dRenderer* render = ( a2dRenderer* ) m_render;
3599  wxGraphicsFont f = render->CreateFont( font );
3600  context->SetFont( f );
3601 }
3602 
3603 void a2dGcDrawer::DoSetActiveStroke()
3604 {
3605  // wxGraphicsRenderer render class does understand a2dStroke and a2dFill,
3606  // so we will have a2dSTROKE_STIPPLE_MASK_OPAQUE_TRANSPARENT available, else lost.
3607  a2dRenderer* render = ( a2dRenderer* ) m_render;
3608  a2dContext* context = ( a2dContext* ) m_context;
3609  wxGraphicsPen p = render->CreateStroke( m_activestroke );
3610  m_context->SetPen( p );
3611 }
3612 
3613 void a2dGcDrawer::DoSetActiveFill()
3614 {
3615  // wxGraphicsRenderer render class does understand a2dStroke and a2dFill,
3616  // so we will have a2dSTROKE_STIPPLE_MASK_OPAQUE_TRANSPARENT available, else lost.
3617  a2dRenderer* render = ( a2dRenderer* ) m_render;
3618  a2dContext* context = ( a2dContext* ) m_context;
3619  wxGraphicsBrush b = render->CreateFill( m_activefill );
3620  m_context->SetBrush( b );
3621 }
3622 
3623 void a2dGcDrawer::DrawImage( const wxImage& imagein, double x, double y, double width, double height, wxUint8 Opacity )
3624 {
3625  if ( m_disableDrawing )
3626  return;
3627 
3628  // wxGraphicsRenderer render class does understand a2dStroke and a2dFill,
3629  // so we will have a2dSTROKE_STIPPLE_MASK_OPAQUE_TRANSPARENT available, else lost.
3630  a2dRenderer* render = ( a2dRenderer* ) m_render;
3631  a2dContext* context = ( a2dContext* ) m_context;
3632  wxGraphicsBitmap bitmap = render->CreateBitmap( imagein );
3633 #if wxCHECK_VERSION(2,9,0)
3634  context->DrawBitmap( bitmap, x, y, width, height );
3635 #else
3636  context->DrawGraphicsBitmap( bitmap, x, y, width, height );
3637 #endif
3638 }
3639 
3640 void a2dGcDrawer::DrawImage( const a2dImageRGBA& image, double x, double y, double width, double height, wxUint8 Opacity )
3641 {
3642  if ( m_disableDrawing )
3643  return;
3644 
3645  wxImage wximage = image.GetImage();
3646  a2dGcDrawer::DrawImage( wximage, x, y, width, height, Opacity );
3647 }
3648 
3649 void a2dGcDrawer::DrawPoint( double xc, double yc )
3650 {
3651  if ( m_disableDrawing )
3652  return;
3653 
3654  double xt, yt;
3655  GetUserToDeviceTransform().TransformPoint( xc, yc, xt, yt );
3656  //DeviceDrawPixel( xt, yt, m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
3657 }
3658 
3659 /* HANDLED IN m_context
3660 void a2dGcDrawer::DrawCharDc( wxChar c )
3661 {
3662  wxGraphicsMatrix m = m_context->CreateMatrix();
3663  m.Set(
3664  m_usertodevice( 0, 0), m_usertodevice( 0, 1),
3665  m_usertodevice( 1, 0), m_usertodevice( 1, 1),
3666  m_usertodevice( 2, 0), m_usertodevice( 2, 1) );
3667  m_context->SetTransform( m );
3668 
3669 #if wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
3670  if ( m_currentfont.GetType() == a2dFONT_WXDC && m_currentfont.GetFreetypeFont().Ok() )
3671  {
3672  a2dFont oldfont = m_currentfont;
3673  m_currentfont = m_currentfont.GetFreetypeFont();
3674  static_cast<a2dContext*>(m_context)->SetFont( m_currentfont );
3675  static_cast<a2dDcContext*>(m_context)->DrawCharFreetype( c );
3676  m_currentfont = oldfont;
3677  }
3678  else
3679  static_cast<a2dDcContext*>(m_context)->DrawCharDc( c );
3680 #else // wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
3681  static_cast<a2dDcContext*>(m_context)->DrawCharDc( c );
3682 #endif // wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
3683 }
3684 
3685 //! \bug EW: DrawCharFreetype crashes when zoomed in extremely far.
3686 void a2dGcDrawer::DrawCharFreetype( wxChar c )
3687 {
3688  wxGraphicsMatrix m = m_context->CreateMatrix();
3689  m.Set(
3690  m_usertodevice( 0, 0), m_usertodevice( 0, 1),
3691  m_usertodevice( 1, 0), m_usertodevice( 1, 1),
3692  m_usertodevice( 2, 0), m_usertodevice( 2, 1) );
3693  m_context->SetTransform( m );
3694  static_cast<a2dDcContext*>(m_context)->DrawCharFreetype( c );
3695 }
3696 */
3697 
3698 
3699 
3700 #endif // wxART2D_USE_GRAPHICS_CONTEXT
3701 
3702 
3703 
3704 
3705 
3706 
3707 
3708 
3709 
3710 
3711 
3712 
3713 
3714 
3715 
3716 
3717 
3718 
3719 
virtual ~a2dMemDcDrawer()
destructor
Definition: dcdrawer.cpp:2420
virtual void SetYaxis(bool up)
set if the Yaxis goes up or down
Definition: drawer2d.cpp:438
int WorldToDeviceXRel(double x) const
convert x relative from world to device coordinates
Definition: drawer2d.h:460
a2dAffineMatrix m_usertodevice
pointer to current user-to-device transform matrix ( so includes mapping matrix ) ...
Definition: drawer2d.h:1139
a2dStroke m_activestroke
used while rendering
Definition: drawer2d.h:1006
wxPoint2DDouble a2dPoint2D
this to define if coordinate numbers are integer or doubles
Definition: artglob.h:47
a2dDrawStyle m_drawstyle
drawstyle (like invert mode)
Definition: drawer2d.h:1015
void DoSetActiveStroke()
per drawer implementation
Definition: dcdrawer.cpp:487
double GetSize() const
Get the font size.
Definition: stylebase.cpp:2917
void DrawPoint(double xc, double yc)
draw single point
Definition: dcdrawer.cpp:1759
wxUint8 m_StrokeOpacityCol1
active stroke alpha
Definition: drawer2d.h:1101
#define wxDynamicCast(obj, className)
Define wxDynamicCast so that it will give a compiler error for unrelated types.
Definition: gen.h:75
Base class for all types of strokes, understood by a2dDrawer2D classes.
Definition: stylebase.h:378
virtual void SetTransform(const a2dAffineMatrix &userToWorld)
set user-to-world transform matrix.
Definition: drawer2d.cpp:446
a2dStroke m_fixStrokeRestore
used to restore an overruled fix style
Definition: drawer2d.h:1018
bool IsNoStroke() const
Definition: stylebase.h:510
a2dFill m_activefill
used while rendering
Definition: drawer2d.h:1009
Quadratic Bezier curve.
Definition: polyver.h:984
unsigned int ConvertSplinedPolyline2(unsigned int n)
converts internal device points array to spline. Returns new number of points.
Definition: drawer2d.cpp:3046
void SetDrawStyle(a2dDrawStyle drawstyle)
set drawstyle to use for drawing,
Definition: drawer2d.cpp:557
void DrawLine(double x1, double y1, double x2, double y2)
Draw line in world coordinates.
Definition: dcdrawer.cpp:1709
int WorldToDeviceY(double y) const
convert y from world to device coordinates
Definition: drawer2d.h:455
double m_x2
control point
Definition: polyver.h:1025
const a2dStroke * a2dBLACK_STROKE
global a2dStroke stock object for BLACK stroking
Stroke and fill base classes.
virtual void DeviceDrawAnnotation(const wxString &text, wxCoord x, wxCoord y, const wxFont &font)
text drawn in device coordinates
Definition: dcdrawer.cpp:2370
virtual void PopTransform(void)
Recall the previously saved user-to-world transform off the matrix stack.
Definition: drawer2d.cpp:480
wxColour GetColour2() const
return colour 2
Definition: stylebase.cpp:4969
const int SPLINE_STEP
number of steps when converting a spline to lines.
Definition: artglob.h:334
a2dStroke m_currentstroke
used while rendering
Definition: drawer2d.h:1000
a2dDrawStyle m_fixDrawstyle
used to restore an overruled fix style
Definition: drawer2d.h:1024
virtual void DeviceDrawLines(unsigned int n, bool spline)
draw an internal polyline in device coordinates
Definition: dcdrawer.cpp:1985
void SetClippingRegion(a2dVertexList *points, bool spline=false, wxPolygonFillMode fillStyle=wxODDEVEN_RULE)
set clipping region from polygon to which everything drawn will be clipped.
Definition: dcdrawer.cpp:262
void ResetStyle()
set a pre-defined style reseting cashed values.
Definition: dcdrawer.cpp:479
void SetBufferSize(int w, int h)
change the size of the buffer
Definition: dcdrawer.cpp:2500
wxBitmap GetSubBitmap(wxRect sub_rect) const
return a bitmap representing a rectangular part of the buffer
Definition: dcdrawer.cpp:2530
Cubic Bezier curve.
Definition: polyver.h:1045
const a2dFill * a2dBLACK_FILL
global a2dFill stock object for BLACK filling
wxFont & GetFont(void)
wxFont in case of a2dFONT_WXDC
Definition: stylebase.cpp:3030
bool IsStrokeOnly()
wxART2D_USE_GRAPHICS_CONTEXT
Definition: drawer2d.h:847
void SetBufferSize(int w, int h)
set buffer size to w pixel wide and h pixels heigh
Definition: dcdrawer.cpp:216
void DrawEllipse(double xc, double yc, double width, double height)
Draw Ellipse in world coordinates.
Definition: dcdrawer.cpp:1689
void SetRenderDC(wxDC *dc)
set the DC that is used for rendering
Definition: dcdrawer.cpp:248
a2dMemDcDrawer(int width=0, int height=0)
constructor ( just some default )
Definition: dcdrawer.cpp:2411
std::vector< wxRealPoint > m_cpointsDouble
cached array for containing transformed device coordinates (double)
Definition: drawer2d.h:1175
double m_y2
control point
Definition: polyver.h:1027
double DeviceToWorldYRel(double y) const
convert y relative from device to world coordinates
Definition: drawer2d.h:449
double m_y3
control point 2
Definition: polyver.h:1100
virtual void BeginDraw()
start to draw on this context (used to initialize a specific drawer)
Definition: dcdrawer.cpp:160
Arc Segment.
Definition: polyver.h:1112
double GetDescent() const
Get descent.
Definition: stylebase.cpp:3101
void SetDrawerStroke(const a2dStroke &stroke)
Used to set the current stroke.
Definition: drawer2d.cpp:565
bool IsIdentity(void) const
Is the matrix the identity matrix?
Definition: afmatrix.h:147
Defines a font to be set to a2dDrawer2D or stored in a2dCanvsObject etc.
Definition: stylebase.h:779
double m_x3
control point 2
Definition: polyver.h:1098
virtual void DrawPolygon(a2dVertexArray *points, bool spline=false, wxPolygonFillMode fillStyle=wxODDEVEN_RULE)
Draw polygon in world coordinates using pointarray.
Definition: drawer2d.cpp:1889
This class implements drawing functions for wxDC based drawing.
Definition: dcdrawer.h:43
bool GetPixelStroke() const
if the width is pixels or not.
Definition: stylebase.cpp:6335
double GetValue(int col, int row) const
get the value in the matrix at col,row
Definition: afmatrix.cpp:106
bool IsNoFill() const
Definition: stylebase.h:273
bool GetYaxis() const
get y axis orientation
Definition: drawer2d.h:280
void DrawCircle(double xc, double yc, double radius)
Draw Circle in world coordinates.
Definition: dcdrawer.cpp:1599
a2dFont m_currentfont
current font set
Definition: drawer2d.h:1012
This class implements drawing functions for wxDC based drawing.
Definition: dcdrawer.h:203
a2dBoundingBox m_clipboxworld
current clipping area in world coordinates
Definition: drawer2d.h:1196
virtual void DrawCharFreetype(wxChar c)
Draw a freetype character.
Definition: dcdrawer.cpp:2309
a2dAffineMatrix m_usertoworld
pointer to current user-to-world transform matrix
Definition: drawer2d.h:1136
void DrawCharFreetype(wxColour col, wxChar c, int x, int y, FT_Matrix trans_matrix, FT_Vector vec)
draw one character into screen buffer, at the position (x,y).
Definition: dcdrawer.cpp:3214
void DrawCharFreetypeCb(wxChar c)
Wrapper for DrawCharFreetype.
Definition: drawer2d.h:800
wxColour GetColour() const
return colour 1
Definition: stylebase.cpp:6131
unsigned char m_colour1blueStroke
active stroke colours
Definition: drawer2d.h:1114
wxBitmap GetBuffer() const
return buffer as a bitmap
Definition: dcdrawer.h:220
double m_y2
control point 1
Definition: polyver.h:1095
virtual void BeginDraw()
start to draw on this context (used to initialize a specific drawer)
Definition: aggdrawer.cpp:173
bool GetVpath(wxChar c, a2dVpath &glyph, const a2dAffineMatrix &affine=a2dIDENTITY_MATRIX)
Get the glyph of a single character as a vpath.
Definition: stylebase.cpp:3111
void DeviceDrawLine(double x1, double y1, double x2, double y2)
draw in pixels
Definition: dcdrawer.cpp:2011
std::vector< wxPoint > m_cpointsInt
cached array for containing transformed device coordinates (integer)
Definition: drawer2d.h:1172
vertex list of line and arc segments.
Definition: polyver.h:600
void TransformPoint(double x, double y, double &tx, double &ty) const
Transform a point.
Definition: afmatrix.cpp:559
virtual void DrawCenterRoundedRectangle(double xc, double yc, double width, double height, double radius, bool pixelsize=false)
Draw CenterRoundedRectangle in world coordinates.
Definition: drawer2d.cpp:2040
virtual void ExtendClippingRegion(a2dVertexList *points, bool spline=false, wxPolygonFillMode fillStyle=wxODDEVEN_RULE, a2dBooleanClip clipoperation=a2dCLIP_AND)
extend clipping region with a polygon to which everything drawn will be clipped.
Definition: dcdrawer.cpp:313
double GetRotation() const
return rotation
Definition: afmatrix.cpp:799
virtual void EndDraw()
end drawing on this context (used to reset a specific drawer)
Definition: aggdrawer.cpp:191
double TransformDistance(double distance) const
Transform a distance.
Definition: afmatrix.cpp:616
void DrawTextGeneric(const wxString &text, double x, double y, void(a2dDrawer2D::*drawchar)(wxChar))
Definition: drawer2d.cpp:2291
virtual void ExtendAndPushClippingRegion(a2dVertexList *points, bool spline=false, wxPolygonFillMode fillStyle=wxODDEVEN_RULE, a2dBooleanClip clipoperation=a2dCLIP_AND)
push on stack the current clipping region and extend clipping region
Definition: dcdrawer.cpp:301
virtual void SetActiveFill(const a2dFill &fill)
sync with actual API graphical context
Definition: drawer2d.cpp:633
a2dDrawStyle
Define the manner in which a2dCanvasView draws to the device.
Definition: artglob.h:280
void SetClippingRegionDev(wxCoord minx, wxCoord miny, wxCoord width, wxCoord height)
set clipping region using x y values in device coordinates
Definition: dcdrawer.cpp:420
void SetDrawerFill(const a2dFill &fill)
Used to set the current fill.
Definition: drawer2d.cpp:621
int WorldToDeviceYRel(double y) const
convert y relative from world to device coordinates
Definition: drawer2d.h:465
void DestroyClippingRegion()
set clipping region off
Definition: dcdrawer.cpp:469
virtual void PushTransform()
Save the current user-to-world transform on the affine stack.
Definition: drawer2d.cpp:452
a2dClipRegionList m_clipregionlist
pushed clipping regions
Definition: drawer2d.h:1181
void PopClippingRegion()
pop a previously pushed clipping region
Definition: dcdrawer.cpp:396
virtual ~a2dDcDrawer()
destructor
Definition: dcdrawer.cpp:141
virtual void DrawRoundedRectangle(double x, double y, double width, double height, double radius, bool pixelsize=false)
Draw RoundedRectangle in world coordinates.
Definition: drawer2d.cpp:2048
a2dAffineMatrix m_worldtodevice
world to device coordinate mapping
Definition: drawer2d.h:1133
double GetLineHeight() const
Get the line height.
Definition: stylebase.cpp:3096
double m_displayaberration
accuracy of arc segment calculation etc. in device coordinates
Definition: drawer2d.h:1184
virtual void ResetStyle()
set a pre-defined style reseting cashed values.
Definition: drawer2d.cpp:545
void DeviceDrawVerticalLine(int x1, int y1, int y2, bool use_stroke_color)
Draw a pixel-width, unstroked vertical line in device (pixel) coordinates.
Definition: dcdrawer.cpp:2043
#define forEachIn(listtype, list)
easy iteration for a2dlist
Definition: a2dlist.h:111
the antigrain based drawing context derived from a2dDrawer2D
wxDC * m_renderDC
The DC to use to draw to the device or buffer ( depends on type of a2dCanvasView ) ...
Definition: dcdrawer.h:174
unsigned char m_colour1greenStroke
active stroke colours
Definition: drawer2d.h:1112
wxBitmap GetBuffer() const
get buffer as bitmap pointer
Definition: aggdrawer.cpp:2395
void DeviceDrawBitmap(const wxBitmap &bmp, double x, double y, bool useMask=false)
in pixels
Definition: dcdrawer.cpp:2097
#define wxStaticCast(obj, className)
The wxWindows 2.4.2 wxStaticCast is buggy. It evaluates its argument twice.
Definition: gen.h:123
bool IsStroked()
Definition: drawer2d.h:860
Drawing context abstraction.
Definition: drawer2d.h:177
wxBitmap GetSubBitmap(wxRect sub_rect) const
get part of the buffer given a rect
Definition: dcdrawer.cpp:222
bool CalcR(a2dVpathSegmentPtr prev, double &radius, double &center_x, double &center_y, double &beginrad, double &midrad, double &endrad, double &phit)
Calculation of center for the Arc.
Definition: polyver.cpp:3820
void DoSetActiveFill()
per drawer implementation
Definition: dcdrawer.cpp:617
Contains graphical drawing context specific classes. a2dDcDrawer and derived classes are used for dra...
int WorldToDeviceX(double x) const
convert x from world to device coordinates
Definition: drawer2d.h:453
virtual void DrawLine(double x1, double y1, double x2, double y2)
Draw line in world coordinates.
Definition: drawer2d.cpp:2167
virtual void ShiftBuffer(int dxy, bool yshift)
quick scroll over small distance
Definition: dcdrawer.cpp:2613
bool m_yaxis
up or down
Definition: drawer2d.h:1027
the antigrain based drawing context derived from a2dDrawer2D
Definition: aggdrawer.h:601
void SetClippingRegionDev(wxCoord minx, wxCoord miny, wxCoord width, wxCoord height)
set clipping region using x y values in device coordinates
Definition: aggdrawer.cpp:691
double m_x2
control point 1
Definition: polyver.h:1093
A 2x3 affine matrix class for 2D transformations.
Definition: afmatrix.h:53
a2dStroke GetDrawerStroke() const
get the current stroke
Definition: drawer2d.h:548
wxMemoryDC * m_memdc
Created at BeginDraw, and destoyed at EndDraw, used to actually draw.
Definition: dcdrawer.h:267
virtual void SetActiveStroke(const a2dStroke &stroke)
sync with actual API graphical context
Definition: drawer2d.cpp:581
void DeviceDrawPixel(int x1, int y1, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
draw a single, unstroked pixel in device coordinates with the given color
Definition: dcdrawer.cpp:2065
a2dBoundingBox ToWorld(const wxRect &rect)
convert the rect in device coordinates to a bounding box in world coordinates and return that boundin...
Definition: drawer2d.cpp:491
void SetMappingMatrix(const a2dAffineMatrix &mapping)
Definition: drawer2d.cpp:396
int m_height
device size height
Definition: drawer2d.h:1151
bool m_disableDrawing
all drawing is disabled when this is true
Definition: drawer2d.h:1208
void DrawPolyPolygon(a2dListOfa2dVertexList polylist, wxPolygonFillMode fillStyle=wxODDEVEN_RULE)
draw a list of polygons ( contour clockwise becomes hole )
Definition: dcdrawer.cpp:1565
bool GetFilling() const
if true, filling is on else filling is transparent.
Definition: stylebase.cpp:5069
a2dDcDrawer(int width=0, int height=0)
Drawer having a buffer of w pixel wide and h pixels heigh.
Definition: dcdrawer.cpp:134
void DrawImage(const wxImage &image, double x, double y, double width, double height, wxUint8 Opacity=255)
Draw wxImage in world coordinates.
Definition: aggdrawer.cpp:2413
Contains graphical drawing context specific classes. a2dDrawer2D and derived classes are used for dra...
wxPoint * _convertToIntPointCache(int n, wxRealPoint *pts)
Convert double points to integer coords in the point cache and return pointer.
Definition: drawer2d.cpp:529
holes one glyph from a freetype font.
Definition: stylebase.h:581
a2dBooleanClip
Used for defining how a ClippingRegion defined as a polygon is combined with.
Definition: drawer2d.h:54
wxClientDC * m_deviceDC
wxDc to draw or blit to the device
Definition: dcdrawer.h:178
wxRect m_clipboxdev
current clipping area in device coordinates
Definition: drawer2d.h:1199
virtual void DrawCharFreetype(wxChar c)
Draw a freetype character.
Definition: drawer2d.h:966
virtual void BeginDraw()
start to draw on this context (used to initialize a specific drawer)
Definition: dcdrawer.cpp:2438
used in freetype rendering
Definition: dcdrawer.cpp:2165
void FillPolygon(int n, wxRealPoint points[])
Used for filling with Gradient fill style.
Definition: drawer2d.cpp:2614
void Aberration(double aber, double angle, double radius, double &dphi, unsigned int &segments)
calculate number of segments in an arc such that a certain accuracy is maintained ...
Definition: artglob.cpp:67
virtual void DrawPolygon(const a2dVertexList *list, bool spline=false, wxPolygonFillMode fillStyle=wxODDEVEN_RULE)
Draw polygon in world coordinates using pointlist.
Definition: dcdrawer.cpp:2517
virtual void DrawCharDc(wxChar c)
Draw a dc character.
Definition: dcdrawer.cpp:2111
int m_beginDraw_endDraw
counter for BeginDraw EndDraw calls
Definition: drawer2d.h:1202
int m_width
device size width
Definition: drawer2d.h:1148
virtual void DrawCharUnknown(wxChar c)
Draw a cross instead of a character.
Definition: drawer2d.cpp:2178
double m_y1
y endpoint of line
Definition: polyver.h:922
void DeviceDrawHorizontalLine(int x1, int y1, int x2, bool use_stroke_color)
Draw a pixel-width, unstroked horizontal line in device (pixel) coordinates.
Definition: dcdrawer.cpp:2021
unsigned char m_colour1redStroke
active stroke colours
Definition: drawer2d.h:1110
void BlitBuffer()
blit whole buffer to device
Definition: drawer2d.cpp:183
wxColour GetColour() const
return colour
Definition: stylebase.cpp:5012
bool Scale(double scale)
Scale by scale (isotropic scaling i.e. the same in x and y):
Definition: afmatrix.cpp:270
const a2dStroke * a2dTRANSPARENT_STROKE
global a2dStroke stock object for TRANSPARENT stroking
virtual void DeviceDrawPolygon(unsigned int n, bool spline, wxPolygonFillMode fillStyle)
draw an internal polygon in device coordinates
Definition: dcdrawer.cpp:2525
wxWindow * m_display
view its window.
Definition: drawer2d.h:1205
bool m_forceNormalizedFont
up or down
Definition: drawer2d.h:1045
int ToDeviceLines(a2dVertexArray *points, a2dBoundingBox &devbbox, bool &smallPoly, bool replaceByRectangle=false)
convert vertex array containing line and arc segments in user coordinates to device coordinate lines...
Definition: drawer2d.cpp:1310
The a2dBoundingBox class stores one a2dBoundingBox of a a2dCanvasObject.
Definition: bbox.h:39
bool m_externalDc
when dc is set from the outside, this is true.
Definition: dcdrawer.h:181
void DrawVpath(const a2dVpath *path)
Draw vector path in world coordinates.
Definition: dcdrawer.cpp:1179
const a2dAffineMatrix & GetTransform() const
get the user-to-world transform matrix.
Definition: drawer2d.h:500
wxBitmap m_buffer
the buffer that is used for rendering
Definition: dcdrawer.h:264
void DrawRoundedRectangle(double x, double y, double width, double height, double radius, bool pixelsize=false)
Draw RoundedRectangle in world coordinates.
Definition: dcdrawer.cpp:1730
float GetWidth() const
Definition: stylebase.cpp:6281
double m_x1
x endpoint of line
Definition: polyver.h:919
virtual void DrawEllipse(double x, double y, double width, double height)
Draw Ellipse in world coordinates.
Definition: drawer2d.cpp:2121
void DrawImage(const wxImage &image, double x, double y, double width, double height, wxUint8 Opacity=255)
Draw a wxImage in world coordinates.
Definition: dcdrawer.cpp:2662
void ConvertToPolygon(a2dListOfa2dVertexList &addTo, bool arc=true)
Definition: polyver.cpp:4313
#define Round(x)
round to integer such that e.g 2.5 &lt; x &lt; 3.5 becomes 3
Definition: artglob.h:60
virtual void DrawTextDc(const wxString &text, double x, double y)
Draw text in user coordinates, based on a dc font .
Definition: dcdrawer.cpp:2122
void DrawImage(const wxImage &image, double x, double y, double width, double height, wxUint8 Opacity=255)
Draw a wxImage in world coordinates.
Definition: dcdrawer.cpp:840
Vector Path.
Definition: polyver.h:1211
virtual void DeviceDrawPolygon(unsigned int n, bool spline, wxPolygonFillMode fillStyle)
draw an internal polygon in device coordinates
Definition: dcdrawer.cpp:1771
virtual void DrawTextFreetype(const wxString &text, double x, double y)
Draw text in world coordinates, based on a freetype font .
Definition: dcdrawer.cpp:2839
virtual void EndDraw()
end drawing on this context (used to reset a specific drawer)
Definition: dcdrawer.cpp:192
a2dFill m_currentfill
used while rendering
Definition: drawer2d.h:1003
const a2dAffineMatrix & GetMappingMatrix()
get the world-to-device (aka mapping) matrix
Definition: drawer2d.h:478
A pointer class, that automatically calls SmrtPtrOwn/SmrtPtrRelease.
Definition: a2dlist.h:20
wxUint8 m_OpacityFactor
opacity will be the one set, derived by this
Definition: drawer2d.h:1211
double DeviceToWorldXRel(double x) const
convert x relative from device to world coordinates
Definition: drawer2d.h:444
const a2dAffineMatrix & GetUserToDeviceTransform() const
get matrix which transforms directly from user coordinates to device
Definition: drawer2d.h:503
const double wxPI
defines PI
Definition: artglob.cpp:28
virtual void EndDraw()
end drawing on this context (used to reset a specific drawer)
Definition: dcdrawer.cpp:2475
unsigned int ConvertSplinedPolygon2(unsigned int n)
converts internal device points array to spline. Returns new number of points.
Definition: drawer2d.cpp:3014
const a2dFill * a2dTRANSPARENT_FILL
global a2dFill stock object for TRANSPARENT filling
a2dFill m_fixFillRestore
used to restore an overruled fix style
Definition: drawer2d.h:1021
dcdrawer.cpp Source File -- Sun Oct 12 2014 17:04:15 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation