wxArt2D
graphica.cpp
1 /*! \file wx/artbase/graphica.cpp
2 
3  \brief the wxGraphicContext based drawing context
4 
5  Vector path drawing the wx way.
6 
7  \author Klaas Holwerda
8 
9  Copyright: 2001-2004 (C) Klaas Holwerda
10 
11  Licence: wxWidgets licence
12 
13  RCS-ID: $Id: graphica.cpp,v 1.10 2009/10/06 18:40:31 titato Exp $
14 */
15 
16 #include "a2dprec.h"
17 
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21 
22 #ifndef WX_PRECOMP
23 #include "wx/image.h"
24 #include "wx/window.h"
25 #include "wx/dc.h"
26 #include "wx/utils.h"
27 #include "wx/dialog.h"
28 #include "wx/app.h"
29 #include "wx/bitmap.h"
30 #include "wx/dcmemory.h"
31 #include "wx/log.h"
32 #include "wx/icon.h"
33 #include "wx/dcprint.h"
34 #include "wx/module.h"
35 #endif
36 
37 #include "wx/artbase/graphica.h"
38 
39 #include "wx/dc.h"
40 
41 #include "wx/graphics.h"
42 #include "wx/rawbmp.h"
43 
44 #ifdef __WXMSW__
45  #include "wx/msw/dcclient.h"
46  #include "wx/msw/dcmemory.h"
47  #include "wx/msw/dcscreen.h"
48 #endif
49 
50 #ifdef __WXGTK3__
51  #include "wx/gtk/dc.h"
52 #elif defined __WXGTK20__
53 #include "wx/gtk/dcclient.h"
54 #elif defined(__WXGTK__)
55  #include "wx/gtk1/dcclient.h"
56  #include "wx/gtk1/dcmemory.h"
57  #include "wx/gtk1/dcscreen.h"
58 #endif
59 
60 #ifdef __WXMAC__
61  #include "wx/osx/dcclient.h"
62  #include "wx/osx/dcmemory.h"
63  #include "wx/osx/dcscreen.h"
64 #endif
65 
66 #ifdef __WXPM__
67  #include "wx/os2/dcclient.h"
68  #include "wx/os2/dcmemory.h"
69  #include "wx/os2/dcscreen.h"
70 #endif
71 
72 #ifdef __WXCOCOA__
73  #include "wx/cocoa/dcclient.h"
74  #include "wx/cocoa/dcmemory.h"
75  #include "wx/cocoa/dcscreen.h"
76 #endif
77 
78 #ifdef __WXMOTIF__
79  #include "wx/motif/dcclient.h"
80  #include "wx/motif/dcmemory.h"
81  #include "wx/motif/dcscreen.h"
82 #endif
83 
84 #ifdef __WXX11__
85  #include "wx/x11/dcclient.h"
86  #include "wx/x11/dcmemory.h"
87  #include "wx/x11/dcscreen.h"
88 #endif
89 
90 #ifdef __WXDFB__
91  #include "wx/dfb/dcclient.h"
92  #include "wx/dfb/dcmemory.h"
93  #include "wx/dfb/dcscreen.h"
94 #endif
95 
96 #if defined(__WXMSW__)
97  #include <wx/msw/private.h>
98 #elif defined(__WXGTK__)
99  #include <wx/dcps.h>
100 #endif
101 
102 #if wxART2D_USE_FREETYPE
103 #include <ft2build.h>
104 #ifdef _MSC_VER
105 // Do not use the define include for MSVC, because of a bug with precompiled
106 // headers. See (freetype)/doc/INSTALL.ANY for (some) more information
107 #include <freetype/freetype.h>
108 #include <freetype/ftoutln.h>
109 #else // _MSC_VER
110 // This is the way it should be included.
111 #include FT_FREETYPE_H
112 #include FT_OUTLINE_H
113 #endif // _MSC_VER
114 #endif
115 
116 #if wxART2D_USE_GRAPHICS_CONTEXT
117 
118 #include <vector>
119 
120 using namespace std;
121 
122 //-----------------------------------------------------------------------------
123 // constants
124 //-----------------------------------------------------------------------------
125 
126 const double RAD2DEG = 180.0 / M_PI;
127 
128 //-----------------------------------------------------------------------------
129 // Local functions
130 //-----------------------------------------------------------------------------
131 
132 static inline double dmin( double a, double b )
133 {
134  return a < b ? a : b;
135 }
136 static inline double dmax( double a, double b )
137 {
138  return a > b ? a : b;
139 }
140 
141 static inline double DegToRad( double deg )
142 {
143  return ( deg * M_PI ) / 180.0;
144 }
145 static inline double RadToDeg( double deg )
146 {
147  return ( deg * 180.0 ) / M_PI;
148 }
149 
150 
151 //-----------------------------------------------------------------------------
152 // wxGraphicsPath implementation
153 //-----------------------------------------------------------------------------
154 
155 // TODO remove this dependency (gdiplus needs the macros)
156 
157 #ifndef max
158 #define max(a,b) (((a) > (b)) ? (a) : (b))
159 #endif
160 
161 #ifndef min
162 #define min(a,b) (((a) < (b)) ? (a) : (b))
163 #endif
164 
165 
166 //-----------------------------------------------------------------------------
167 // a2dStrokeData implementation
168 //-----------------------------------------------------------------------------
169 
170 a2dStrokeData::~a2dStrokeData()
171 {
172 }
173 
174 void a2dStrokeData::Init()
175 {
176 }
177 
178 a2dStrokeData::a2dStrokeData( wxGraphicsRenderer* renderer, const wxPen& pen )
179  : wxGraphicsObjectRefData( renderer )
180 {
181  Init();
182  m_stroke = a2dStroke( pen );
183 }
184 
185 a2dStrokeData::a2dStrokeData( wxGraphicsRenderer* renderer, const a2dStroke& stroke )
186  : wxGraphicsObjectRefData( renderer )
187 {
188  Init();
189  m_stroke = stroke;
190 }
191 
192 void a2dStrokeData::Apply( wxGraphicsContext* context )
193 {
194  a2dContext* ctext = ( a2dContext* ) context->GetNativeContext();
195  ctext->SetStroke( m_stroke );
196 }
197 
198 //-----------------------------------------------------------------------------
199 // a2dFillData implementation
200 //-----------------------------------------------------------------------------
201 
202 a2dFillData::a2dFillData( wxGraphicsRenderer* renderer )
203  : wxGraphicsObjectRefData( renderer )
204 {
205  Init();
206 }
207 
208 a2dFillData::a2dFillData( wxGraphicsRenderer* renderer, const wxBrush& brush )
209  : wxGraphicsObjectRefData( renderer )
210 {
211  Init();
212  m_fill = a2dFill( brush );
213 }
214 
215 a2dFillData::a2dFillData( wxGraphicsRenderer* renderer, const a2dFill& fill )
216  : wxGraphicsObjectRefData( renderer )
217 {
218  Init();
219  m_fill = fill;
220 }
221 
222 a2dFillData::~a2dFillData ()
223 {
224 }
225 
226 void a2dFillData::Apply( wxGraphicsContext* context )
227 {
228  a2dContext* ctext = ( a2dContext* ) context->GetNativeContext();
229  ctext->SetFill( m_fill );
230 }
231 
232 #if wxCHECK_VERSION(2, 9, 1)
233 void a2dFillData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
234  const wxGraphicsGradientStops& stops )
235 {
236  //todo
237  m_fill = a2dFill();
238 }
239 
240 void a2dFillData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
241  const wxGraphicsGradientStops& stops )
242 {
243  //todo
244  m_fill = a2dFill();
245 }
246 #else
247 void a2dFillData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
248  const wxColour& c1, const wxColour& c2 )
249 {
250  //todo
251  m_fill = a2dFill();
252 }
253 
254 void a2dFillData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
255  const wxColour& oColor, const wxColour& cColor )
256 {
257  //todo
258  m_fill = a2dFill();
259 }
260 #endif
261 
262 
263 void a2dFillData::Init()
264 {
265 }
266 
267 //-----------------------------------------------------------------------------
268 // a2dFontData implementation
269 //-----------------------------------------------------------------------------
270 
271 a2dFontData::a2dFontData( wxGraphicsRenderer* renderer, const wxFont& font,
272  const wxColour& col ) : wxGraphicsObjectRefData( renderer )
273 {
274  m_font = a2dFont( font, font.GetPointSize() );
275 }
276 
277 a2dFontData::a2dFontData( wxGraphicsRenderer* renderer, const a2dFont& font )
278  : wxGraphicsObjectRefData( renderer )
279 {
280  m_font = font;
281 }
282 
283 a2dFontData::~a2dFontData()
284 {
285 }
286 
287 void a2dFontData::Apply( wxGraphicsContext* context )
288 {
289  a2dContext* ctext = ( a2dContext* ) context->GetNativeContext();
290  ctext->SetFont( m_font );
291 }
292 
293 //-----------------------------------------------------------------------------
294 // a2dPathData implementation
295 //-----------------------------------------------------------------------------
296 
297 a2dPathData::a2dPathData( wxGraphicsRenderer* renderer, a2dVpath* path )
298  : wxGraphicsPathData( renderer )
299 {
300  if ( path )
301  m_path = *path;
302  else
303  m_path = a2dVpath();
304 
305 }
306 
307 a2dPathData::~a2dPathData()
308 {
309 }
310 
311 wxGraphicsObjectRefData* a2dPathData::Clone() const
312 {
313  a2dVpath* p = new a2dVpath( m_path );
314  return new a2dPathData( GetRenderer() , p );
315 }
316 
317 
318 void* a2dPathData::GetNativePath() const
319 {
320  return ( void* ) &m_path;
321 }
322 
323 void a2dPathData::UnGetNativePath( void* p ) const
324 {
325 }
326 
327 //
328 // The Primitives
329 //
330 
331 void a2dPathData::MoveToPoint( wxDouble x , wxDouble y )
332 {
333  m_path.MoveTo( x, y );
334 }
335 
336 void a2dPathData::AddLineToPoint( wxDouble x , wxDouble y )
337 {
338  m_path.LineTo( x, y );
339 }
340 
341 void a2dPathData::AddPath( const wxGraphicsPathData* path )
342 {
343  a2dVpath* p = ( a2dVpath* )path->GetNativePath();
344  m_path = *p;
345 }
346 
347 void a2dPathData::CloseSubpath()
348 {
349  m_path.back()->SetClose( a2dPATHSEG_END_CLOSED );
350 }
351 
352 void a2dPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
353 {
354  m_path.CBCurveTo( cx1, cy1, cx2, cy2, x, y );
355 }
356 
357 // gets the last point of the current path, (0,0) if not yet set
358 void a2dPathData::GetCurrentPoint( wxDouble* x, wxDouble* y ) const
359 {
360  double dx, dy;
361  a2dVpathSegmentPtr seg = m_path.back();
362  dx = seg->m_x1;
363  dy = seg->m_y1;
364  if ( x )
365  *x = dx;
366  if ( y )
367  *y = dy;
368 }
369 
370 void a2dPathData::AddArc( wxDouble xc, wxDouble yc, wxDouble radius, double startAngle, double endAngle, bool clockwise )
371 {
372  if ( ( endAngle - startAngle ) >= 2 * M_PI )
373  {
374  double x1 = xc + radius;
375  double y1 = yc;
376  double x2 = xc + radius;
377  double y2 = yc;
378  double xm = xc - radius;
379  double ym = yc;
380  m_path.ArcTo( xc, yc, x2 , y2, xm, ym );
381  }
382  else if ( clockwise || ( endAngle - startAngle ) >= 2 * M_PI )
383  {
384  double x1 = xc + radius * cos( startAngle );
385  double y1 = yc + radius * sin( startAngle );
386  double x2 = xc + radius * cos( endAngle );
387  double y2 = yc + radius * sin( endAngle );
388 
389  //if going counterclockwise from begin to end we pass trough middle => counterclockwise
390  //if going counterclockwise from begin to end we do NOT pass trough middle => clockwise
391  double er;
392 
393  //rotate such that startAngle = zero
394  er = endAngle - startAngle;
395  //make positive
396  if ( er <= 0 ) er += 2.0 * M_PI;
397  if ( er >= 2.0 * M_PI ) er -= 2.0 * M_PI;
398 
399  double midrad;
400  midrad = er / 2.0 + startAngle;
401 
402  double xm = xc + radius * cos( midrad );
403  double ym = yc + radius * sin( midrad );
404 
405  //m_path.MoveTo( x1, y1 );
406  m_path.ArcTo( xc, yc, x2 , y2, xm, ym );
407  }
408  else
409  {
410  double x1 = xc + radius * cos( startAngle );
411  double y1 = yc + radius * sin( startAngle );
412  double x2 = xc + radius * cos( endAngle );
413  double y2 = yc + radius * sin( endAngle );
414 
415  //if going counterclockwise from begin to end we pass trough middle => counterclockwise
416  //if going counterclockwise from begin to end we do NOT pass trough middle => clockwise
417  double er;
418 
419  //rotate such that startAngle = zero
420  er = endAngle - startAngle;
421  //make positive
422  if ( er <= 0 ) er += 2.0 * M_PI;
423  if ( er >= 2.0 * M_PI ) er -= 2.0 * M_PI;
424 
425  double midrad;
426  midrad = ( 2.0 * M_PI - er / 2.0 );
427 
428  double xm = xc + radius * cos( midrad );
429  double ym = yc + radius * sin( midrad );
430 
431  //m_path.MoveTo( x1, y1 );
432  m_path.ArcTo( xc, yc, x2 , y2, xm, ym );
433  }
434 }
435 
436 // transforms each point of this path by the matrix
437 void a2dPathData::Transform( const wxGraphicsMatrixData* matrix )
438 {
439  // as we don't have a true path object, we have to apply the inverse
440  // matrix to the context
441  a2dAffineMatrix m = *( ( a2dAffineMatrix* ) matrix->GetNativeMatrix() );
442  m_path.Transform( m );
443 }
444 
445 // gets the bounding box enclosing all points (possibly including control points)
446 void a2dPathData::GetBox( wxDouble* x, wxDouble* y, wxDouble* w, wxDouble* h ) const
447 {
448  double x1, y1, x2, y2;
449 
450  //cairo_stroke_extents( m_pathContext, &x1, &y1, &x2, &y2 );
451  x1 = 0;
452  y1 = 0;
453  x2 = 1000;
454  y2 = 1000;
455 
456  if ( x2 < x1 )
457  {
458  *x = x2;
459  *w = x1 - x2;
460  }
461  else
462  {
463  *x = x1;
464  *w = x2 - x1;
465  }
466 
467  if( y2 < y1 )
468  {
469  *y = y2;
470  *h = y1 - y2;
471  }
472  else
473  {
474  *y = y1;
475  *h = y2 - y1;
476  }
477 }
478 
479 bool a2dPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle ) const
480 {
481  return false;//cairo_in_stroke( m_pathContext, x, y) != 0;
482 }
483 
484 //-----------------------------------------------------------------------------
485 // a2dMatrixData implementation
486 //-----------------------------------------------------------------------------
487 
488 a2dMatrixData::a2dMatrixData( wxGraphicsRenderer* renderer, const a2dAffineMatrix* matrix )
489  : wxGraphicsMatrixData( renderer )
490 {
491  if ( matrix )
492  m_matrix = *matrix;
493 }
494 
495 a2dMatrixData::~a2dMatrixData()
496 {
497  // nothing to do
498 }
499 
500 wxGraphicsObjectRefData* a2dMatrixData::Clone() const
501 {
502  return new a2dMatrixData( GetRenderer(), &m_matrix );
503 }
504 
505 // concatenates the matrix
506 void a2dMatrixData::Concat( const wxGraphicsMatrixData* t )
507 {
508  m_matrix *= *( ( a2dAffineMatrix* ) t->GetNativeMatrix() );
509 }
510 
511 // sets the matrix to the respective values
512 void a2dMatrixData::Set( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
513  wxDouble tx, wxDouble ty )
514 {
515  m_matrix = a2dAffineMatrix( a, b, c, d, tx, ty );
516 }
517 
518 // gets the component valuess of the matrix
519 void a2dMatrixData::Get( wxDouble* a, wxDouble* b, wxDouble* c,
520  wxDouble* d, wxDouble* tx, wxDouble* ty ) const
521 {
522  if ( a ) *a = m_matrix( 0, 0 );
523  if ( b ) *b = m_matrix( 0, 1 );
524  if ( c ) *c = m_matrix( 1, 0 );
525  if ( d ) *d = m_matrix( 1, 1 );
526  if ( tx ) *tx = m_matrix( 2, 0 );
527  if ( ty ) *ty = m_matrix( 2, 1 );
528 }
529 
530 // makes this the inverse matrix
531 void a2dMatrixData::Invert()
532 {
533  m_matrix.Invert();
534 }
535 
536 // returns true if the elements of the transformation matrix are equal ?
537 bool a2dMatrixData::IsEqual( const wxGraphicsMatrixData* t ) const
538 {
539  return m_matrix == *( ( a2dAffineMatrix* ) t->GetNativeMatrix() );
540 }
541 
542 // return true if this is the identity matrix
543 bool a2dMatrixData::IsIdentity() const
544 {
545  return m_matrix.IsIdentity();
546 }
547 
548 //
549 // transformation
550 //
551 
552 // add the translation to this matrix
553 void a2dMatrixData::Translate( wxDouble dx , wxDouble dy )
554 {
555  m_matrix.Translate( dx, dy ) ;
556 }
557 
558 // add the scale to this matrix
559 void a2dMatrixData::Scale( wxDouble xScale , wxDouble yScale )
560 {
561  m_matrix.Scale( xScale, yScale, m_matrix( 2, 0 ), m_matrix( 2, 0 ) ) ;
562 }
563 
564 // add the rotation to this matrix (radians)
565 void a2dMatrixData::Rotate( wxDouble angle )
566 {
567  m_matrix.Rotate( angle ) ;
568 }
569 
570 //
571 // apply the transforms
572 //
573 
574 // applies that matrix to the point
575 void a2dMatrixData::TransformPoint( wxDouble* x, wxDouble* y ) const
576 {
577  double lx = *x, ly = *y ;
578  m_matrix.TransformPoint( lx, ly );
579  *x = lx;
580  *y = ly;
581 }
582 
583 // applies the matrix except for translations
584 void a2dMatrixData::TransformDistance( wxDouble* dx, wxDouble* dy ) const
585 {
586  double lx = *dx, ly = *dy ;
587  //todo
588  m_matrix.TransformDistance( lx, ly );
589  *dx = lx;
590  *dy = ly;
591 }
592 
593 // returns the native representation
594 void* a2dMatrixData::GetNativeMatrix() const
595 {
596  return ( void* ) &m_matrix;
597 }
598 
599 //-----------------------------------------------------------------------------
600 // wxAggBitmap implementation
601 //-----------------------------------------------------------------------------
602 
603 a2dBitmapData::a2dBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ) : wxGraphicsObjectRefData( renderer )
604 {
605  wxCHECK_RET( bmp.IsOk(), wxT( "Invalid bitmap in a2dBitmapData" ) );
606 
607  m_width = bmp.GetWidth();
608  m_height = bmp.GetHeight();
609  m_image = bmp.ConvertToImage();
610 }
611 
612 a2dBitmapData::a2dBitmapData( wxGraphicsRenderer* renderer, const wxImage& image ) : wxGraphicsObjectRefData( renderer )
613 {
614  wxCHECK_RET( image.IsOk(), wxT( "Invalid image in a2dBitmapData" ) );
615 
616  m_width = image.GetWidth();
617  m_height = image.GetHeight();
618  m_image = image;
619 }
620 
621 a2dBitmapData::a2dBitmapData( wxGraphicsRenderer* renderer, const wxGraphicsBitmap& a2dbitmap ) : wxGraphicsObjectRefData( renderer )
622 {
623  a2dBitmapData* data = ( a2dBitmapData* ) a2dbitmap.GetRefData();
624 
625  m_width = data->GetSize().GetWidth();
626  m_height = data->GetSize().GetHeight();
627  m_image = data->GetImage();
628 }
629 
630 a2dBitmapData::~a2dBitmapData()
631 {
632 }
633 
634 //-----------------------------------------------------------------------------
635 // a2dContext implementation
636 //-----------------------------------------------------------------------------
637 
638 a2dContext::a2dContext( wxGraphicsRenderer* renderer, a2dContext* context )
639  :
640  m_width( context->m_width ),
641  m_height( context->m_height ),
642  m_drawstyle( a2dFILLED ),
643  wxGraphicsContext( renderer )
644 {
645  Init();
646 }
647 
648 a2dContext::a2dContext( wxGraphicsRenderer* renderer, int width, int height )
649  :
650  m_width( width ),
651  m_height( height ),
652  m_drawstyle( a2dFILLED ),
653  wxGraphicsContext( renderer )
654 {
655  Init();
656 }
657 
658 a2dContext::a2dContext( wxGraphicsRenderer* renderer )
659  :
660  m_width( 0 ),
661  m_height( 0 ),
662  m_drawstyle( a2dFILLED ),
663  wxGraphicsContext( renderer )
664 {
665  Init();
666 }
667 
668 void a2dContext::Init()
669 {
670  m_activestroke = *a2dBLACK_STROKE;
671  m_activefill = *a2dBLACK_FILL;
672  m_a2dfont = *a2dNullFONT;
673  m_OpacityFactor = 255;
674  m_displayaberration = 0.5;
675  m_yaxis = false;
676  m_drawingthreshold = a2dGlobals->GetPrimitiveThreshold();
677 }
678 
679 /*
680 a2dContext::a2dContext( wxGraphicsRenderer* renderer, const wxImage& drawable )
681 :
682  m_width( drawable.GetWidth() ),
683  m_height( drawable.GetHeight() ),
684  wxGraphicsContext(renderer)
685 {
686 }
687 
688 a2dContext::a2dContext( wxGraphicsRenderer* renderer, wxWindow *window)
689 :
690  m_width( window->GetSize().GetWidth() ),
691  m_height( window->GetSize().GetHeight() ),
692  wxGraphicsContext(renderer)
693 {
694 }
695 */
696 
697 a2dContext::~a2dContext()
698 {
699  PopState();
700  PopState();
701 }
702 
703 void a2dContext::SetYaxis( bool up )
704 {
705  m_yaxis = up;
706 }
707 
708 void a2dContext::SetPen( const wxGraphicsPen& pen )
709 {
710  wxGraphicsContext::SetPen( pen );
711 
712  if ( !pen.IsNull() )
713  ( ( a2dStrokeData* )pen.GetRefData() )->Apply( this );
714  else
715  SetStroke( *a2dTRANSPARENT_STROKE );
716 }
717 
718 void a2dContext::SetBrush( const wxGraphicsBrush& brush )
719 {
720  wxGraphicsContext::SetBrush( brush );
721 
722  if ( !brush.IsNull() )
723  ( ( a2dFillData* )brush.GetRefData() )->Apply( this );
724  else
725  SetFill( *a2dTRANSPARENT_FILL );
726 }
727 
728 void a2dContext::SetFont( const wxGraphicsFont& font )
729 {
730  wxGraphicsContext::SetFont( font );
731  ( ( a2dFontData* ) font.GetRefData() )->Apply( this );
732 }
733 
734 void a2dContext::SetStroke( const a2dStroke& stroke )
735 {
736  switch( m_drawstyle )
737  {
738  case a2dWIREFRAME_INVERT:
739  case a2dWIREFRAME:
741  m_activestroke = stroke;
742  break;
744  m_activestroke = *a2dBLACK_STROKE;
745  break;
746  case a2dFILLED:
747  m_activestroke = stroke;
748  break;
749  case a2dFIX_STYLE:
750  break;
751  case a2dFIX_STYLE_INVERT:
752  break;
753  default:
754  wxASSERT( 0 );
755  }
756 
757  m_colour1redStroke = m_activestroke.GetColour().Red();
758  m_colour1greenStroke = m_activestroke.GetColour().Green();
759  m_colour1blueStroke = m_activestroke.GetColour().Blue();
760 
761  if ( m_activestroke.IsNoStroke() || m_activestroke.GetStyle() == a2dSTROKE_TRANSPARENT )
762  {
763  m_StrokeOpacityCol1 = 0;
764  m_StrokeOpacityCol2 = 0;
765  }
766  else
767  {
768  m_StrokeOpacityCol1 = m_activestroke.GetColour().Alpha() * m_OpacityFactor / 255 ;
769  m_StrokeOpacityCol2 = m_activestroke.GetColour().Alpha() * m_OpacityFactor / 255 ;
770  }
771  DoSetActiveStroke();
772 }
773 
774 void a2dContext::SetFill( const a2dFill& fill )
775 {
776  switch( m_drawstyle )
777  {
778  case a2dWIREFRAME_INVERT:
779  case a2dWIREFRAME:
782  m_activefill = *a2dTRANSPARENT_FILL;
783  break;
784  case a2dFILLED:
785  m_activefill = fill;
786  break;
787  case a2dFIX_STYLE:
788  case a2dFIX_STYLE_INVERT:
789  break;
790  default:
791  wxASSERT( 0 );
792  }
793 
794  m_colour1redFill = m_activefill.GetColour().Red();
795  m_colour1greenFill = m_activefill.GetColour().Green();
796  m_colour1blueFill = m_activefill.GetColour().Blue();
797  m_colour2redFill = m_activefill.GetColour2().Red();
798  m_colour2greenFill = m_activefill.GetColour2().Green();
799  m_colour2blueFill = m_activefill.GetColour2().Blue();
800 
801  if ( !m_activefill.GetFilling() )
802  {
803  m_FillOpacityCol1 = 0;
804  m_FillOpacityCol2 = 0;
805  }
806  else if ( m_activefill.GetStyle() == a2dFILL_TRANSPARENT )
807  {
808  m_FillOpacityCol1 = 0;
809  m_FillOpacityCol2 = 0;
810  }
811  else if ( m_activefill.IsNoFill() )
812  {
813  m_FillOpacityCol1 = 0;
814  m_FillOpacityCol2 = 0;
815  }
816  else
817  {
818  m_FillOpacityCol1 = m_activefill.GetColour().Alpha() * m_OpacityFactor / 255;
819  m_FillOpacityCol2 = m_activefill.GetColour2().Alpha() * m_OpacityFactor / 255;
820  }
821 
822  DoSetActiveFill();
823 }
824 
825 void a2dContext::SetFont( const a2dFont& font )
826 {
827  m_a2dfont = font;
828 }
829 
830 void a2dContext::Clip( const wxRegion& region )
831 {
832  // Create a path with all the rectangles in the region
833  wxGraphicsPath path = GetRenderer()->CreatePath();
834  wxRegionIterator ri( region );
835  while ( ri )
836  {
837  path.AddRectangle( ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH() );
838  ri++;
839  }
840 
841  //todo multiclipping render needed
842 }
843 
844 void a2dContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
845 {
846  //need to calculate clip in device coordinates from world coordinates
847  // not even rectangular in the end, so assume a polygon as result.
848  wxPoint trpoints[4];
849  double dx, dy;
850 
851  m_usertodevice.TransformPoint( x, y, dx, dy );
852  trpoints[0] = wxPoint( dx, dy );
853  m_usertodevice.TransformPoint( x, y + h, dx, dy );
854  trpoints[1] = wxPoint( dx, dy );
855  m_usertodevice.TransformPoint( x + w, y + h, dx, dy );
856  trpoints[2] = wxPoint( dx, dy );
857  m_usertodevice.TransformPoint( x + w, y, dx, dy );
858  trpoints[3] = wxPoint( dx, dy );
859 
860  double xmin = trpoints[0].x;
861  double ymin = trpoints[0].y;
862  double xmax = trpoints[0].x;
863  double ymax = trpoints[0].y;
864  for ( int i = 1; i < 4; i ++ )
865  {
866  xmin = wxMin( xmin, trpoints[i].x );
867  xmax = wxMax( xmin, trpoints[i].x );
868  ymin = wxMin( ymin, trpoints[i].y );
869  ymax = wxMax( ymin, trpoints[i].y );
870  }
871  wxRect cliprect = wxRect( xmin, ymin, xmax - xmin, ymax - ymin );
872  m_clipboxdev = cliprect;
873 }
874 
875 void a2dContext::ResetClip()
876 {
877  m_clipboxdev = wxRect( 0, 0, m_width, m_height );
878 }
879 
880 void a2dContext::DrawPath( const wxGraphicsPath& path, wxPolygonFillMode fillStyle )
881 {
882  if ( !m_pen.IsNull() || !m_brush.IsNull() )
883  {
884  a2dVpath* cp = ( a2dVpath* ) path.GetNativePath() ;
885  /*
886  if ( !m_pen.IsNull() )
887  ((a2dStrokeData*)m_pen.GetRefData())->Apply(this);
888  else
889  SetStroke( *a2dTRANSPARENT_STROKE );
890  if ( !m_brush.IsNull() )
891  ((a2dFillData*)m_brush.GetRefData())->Apply(this);
892  else
893  SetFill( *a2dTRANSPARENT_FILL );
894  */
895  DrawVpath( cp );
896  }
897 }
898 
899 void a2dContext::StrokePath( const wxGraphicsPath& path )
900 {
901  if ( !m_pen.IsNull() )
902  {
903  a2dVpath* cp = ( a2dVpath* ) path.GetNativePath() ;
904  //((a2dStrokeData*)m_pen.GetRefData())->Apply(this);
905 
906  a2dFill curfill = m_activefill;
907  SetFill( *a2dTRANSPARENT_FILL );
908  DrawVpath( cp );
909  SetFill( curfill );
910  }
911 }
912 
913 void a2dContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fillStyle )
914 {
915  if ( !m_brush.IsNull() )
916  {
917  a2dVpath* cp = ( a2dVpath* ) path.GetNativePath() ;
918  //((a2dFillData*)m_brush.GetRefData())->Apply(this);
919 
920  a2dStroke curstroke = m_activestroke;
921  m_activestroke = *a2dTRANSPARENT_STROKE;
922  DrawVpath( cp );
923  m_activestroke = curstroke;
924  }
925 }
926 
927 void a2dContext::Rotate( wxDouble angle )
928 {
929  m_usertodevice.Rotate( angle ) ;
930 }
931 
932 void a2dContext::Translate( wxDouble dx , wxDouble dy )
933 {
934  m_usertodevice.Translate( dx, dy ) ;
935 }
936 
937 void a2dContext::Scale( wxDouble xScale , wxDouble yScale )
938 {
939  m_usertodevice.Scale( xScale, yScale, 0, 0 ) ;
940 }
941 
942 // concatenates this transform with the current transform of this context
943 void a2dContext::ConcatTransform( const wxGraphicsMatrix& matrix )
944 {
945  a2dAffineMatrix* m = ( a2dAffineMatrix* ) matrix.GetNativeMatrix();
946  m_usertodevice *= *m;
947 }
948 
949 // sets the transform of this context
950 void a2dContext::SetTransform( const wxGraphicsMatrix& matrix )
951 {
952  a2dAffineMatrix* m = ( a2dAffineMatrix* ) matrix.GetNativeMatrix();
953  m_usertodevice = *m;
954 }
955 
956 // gets the matrix of this context
957 wxGraphicsMatrix a2dContext::GetTransform() const
958 {
959  wxGraphicsMatrix matrix = CreateMatrix();
960  a2dAffineMatrix* m = ( a2dAffineMatrix* ) matrix.GetNativeMatrix();
961  *m = m_usertodevice;
962  return matrix;
963 }
964 
965 void a2dContext::PushState()
966 {
967 }
968 
969 void a2dContext::PopState()
970 {
971 }
972 
973 #if wxCHECK_VERSION(2,9,0)
974 void a2dContext::DrawBitmap( const wxGraphicsBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
975 #else
976 void a2dContext::DrawGraphicsBitmap( const wxGraphicsBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
977 #endif
978 {
979  a2dBitmapData* data = static_cast<a2dBitmapData*>( bmp.GetRefData() );
980  wxImage image = data->GetImage();
981 }
982 
983 void a2dContext::DrawBitmap( const wxBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
984 {
985  wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap( bmp );
986 #if wxCHECK_VERSION(2,9,0)
987  DrawBitmap( bitmap, x, y, w, h );
988 #else
989  DrawGraphicsBitmap( bitmap, x, y, w, h );
990 #endif
991 }
992 
993 void a2dContext::DrawIcon( const wxIcon& icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
994 {
995  //DrawBitmap(icon, x, y, w, h);
996 }
997 
998 #if wxCHECK_VERSION(2,9,0)
999 void a2dContext::DoDrawText( const wxString& str, wxDouble x, wxDouble y )
1000 #else
1001 void a2dContext::DrawText( const wxString& str, wxDouble x, wxDouble y )
1002 #endif
1003 {
1004  if ( str.empty() )
1005  return;
1006 
1007  //const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
1008  //wxWCharBuffer s = str.wc_str( *wxConvUI );
1009 
1010  // Get the bounding box, including alignment displacement.
1011  a2dBoundingBox bbox = m_a2dfont.GetTextExtent( str, wxMINX | wxMINY, false );
1012  bbox.Translate( x, y );
1013 
1014  // Get unaligned coordinates for DrawTextXXX functions. By default these functions
1015  // use the lowerleft corner of the boundingbox, hence GetMinX() and GetMinY().
1016  x = bbox.GetMinX();
1017  y = bbox.GetMinY();
1018 
1019  // Get font size in device units, also takes stretching into account
1020  double dx, dy, size;
1021  dx = m_usertodevice.GetValue( 1, 0 );
1022  dy = m_usertodevice.GetValue( 1, 1 );
1023  size = m_a2dfont.GetSize() * sqrt( dx * dx + dy * dy );
1024 
1025  // Transform user bbox to world bbox.
1026  a2dBoundingBox worldbbox( bbox );
1027  worldbbox.MapBbox( m_usertodevice );
1028  wxRect devb = wxRect( worldbbox.GetMinX(), worldbbox.GetMinY(), worldbbox.GetWidth(), worldbbox.GetHeight() );
1029 
1030  // If bbox not outside clipping area, draw the text
1031  if ( m_clipboxdev.Intersects( devb ) )
1032  {
1033  // add this to see tranformed boundingbox.
1034  //DrawRoundedRectangle( bbox.GetMinX(), bbox.GetMinY(), bbox.GetWidth(), bbox.GetHeight(), 0 );
1035 
1036  // If text > threshold, draw text
1037  if ( size > m_drawingthreshold )
1038  {
1039  // Try to find the appropriate drawing function.
1040  switch ( m_a2dfont.GetType() )
1041  {
1042  case a2dFONT_STROKED:
1043  DrawTextStroke( str, x, y );
1044  break;
1045  case a2dFONT_FREETYPE:
1046  DrawTextFreetype( str, x, y );
1047  break;
1048  case a2dFONT_WXDC:
1049  DrawTextDc( str, x, y );
1050  break;
1051  default:
1052  DrawTextUnknown( str, x, y );
1053  }
1054  }
1055  // If text < threshold, draw a simple version.
1056  else
1057  DrawTextUnknown( str, x, y, true );
1058  }
1059 }
1060 
1061 
1062 void a2dContext::GetTextExtent( const wxString& str, wxDouble* width, wxDouble* height,
1063  wxDouble* descent, wxDouble* externalLeading ) const
1064 {
1065  if ( str.empty() )
1066  return;
1067 
1068  if ( width )
1069  {
1070  const wxWX2MBbuf buf( str.mb_str( wxConvUTF8 ) );
1071  }
1072 
1073  if ( height || descent || externalLeading )
1074  {
1075  }
1076 }
1077 
1078 void a2dContext::GetPartialTextExtents( const wxString& text, wxArrayDouble& widths ) const
1079 {
1080  widths.Empty();
1081  widths.Add( 0, text.length() );
1082 
1083  if ( text.empty() )
1084  return;
1085 
1086  // TODO
1087 }
1088 
1089 void* a2dContext::GetNativeContext()
1090 {
1091  return this;
1092 }
1093 
1094 //------------------------------------------------------------------------
1095 // basic platform independent drawing of primitives
1096 //------------------------------------------------------------------------
1097 int a2dContext::ToDeviceLines( a2dVertexArray* points, a2dBoundingBox& devbbox, bool& smallPoly, bool replaceByRectangle )
1098 {
1099  unsigned int segments = 0;
1100 
1101  unsigned int i;
1102  for ( i = 0; i < points->size(); i++ )
1103  {
1104  const a2dLineSegmentPtr seg = points->operator[]( i );
1105 
1106  if ( seg->GetArc() )
1107  {
1108  const a2dArcSegment* cseg = ( const a2dArcSegment* ) ( seg.Get() );
1109 
1110  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1111 
1112  if ( cseg->CalcR( *( points->operator[]( i ? i - 1 : 0 ) ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1113  {
1114  double dphi;
1115  unsigned int circlesegments;
1116  double radiusDev = m_usertodevice.TransformDistance( radius );
1117  Aberration( m_displayaberration, phit, radiusDev , dphi, circlesegments );
1118  segments += circlesegments + 1;
1119  }
1120  else
1121  segments ++;
1122  }
1123  else
1124  segments++;
1125  }
1126 
1127  //TODO memory error because of wrong calculation of segments?? for the moment *2 to be save
1128  m_cpointsDouble.resize( segments * 2 );
1129 
1130  unsigned int count = 0;
1131  double x, y, lastx, lasty;
1132  for ( i = 0; i < points->size(); i++ )
1133  {
1134  const a2dLineSegmentPtr seg = points->operator[]( i );
1135 
1136  if ( !seg->GetArc() )
1137  {
1138  m_usertodevice.TransformPoint( seg->m_x, seg->m_y, x, y );
1139 
1140  //to reduce the points count for lines or a polygon on the screen
1141  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1142  {
1143  m_cpointsDouble[count].x = x;
1144  m_cpointsDouble[count].y = y;
1145  lastx = x;
1146  lasty = y;
1147  devbbox.Expand( x, y );
1148  count++;
1149  }
1150  }
1151  else
1152  {
1153  const a2dArcSegment* cseg = ( const a2dArcSegment* ) ( seg.Get() );
1154 
1155  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1156 
1157  if ( cseg->CalcR( *( points->operator[]( i ? i - 1 : 0 ) ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1158  {
1159  double dphi;
1160  unsigned int segments;
1161  double radiusDev = m_usertodevice.TransformDistance( radius );
1162  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
1163 
1164  double theta = beginrad;
1165  unsigned int step;
1166 
1167  double x, y;
1168  for ( step = 0; step < segments + 1; step++ )
1169  {
1170  m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
1171 
1172  //to reduce the points count for lines or a polygon on the screen
1173  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1174  {
1175  m_cpointsDouble[count].x = x;
1176  m_cpointsDouble[count].y = y;
1177  lastx = x;
1178  lasty = y;
1179  devbbox.Expand( x, y );
1180  count++;
1181  }
1182  theta = theta + dphi;
1183  }
1184  }
1185  else
1186  {
1187  double x, y;
1188  m_usertodevice.TransformPoint( cseg->m_x, cseg->m_y, x, y );
1189 
1190  //to reduce the points count for lines or a polygon on the screen
1191  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1192  {
1193  m_cpointsDouble[count].x = x;
1194  m_cpointsDouble[count].y = y;
1195  lastx = x;
1196  lasty = y;
1197  devbbox.Expand( x, y );
1198  count++;
1199  }
1200  }
1201  }
1202  }
1203 
1204  return count;
1205 }
1206 
1207 int a2dContext::ToDeviceLines( const a2dVertexList* list, a2dBoundingBox& devbbox, bool& smallPoly, bool replaceByRectangle )
1208 {
1209  unsigned int segments = 0;
1210 
1211  if ( list->empty() )
1212  return 0;
1213 
1214  a2dVertexList::const_iterator iterprev = list->end();
1215  if ( iterprev != list->begin() )
1216  iterprev--;
1217  a2dVertexList::const_iterator iter = list->begin();
1218  while ( iter != list->end() )
1219  {
1220  a2dLineSegment* seg = ( *iter );
1221 
1222  if ( seg->GetArc() )
1223  {
1224  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
1225 
1226  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1227 
1228  if ( cseg->CalcR( *( *iterprev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1229  {
1230  double dphi;
1231  unsigned int circlesegments;
1232  double radiusDev = m_usertodevice.TransformDistance( radius );
1233  Aberration( m_displayaberration, phit, radiusDev , dphi, circlesegments );
1234  segments += circlesegments + 1;
1235  }
1236  else
1237  segments ++;
1238  }
1239  else
1240  segments++;
1241 
1242  iterprev = iter++;
1243  }
1244 
1245  //TODO memory error because of wrong calculation of segments?? for the moment *2 to be save
1246  m_cpointsDouble.resize( segments * 2 );
1247 
1248  unsigned int count = 0;
1249  double x, y, lastx, lasty;
1250  iterprev = list->end();
1251  if ( iterprev != list->begin() )
1252  iterprev--;
1253  iter = list->begin();
1254  while ( iter != list->end() )
1255  {
1256  a2dLineSegment* seg = ( *iter );
1257 
1258  if ( !seg->GetArc() )
1259  {
1260  m_usertodevice.TransformPoint( seg->m_x, seg->m_y, x, y );
1261 
1262  //to reduce the points count for lines or a polygon on the screen
1263  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1264  {
1265  m_cpointsDouble[count].x = x;
1266  m_cpointsDouble[count].y = y;
1267  lastx = x;
1268  lasty = y;
1269  devbbox.Expand( x, y );
1270  count++;
1271  }
1272  }
1273  else
1274  {
1275  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
1276 
1277  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1278 
1279  if ( cseg->CalcR( *( *iterprev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1280  {
1281  double dphi;
1282  unsigned int segments;
1283  double radiusDev = m_usertodevice.TransformDistance( radius );
1284  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
1285 
1286  double theta = beginrad;
1287  unsigned int step;
1288 
1289  double x, y;
1290  for ( step = 0; step < segments + 1; step++ )
1291  {
1292  m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
1293 
1294  //to reduce the points count for lines or a polygon on the screen
1295  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1296  {
1297  m_cpointsDouble[count].x = x;
1298  m_cpointsDouble[count].y = y;
1299  lastx = x;
1300  lasty = y;
1301  devbbox.Expand( x, y );
1302  count++;
1303  }
1304  theta = theta + dphi;
1305  }
1306  }
1307  else
1308  {
1309  double x, y;
1310  m_usertodevice.TransformPoint( cseg->m_x, cseg->m_y, x, y );
1311 
1312  //to reduce the points count for lines or a polygon on the screen
1313  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1314  {
1315  m_cpointsDouble[count].x = x;
1316  m_cpointsDouble[count].y = y;
1317  lastx = x;
1318  lasty = y;
1319  devbbox.Expand( x, y );
1320  count++;
1321  }
1322  }
1323  }
1324  iterprev = iter++;
1325  }
1326 
1327  return count;
1328 }
1329 
1330 
1331 void a2dContext::DrawVpath( const a2dVpath* path )
1332 {
1333  double tstep = 1 / ( double ) SPLINE_STEP;
1334  unsigned int i;
1335 
1336  a2dVertexList points;
1337  bool move = false;
1338  int count = 0;
1339  bool nostrokeparts = false;
1340 
1341  //first draw as much as possible ( nostroke parts may stop this first round )
1342  for ( i = 0; i < path->size(); i++ )
1343  {
1344  a2dVpathSegmentPtr seg = path->operator[]( i );
1345  switch ( seg->GetType() )
1346  {
1347  case a2dPATHSEG_MOVETO:
1348  if ( count == 0 )
1349  {
1350  points.push_back( new a2dLineSegment( seg->m_x1, seg->m_y1 ) );
1351  count++;
1352  }
1353  else
1354  {
1355  i--;
1356  move = true;
1357  }
1358  break;
1359 
1360  case a2dPATHSEG_LINETO:
1361  points.push_back( new a2dLineSegment( seg->m_x1, seg->m_y1 ) );
1362  count++;
1363  break;
1365  points.push_back( new a2dLineSegment( seg->m_x1, seg->m_y1 ) );
1366  count++;
1367  nostrokeparts = true;
1368  break;
1369 
1371  nostrokeparts = true;
1372  case a2dPATHSEG_CBCURVETO:
1373  {
1374  double xw, yw;
1375 
1376  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
1377  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
1378  a2dVpathCBCurveSegment* cseg = ( a2dVpathCBCurveSegment* ) ( seg.Get() );
1379 
1380  int step;
1381  double t = 0;
1382  for ( step = 0; step <= SPLINE_STEP; step++ )
1383  {
1384  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 );
1385  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 );
1386  points.push_back( new a2dLineSegment( xw, yw ) );
1387  count++;
1388  t = t + tstep;
1389  }
1390  }
1391  break;
1392 
1394  nostrokeparts = true;
1395  case a2dPATHSEG_QBCURVETO:
1396  {
1397  double xw, yw;
1398 
1399  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
1400  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
1401  a2dVpathQBCurveSegment* cseg = ( a2dVpathQBCurveSegment* ) seg.Get();
1402 
1403  int step;
1404  double t = 0;
1405  for ( step = 0; step <= SPLINE_STEP; step++ )
1406  {
1407  xw = xwl * pow( 1 - t, 2 ) + cseg->m_x2 * ( 1 - t ) * t * 2 + cseg->m_x1 * pow( t, 2 );
1408  yw = ywl * pow( 1 - t, 2 ) + cseg->m_y2 * ( 1 - t ) * t * 2 + cseg->m_y1 * pow( t, 2 );
1409  points.push_back( new a2dLineSegment( xw, yw ) );
1410  count++;
1411  t = t + tstep;
1412  }
1413  }
1414  break;
1415 
1417  nostrokeparts = true;
1418  case a2dPATHSEG_ARCTO:
1419  {
1420  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
1421 
1422  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1423 
1424  if ( cseg->CalcR( path->operator[]( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1425  {
1426  double dphi;
1427  unsigned int segments;
1428  double radiusDev = m_usertodevice.TransformDistance( radius );
1429  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
1430 
1431  double theta = beginrad;
1432  unsigned int step;
1433 
1434  for ( step = 0; step < segments + 1; step++ )
1435  {
1436  points.push_back( new a2dLineSegment( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ) ) );
1437  count++;
1438  theta = theta + dphi;
1439  }
1440  }
1441  else
1442  {
1443  points.push_back( new a2dLineSegment( cseg->m_x1, cseg->m_y1 ) );
1444  count++;
1445  }
1446  }
1447  default:
1448  break;
1449  break;
1450  }
1451 
1452  if ( move )
1453  {
1454  DrawLines( &points );
1455  move = false;
1456  count = 0;
1457  points.clear();
1458  }
1459  else if ( seg->GetClose() != a2dPATHSEG_END_OPEN )
1460  {
1461  if ( nostrokeparts || seg->GetClose() == a2dPATHSEG_END_CLOSED_NOSTROKE )
1462  {
1463  a2dStroke stroke = m_activestroke;
1464  m_activestroke = *a2dTRANSPARENT_STROKE;
1465  DrawPolygon( &points, wxODDEVEN_RULE );
1466  m_activestroke = stroke;
1467  nostrokeparts = true;
1468  }
1469  else
1470  {
1471  DrawPolygon( &points, wxODDEVEN_RULE );
1472  }
1473 
1474  move = false;
1475  count = 0;
1476  points.clear();
1477  }
1478  else if ( i == path->size() - 1 ) //last segment?
1479  {
1480  DrawLines( &points );
1481  }
1482  }
1483 
1484  if ( nostrokeparts )
1485  {
1486  points.clear();
1487  move = false;
1488  count = 0;
1489  nostrokeparts = false;
1490 
1491  double lastmovex = 0;
1492  double lastmovey = 0;
1493 
1494  for ( i = 0; i < path->size(); i++ )
1495  {
1496  a2dVpathSegmentPtr seg = path->operator[]( i );
1497  switch ( seg->GetType() )
1498  {
1499  case a2dPATHSEG_MOVETO:
1500  if ( count == 0 )
1501  {
1502  points.push_back( new a2dLineSegment( seg->m_x1, seg->m_y1 ) );
1503  lastmovex = seg->m_x1;
1504  lastmovey = seg->m_y1;
1505  count++;
1506  }
1507  else
1508  {
1509  i--;
1510  move = true;
1511  }
1512  break;
1513 
1514  case a2dPATHSEG_LINETO:
1515  points.push_back( new a2dLineSegment( seg->m_x1, seg->m_y1 ) );
1516  count++;
1517  break;
1518 
1523  if ( count == 0 )
1524  {
1525  points.push_back( new a2dLineSegment( seg->m_x1, seg->m_y1 ) );
1526  count++;
1527  }
1528  else
1529  {
1530  i--;
1531  nostrokeparts = true;
1532  }
1533  break;
1534 
1535  case a2dPATHSEG_CBCURVETO:
1536  {
1537  double xw, yw;
1538 
1539  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
1540  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
1542 
1543  int step;
1544  double t = 0;
1545  for ( step = 0; step <= SPLINE_STEP; step++ )
1546  {
1547  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 );
1548  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 );
1549  points.push_back( new a2dLineSegment( xw, yw ) );
1550  count++;
1551  t = t + tstep;
1552  }
1553  }
1554  break;
1555 
1556  case a2dPATHSEG_QBCURVETO:
1557  {
1558  double xw, yw;
1559 
1560  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
1561  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
1563 
1564  int step;
1565  double t = 0;
1566  for ( step = 0; step <= SPLINE_STEP; step++ )
1567  {
1568  xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
1569  yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
1570  points.push_back( new a2dLineSegment( xw, yw ) );
1571  count++;
1572  t = t + tstep;
1573  }
1574  }
1575  break;
1576 
1577  case a2dPATHSEG_ARCTO:
1578  {
1579  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
1580 
1581  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1582 
1583  if ( cseg->CalcR( path->operator[]( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1584  {
1585  double dphi;
1586  unsigned int segments;
1587  double radiusDev = m_usertodevice.TransformDistance( radius );
1588  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
1589 
1590  double theta = beginrad;
1591  unsigned int step;
1592 
1593  for ( step = 0; step < segments + 1; step++ )
1594  {
1595  points.push_back( new a2dLineSegment( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ) ) );
1596  count++;
1597  theta = theta + dphi;
1598  }
1599  }
1600  else
1601  {
1602  points.push_back( new a2dLineSegment( cseg->m_x1, cseg->m_y1 ) );
1603  count++;
1604  }
1605  }
1606  default:
1607  break;
1608 
1609  break;
1610  }
1611 
1612  if ( move || nostrokeparts )
1613  {
1614  DrawLines( &points );
1615  move = false;
1616  nostrokeparts = false;
1617  points.clear();
1618  count = 0;
1619  }
1620  else if ( seg->GetClose() != a2dPATHSEG_END_OPEN )
1621  {
1622  if ( seg->GetClose() == a2dPATHSEG_END_CLOSED )
1623  {
1624  points.push_back( new a2dLineSegment( lastmovex, lastmovey ) );
1625  count++;
1626  }
1627  DrawLines( &points );
1628  nostrokeparts = false;
1629  move = false;
1630  points.clear();
1631  count = 0;
1632  }
1633  else if ( i == path->size() )
1634  {
1635  DrawLines( &points );
1636  }
1637  }
1638  }
1639 
1640 }
1641 
1642 void a2dContext::DrawCharUnknown( wxChar c )
1643 {
1644  a2dStroke oldstroke = m_activestroke;
1645  // set text linestroke.
1646  a2dStroke stroke = a2dStroke( m_activestroke.GetColour(), m_a2dfont.GetSize() / 20.0 );
1647  m_activestroke = stroke;
1648 
1649  if ( c != wxChar( ' ' ) )
1650  {
1651  double desc = m_a2dfont.GetDescent();
1652  double size = m_a2dfont.GetSize();
1653  double width = m_a2dfont.GetWidth( c );
1654  DrawLine( 0.1 * width, desc, 0.9 * width, desc + size );
1655  DrawLine( 0.9 * width, desc, 0.1 * width, desc + size );
1656  }
1657 
1658  // restore context
1659  m_activestroke = oldstroke;
1660 }
1661 
1662 void a2dContext::DrawTextUnknown( const wxString& text, double x, double y, bool words )
1663 {
1664  if ( words && m_a2dfont.Ok() )
1665  {
1666  a2dStroke oldstroke = m_activestroke;
1667  // Draw a piece of line for each word.
1668  a2dBoundingBox linebbox = m_a2dfont.GetTextExtent( text, m_yaxis );
1669 
1670  if ( !m_activefill.IsNoFill() && !m_activefill.GetStyle() == a2dFILL_TRANSPARENT )
1671  {
1672  m_activestroke = *a2dTRANSPARENT_STROKE;
1673  DrawRoundedRectangle( x + linebbox.GetMinX(), y + linebbox.GetMinY(),
1674  linebbox.GetWidth(), linebbox.GetHeight(), 0 );
1675  m_activestroke = oldstroke;
1676  }
1677 
1678  // set text linestroke.
1679  a2dStroke strokew = a2dStroke( m_activestroke.GetColour(), 1 );
1680  m_activestroke = strokew;
1681 
1682  double h = linebbox.GetHeight();
1683  double w;
1684  wxChar c;
1685  double start = x;
1686  for ( size_t i = 0; i < text.Length(); i++ )
1687  {
1688  c = text[i];
1689  w = m_a2dfont.GetWidth( c );
1690  if ( c == wxChar( ' ' ) )
1691  {
1692  if ( x != start )
1693  DrawLine( start, y + h / 2, x, y + h / 2 );
1694  start = x + w;
1695  }
1696  x += w;
1697  }
1698  if ( x != start )
1699  DrawLine( start, y + h / 2, x, y + h / 2 );
1700 
1701  // restore context
1702  m_activestroke = oldstroke;
1703  }
1704  else
1705  {
1706  a2dBoundingBox linebbox = m_a2dfont.GetTextExtent( text, m_yaxis );
1707 
1708  DrawRoundedRectangle( x + linebbox.GetMinX(), y + linebbox.GetMinY(),
1709  linebbox.GetWidth(), linebbox.GetHeight(), 0 );
1710  DrawLine( x + linebbox.GetMinX(), y + linebbox.GetMinY(), x + linebbox.GetMaxX(), y + linebbox.GetMaxY() );
1711  DrawLine( x + linebbox.GetMinX(), y + linebbox.GetMaxY(), x + linebbox.GetMaxX(), y + linebbox.GetMinY() );
1712  }
1713 }
1714 
1715 
1716 void a2dContext::DrawCharStroke( wxChar c )
1717 {
1718  a2dStroke strokeold = m_activestroke;
1719  // set text linestroke.
1720  //!todo what about the style (pixel or not of stroke font )
1721  a2dStroke stroke = a2dStroke( m_activestroke.GetColour(), 0.0 );
1722  stroke.SetWidth( m_a2dfont.GetStrokeWidth() );
1723  m_activestroke = stroke;
1724 
1725  a2dAffineMatrix affineold = m_usertodevice;
1726 
1727  // scale character to size
1728  a2dAffineMatrix affine;
1729  affine.Scale( m_a2dfont.GetSize() );
1730  m_usertodevice = affine;
1731 
1732  a2dVertexList** ptr = m_a2dfont.GetGlyphStroke( c );
1733  if ( ptr )
1734  {
1735  while ( *ptr )
1736  {
1737  DrawLines( *ptr );
1738  ptr++;
1739  }
1740  }
1741 
1742  m_usertodevice = affineold;
1743  m_activestroke = strokeold;
1744 }
1745 
1746 void a2dContext::DrawTextGeneric( const wxString& text, double x, double y, void ( a2dContext::*drawchar )( wxChar ) )
1747 {
1748  // mirror text, depending on y-axis orientation
1749  const double h = m_a2dfont.GetLineHeight();
1750  a2dAffineMatrix affine;
1751  if ( !GetYaxis() )
1752  {
1753  affine.Translate( 0.0, -h );
1754  affine.Mirror( true, false );
1755  }
1756  // position text
1757  affine.Translate( x, y );
1758 
1759  a2dAffineMatrix affineold = m_usertodevice;
1760  a2dAffineMatrix textm = affine;
1761 
1762  m_usertodevice = m_usertodevice;
1763 
1764  bool textwasvisible = false;
1765 
1766  double w = 0.0;
1767  wxChar c = 0;
1768  const size_t n = text.Length();
1769  for ( size_t i = 0; i < n; i++ )
1770  {
1771  const wxChar oldc = c;
1772  c = text[i];
1773  if ( i > 0 )
1774  {
1775  textm *= a2dAffineMatrix( w + m_a2dfont.GetKerning( oldc, c ), 0.0 );
1776  }
1777  m_usertodevice = affineold * textm;
1778 
1779  w = m_a2dfont.GetWidth( c );
1780 
1781  // get absolute character bounding box
1782  a2dBoundingBox bbox( 0.0, 0.0, w, h );
1783  bbox.MapBbox( m_usertodevice );
1784  wxRect devb = wxRect( bbox.GetMinX(), bbox.GetMinY(), bbox.GetWidth(), bbox.GetHeight() );
1785 
1786  // if character is not outside clipping box, draw it.
1787  if ( m_clipboxdev.Intersects( devb ) )
1788  {
1789  ( this->*drawchar )( c );
1790  textwasvisible = true;
1791  }
1792  else if ( textwasvisible )
1793  {
1794  // If characters of a string had been visible, and this character is not
1795  // visible, then so will all succeeding. i.o.w. we can stop drawing.
1796  break;
1797  }
1798  }
1799 
1800  // restore context
1801  m_usertodevice = affineold;
1802 }
1803 
1804 //use by polygon filling
1805 //moves the scanline up
1806 //index is the index of the point where the search begins
1807 //direction is +1 or -1 and indicates if the segment ascends or decends
1808 bool a2dContext::MoveUp( int n, wxRealPoint points[] , double horline, int& index, int direction )
1809 {
1810  int walk = ( index + direction + n ) % n;
1811  while ( points[walk].y < horline )
1812  {
1813  if ( points[walk].y < points[index].y )
1814  return false;
1815  else
1816  {
1817  //modify index
1818  index = walk;
1819  walk = ( index + direction + n ) % n;
1820  }
1821  }
1822  return true;
1823 }
1824 
1825 //a crictical point is a point between a decending and a ascending segment
1826 //collect those points for filling later
1827 void a2dContext::DetectCriticalPoints( int n, wxRealPoint points[] )
1828 {
1829  //candidate for critical point
1830  //true if Y is getting lower, unchanged i Y is unchanged
1831  //and if Y becomes higher and candidate was true: it is a critical point
1832  bool candidate = false;
1833  int i, j;
1834 
1835  for ( i = 0; i < n; i++ )
1836  {
1837  //j next point
1838  j = ( i + 1 ) % n;
1839 
1840  //check if Y is smaller
1841  if ( points[i].y > points[j].y )
1842  //we have a candidate
1843  candidate = true;
1844  else if ( ( points[i].y < points[j].y ) && candidate )
1845  {
1846  //this is a critical point put in list
1847  bool inserted = false;
1848  a2dCriticalPointList::compatibility_iterator node = m_CRlist.GetFirst();
1849  while ( node )
1850  {
1851  //sorted on smallest Y value
1852  int* ind = node->GetData();
1853  if ( points[*ind].y > points[i].y )
1854  {
1855  m_CRlist.Insert( node, new int( i ) );
1856  inserted = true;
1857  break;
1858  }
1859  node = node->GetNext();
1860  }
1861  if ( !inserted )
1862  m_CRlist.Append( new int( i ) );
1863  candidate = false;
1864  }
1865  }
1866  if ( candidate )
1867  {
1868  for ( i = 0; i < n; i++ )
1869  {
1870  //j next point
1871  j = ( i + 1 ) % n;
1872 
1873  //check if Y is smaller
1874  if ( points[i].y > points[j].y )
1875  //we have a candidate
1876  candidate = true;
1877  else if ( ( points[i].y < points[j].y ) && candidate )
1878  {
1879  //this is a critical point put in list
1880  bool inserted = false;
1881  a2dCriticalPointList::compatibility_iterator node = m_CRlist.GetFirst();
1882  while ( node )
1883  {
1884  //sorted on smallest Y value
1885  int* ind = node->GetData();
1886  if ( points[*ind].y > points[i].y )
1887  {
1888  m_CRlist.Insert( node, new int( i ) );
1889  inserted = true;
1890  break;
1891  }
1892  node = node->GetNext();
1893  }
1894  if ( !inserted )
1895  m_CRlist.Append( new int( i ) );
1896  candidate = false;
1897  }
1898  }
1899  }
1900 }
1901 
1902 
1903 static int SortonXs( const a2dAET** first, const a2dAET** second )
1904 {
1905  if ( ( *first )->m_xs < ( *second )->m_xs )
1906  return -1;
1907  else if ( ( *first )->m_xs > ( *second )->m_xs )
1908  return 1;
1909 
1910  return 0;
1911 }
1912 
1913 void a2dContext::ColourXYLinear( int x1, int x2, int y )
1914 {
1915  int dred = m_colour2redFill - m_colour1redFill;
1916  int dgreen = m_colour2greenFill - m_colour1greenFill;
1917  int dblue = m_colour2blueFill - m_colour1blueFill;
1918 
1919  if ( m_dx1 == m_dx2 )
1920  {
1921  //total number of lines to go from m_textbg to m_textfg
1922  //gives the following number of steps for the gradient color
1923  double stepcol = m_max_y - m_min_y;
1924 
1925  double curcol = y - m_min_y;
1926 
1927  a2dStroke current = m_activestroke;
1928  wxColour gradcol( ( unsigned char ) ( m_colour1redFill + dred * curcol / stepcol ),
1929  ( unsigned char ) ( m_colour1greenFill + dgreen * curcol / stepcol ),
1930  ( unsigned char ) ( m_colour1blueFill + dblue * curcol / stepcol ) );
1931  a2dStroke gradientstroke = a2dStroke( gradcol, 0 );
1932  m_activestroke = gradientstroke;
1933  DeviceDrawHorizontalLine( x1, y, x2, true );
1934  m_activestroke = current;
1935  }
1936  else
1937  {
1938  int j;
1939  for ( j = x1; j <= x2; j++ )
1940  {
1941  a2dLine perstroke( j, y, j + m_dy2 - m_dy1, y + m_dx2 - m_dx1 );
1942  a2dPoint2D crossing;
1943  perstroke.CalculateLineParameters();
1944  perstroke.Intersect( m_line, crossing );
1945 
1946  double length = sqrt( ( double ) ( crossing.m_x - m_dx1 ) * ( crossing.m_x - m_dx1 ) + ( crossing.m_y - m_dy1 ) * ( crossing.m_y - m_dy1 ) );
1947 
1948  if ( length > m_length )
1949  length = m_length;
1950 
1951  DeviceDrawPixel( j, y, m_colour1redFill + dred * int( length / m_length ),
1952  m_colour1greenFill + dgreen * int( length / m_length ),
1953  m_colour1blueFill + dblue * int( length / m_length ) );
1954  }
1955  }
1956 }
1957 
1958 void a2dContext::ColourXYRadial( int x1, int x2, int y )
1959 {
1960  int dred = m_colour2redFill - m_colour1redFill;
1961  int dgreen = m_colour2greenFill - m_colour1greenFill;
1962  int dblue = m_colour2blueFill - m_colour1blueFill;
1963 
1964  int j;
1965  for ( j = x1; j <= x2; j++ )
1966  {
1967  double cradius = sqrt( ( double ) ( j - m_dx1 ) * ( j - m_dx1 ) + ( y - m_dy1 ) * ( y - m_dy1 ) );
1968 
1969  double delta;
1970  if ( m_radiusd == 0 )
1971  delta = 0;
1972  else if ( cradius > m_radiusd )
1973  delta = 1;
1974  else
1975  delta = cradius / m_radiusd;
1976 
1977  DeviceDrawPixel( j, y, ( unsigned char ) ( m_colour1redFill + dred * delta ),
1978  ( unsigned char ) ( m_colour1greenFill + dgreen * delta ),
1979  ( unsigned char ) ( m_colour1blueFill + dblue * delta ) );
1980  }
1981 }
1982 
1983 void a2dContext::FillPolygon( int n, wxRealPoint points[] )
1984 {
1985  wxRect clip;
1986  clip.x = m_clipboxdev.x;
1987  clip.y = m_clipboxdev.y;
1988  clip.width = m_clipboxdev.width;
1989  clip.height = m_clipboxdev.height;
1990 
1991  m_min_y = points[0].y;
1992  m_max_y = points[0].y;
1993  m_min_x = points[0].x;
1994  m_max_x = points[0].x;
1995  double centroidx = 0;
1996  double centroidy = 0;
1997  int i;
1998  for ( i = 0; i < n; i++ )
1999  {
2000  m_min_y = wxMin( m_min_y, points[i].y );
2001  m_max_y = wxMax( m_max_y, points[i].y );
2002  m_min_x = wxMin( m_min_x, points[i].x );
2003  m_max_x = wxMax( m_max_x, points[i].x );
2004  centroidx += points[i].x;
2005  centroidy += points[i].y;
2006  }
2007 
2008  centroidx /= double( n );
2009  centroidy /= double( n );
2010 
2011  int index;
2012 
2013  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
2014  {
2015  double x1 = m_activefill.GetStart().m_x;
2016  double y1 = m_activefill.GetStart().m_y;
2017  double x2 = m_activefill.GetStop().m_x;
2018  double y2 = m_activefill.GetStop().m_y;
2019  m_usertodevice.TransformPoint( x1, y1, m_dx1, m_dy1 );
2020  m_usertodevice.TransformPoint( x2, y2, m_dx2, m_dy2 );
2021  if ( m_dx1 == m_dx2 && m_dy1 == m_dy2 )
2022  {
2023  //do a linear fill vertical
2024  m_dx1 = centroidx;
2025  m_dy1 = m_min_y;
2026  m_dx2 = centroidx;
2027  m_dy2 = m_max_y;
2028  if ( m_dx1 == m_dx2 && m_dy1 == m_dy2 )
2029  m_dx2 = m_dx2 + 100;
2030  }
2031  m_length = sqrt ( ( m_dx1 - m_dx2 ) * ( m_dx1 - m_dx2 ) + ( m_dy1 - m_dy2 ) * ( m_dy1 - m_dy2 ) );
2032  m_line = a2dLine( m_dx1, m_dy1, m_dx2, m_dy2 );
2033  m_line.CalculateLineParameters();
2034  }
2035  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
2036  {
2037  double xfc = m_activefill.GetFocal().m_x;
2038  double yfc = m_activefill.GetFocal().m_y;
2039  double xe = m_activefill.GetCenter().m_x;
2040  double ye = m_activefill.GetCenter().m_y;
2041  m_usertodevice.TransformPoint( xfc, yfc, m_dx1, m_dy1 );
2042  m_usertodevice.TransformPoint( xe, ye, m_dx2, m_dy2 );
2043  if ( m_dx1 == m_dx2 && m_dy1 == m_dy2 )
2044  {
2045  //no start stop given
2046  m_dx1 = centroidx;
2047  m_dy1 = centroidy;
2048  m_dx2 = centroidx;
2049  m_dy2 = m_max_y;
2050 
2051  if ( m_dx1 == m_dx2 && m_dy1 == m_dy2 )
2052  m_dx2 = m_dx2 + 10;
2053  }
2054  double dx3, dy3;
2055  m_usertodevice.TransformPoint( xe, ye + m_activefill.GetRadius(), dx3, dy3 );
2056  m_radiusd = sqrt ( ( dx3 - m_dx2 ) * ( dx3 - m_dx2 ) + ( dy3 - m_dy2 ) * ( dy3 - m_dy2 ) );
2057  }
2058 
2059  DetectCriticalPoints( n, points );
2060 
2061  int min = ( int ) wxMax ( m_min_y, clip.y );
2062  int max = ( int ) wxMin ( m_max_y, clip.y + clip.height );
2063 
2064  for ( i = min; i < max; i++ )
2065  {
2066  a2dAETList::compatibility_iterator node = m_AETlist.GetFirst();
2067  int count = m_AETlist.size();
2068  while ( count > 0 )
2069  {
2070  a2dAET* ele = node->GetData();
2071  index = ele->m_index;
2072  int direction = ele->m_direction;
2073  if ( !MoveUp( n, points, i, index, direction ) )
2074  {
2075  a2dAETList::compatibility_iterator h = node;
2076  //remove this node
2077  node = node->GetNext();
2078  delete h->GetData();
2079  m_AETlist.DeleteNode( h );
2080  }
2081  else
2082  {
2083  if ( ele->m_index != index )
2084  {
2085  ele->m_index = index;
2086  int h = ( index + direction + n ) % n;
2087  ele->CalculateLineParameters( points[h], points[index] );
2088  }
2089  if ( ele->m_horizontal )
2090  ele->m_xs = ( int ) points[index].x;
2091  else
2092  ele->CalculateXs( i );
2093  node = node->GetNext();
2094  }
2095  count--;
2096  }
2097 
2098  a2dCriticalPointList::compatibility_iterator nodec = m_CRlist.GetFirst();
2099  while ( m_CRlist.size() && points[*nodec->GetData()].y <= i )
2100  {
2101  int DI;
2102  for ( DI = -1; DI <= 1 ; DI += 2 )
2103  {
2104  index = *nodec->GetData();
2105  if ( MoveUp( n, points, i, index, DI ) )
2106  {
2107  a2dAET* ele = new a2dAET();
2108  ele->m_index = index;
2109  ele->m_direction = DI;
2110  int h = ( index + DI + n ) % n;
2111  ele->CalculateLineParameters( points[h], points[index] );
2112  if ( ele->m_horizontal )
2113  ele->m_xs = ( int ) points[index].x;
2114  else
2115  ele->CalculateXs( i );
2116 
2117  //insert in sorted order of m_xs
2118  bool inserted = false;
2119  node = m_AETlist.GetFirst();
2120  while ( node )
2121  {
2122  //sorted on smallest xs value
2123  if ( ele->m_xs < ( node->GetData() )->m_xs )
2124  {
2125  m_AETlist.Insert( node, ele );
2126  inserted = true;
2127  break;
2128  }
2129 // TODO to make sorting work (is eqaul in xs the sorting can be wrong
2130  node = node->GetNext();
2131  }
2132  if ( !inserted )
2133  m_AETlist.Append( ele );
2134  }
2135  }
2136 
2137  a2dCriticalPointList::compatibility_iterator h = nodec;
2138  nodec = nodec->GetNext();
2139  delete h->GetData();
2140  m_CRlist.DeleteNode( h );
2141  }
2142 
2143  //and since i am not smart enough to insert sorted when xs is equal
2144  //sort again and again :-((
2145  if ( m_AETlist.GetCount() > 1 )
2146  {
2147  if ( m_AETlist.GetCount() > 2 )
2148  m_AETlist.Sort( SortonXs );
2149  else if ( m_AETlist.GetFirst()->GetData()->m_xs > m_AETlist.GetLast()->GetData()->m_xs )
2150  {
2151  a2dAET* f = m_AETlist.GetFirst()->GetData();
2152  m_AETlist.GetFirst()->SetData( m_AETlist.GetLast()->GetData() );
2153  m_AETlist.GetLast()->SetData( f );
2154  }
2155  }
2156 
2157  //m_AETlist must be sorted in m_xs at this moment
2158  //now draw all the line parts on one horizontal scanline (Winding Rule)
2159  int out = 0;
2160  node = m_AETlist.GetFirst();
2161  while ( node )
2162  {
2163  a2dAET* ele = node->GetData();
2164  out += ele->m_direction;
2165 
2166  if ( out != 0 )
2167  {
2168  int x1 = ( int ) ele->m_xs;
2169  node = node->GetNext();
2170  if ( node )
2171  {
2172  ele = node->GetData();
2173  int x2 = ( int ) ele->m_xs;
2174 
2175  if ( x1 < clip.x ) x1 = clip.x;
2176  if ( x2 > clip.x + clip.width ) x2 = clip.x + clip.width;
2177  if ( i >= clip.y && i <= clip.y + clip.height && ( x1 != x2 ) )
2178  {
2179  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
2180  ColourXYLinear( x1, x2, i );
2181  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
2182  ColourXYRadial( x1, x2, i );
2183  else
2184  DeviceDrawHorizontalLine( x1, i, x2, false );
2185  }
2186  }
2187  //something is wrong if we arrive here.
2188  }
2189  else
2190  node = node->GetNext();
2191  }
2192  }
2193 
2194  a2dAETList::compatibility_iterator node = m_AETlist.GetFirst();
2195  while ( node )
2196  {
2197  a2dAETList::compatibility_iterator h = node;
2198  delete h->GetData();
2199  m_AETlist.DeleteNode( h );
2200  node = m_AETlist.GetFirst();
2201  }
2202 
2203  a2dCriticalPointList::compatibility_iterator nodec = m_CRlist.GetFirst();
2204  while ( nodec )
2205  {
2206  a2dCriticalPointList::compatibility_iterator h = nodec;
2207  delete h->GetData();
2208  m_CRlist.DeleteNode( h );
2209  nodec = m_CRlist.GetFirst();
2210  }
2211 
2212 }
2213 
2214 void a2dContext::DrawPolygon( const a2dVertexList* list, wxPolygonFillMode fillStyle )
2215 {
2216  a2dBoundingBox devbox;
2217  bool smallPoly = false;
2218  int segments = ToDeviceLines( list, devbox, smallPoly );
2219 
2220  if ( segments == 0 )
2221  return;
2222 
2223  DeviceDrawPolygon( segments, false, fillStyle );
2224 }
2225 
2226 void a2dContext::DrawLines( const a2dVertexList* list )
2227 {
2228  a2dBoundingBox devbox;
2229  bool smallPoly = false;
2230  int segments = ToDeviceLines( list, devbox, smallPoly );
2231 
2232  if ( segments > 0 )
2233  DeviceDrawLines( segments, false );
2234 }
2235 
2236 void a2dContext::DrawLine( double x1, double y1, double x2, double y2 )
2237 {
2238  a2dVertexList points;
2239  points.push_back( new a2dLineSegment( x1, y1 ) );
2240  points.push_back( new a2dLineSegment( x2, y2 ) );
2241  DrawLines( &points );
2242 }
2243 
2244 void a2dContext::DeviceDrawPolygon( unsigned int n, bool spline , wxPolygonFillMode fillStyle )
2245 {
2246  wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
2247 }
2248 
2249 void a2dContext::DeviceDrawLines( unsigned int n, bool spline )
2250 {
2251  wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
2252 }
2253 
2254 void a2dContext::DeviceDrawLine( double x1, double y1, double x2, double y2 )
2255 {
2256  wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
2257 }
2258 
2259 void a2dContext::DeviceDrawHorizontalLine( int x1, int y1, int x2, bool WXUNUSED( use_pen ) )
2260 {
2261  wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
2262 }
2263 
2264 void a2dContext::DeviceDrawVerticalLine( int x1, int y1, int y2, bool WXUNUSED( use_pen ) )
2265 {
2266  wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
2267 }
2268 
2269 void a2dContext::DeviceDrawPixel( int x1, int y1, unsigned char r, unsigned char g, unsigned char b, unsigned char a )
2270 {
2271  wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
2272 }
2273 
2274 wxPoint* a2dContext::_convertToIntPointCache( int n, wxRealPoint* pts )
2275 {
2276  m_cpointsInt.resize( n );
2277  // Convert to integer coords by rounding
2278  for ( int i = 0; i < n; i++ )
2279  {
2280  m_cpointsInt[i].x = Round( pts[i].x );
2281  m_cpointsInt[i].y = Round( pts[i].y );
2282  }
2283  return &m_cpointsInt[0];
2284 }
2285 
2286 
2287 //HERE
2288 
2289 //-----------------------------------------------------------------------------
2290 // a2dDcContext implementation
2291 //-----------------------------------------------------------------------------
2292 
2293 a2dDcContext::a2dDcContext( wxGraphicsRenderer* renderer, wxMemoryDC* dc, wxBitmap* drawable )
2294  :
2295  a2dContext( renderer, dc->GetSize().GetWidth(), dc->GetSize().GetHeight() )
2296 {
2297  m_buffer = drawable;
2298  m_renderDC = dc;
2299 }
2300 
2301 a2dDcContext::a2dDcContext( wxGraphicsRenderer* renderer, wxBitmap* drawable )
2302  :
2303  a2dContext( renderer, drawable->GetWidth(), drawable->GetHeight() )
2304 {
2305  m_buffer = drawable;
2306  m_renderDC = new wxMemoryDC( *drawable );
2307 }
2308 
2309 a2dDcContext::~a2dDcContext()
2310 {
2311 }
2312 
2313 void a2dDcContext::DoSetActiveStroke()
2314 {
2315  if ( m_renderDC )
2316  {
2317  if ( m_activestroke.GetStyle() == a2dSTROKE_TRANSPARENT )
2318  {
2319  m_renderDC->SetPen( *wxTRANSPARENT_PEN );
2320  }
2321  else if ( m_activestroke.IsNoStroke() )
2322  {
2323  m_renderDC->SetPen( *wxTRANSPARENT_PEN );
2324  //nullpen gives assert in wxDC its pen (no ref data )
2325  //m_renderDC->SetPen( *wxNullPen );
2326  }
2327  else if ( m_drawstyle == a2dWIREFRAME_INVERT_ZERO_WIDTH )
2328  {
2329  m_renderDC->SetPen( *wxBLACK_PEN );
2330  }
2331  else if ( m_activestroke.GetType() == a2dSTROKE_ONE_COLOUR )
2332  {
2333  int style;
2334  switch( m_activestroke.GetStyle() )
2335  {
2336  case a2dSTROKE_SOLID: style = wxSOLID;
2337  break;
2338  case a2dSTROKE_TRANSPARENT: style = wxTRANSPARENT;
2339  break;
2340  case a2dSTROKE_DOT: style = wxDOT;
2341  break;
2342  case a2dSTROKE_DOT_DASH: style = wxDOT_DASH;
2343  break;
2344  case a2dSTROKE_LONG_DASH: style = wxLONG_DASH;
2345  break;
2346  case a2dSTROKE_SHORT_DASH: style = wxSHORT_DASH;
2347  break;
2348  case a2dSTROKE_BDIAGONAL_HATCH: style = wxBDIAGONAL_HATCH;
2349  break;
2350  case a2dSTROKE_CROSSDIAG_HATCH: style = wxCROSSDIAG_HATCH;
2351  break;
2352  case a2dSTROKE_FDIAGONAL_HATCH: style = wxFDIAGONAL_HATCH;
2353  break;
2354  case a2dSTROKE_CROSS_HATCH: style = wxCROSS_HATCH;
2355  break;
2356  case a2dSTROKE_HORIZONTAL_HATCH: style = wxHORIZONTAL_HATCH;
2357  break;
2358  case a2dSTROKE_VERTICAL_HATCH: style = wxVERTICAL_HATCH;
2359  break;
2360  case a2dSTROKE_STIPPLE: style = wxSTIPPLE;
2361  break;
2362  case a2dSTROKE_STIPPLE_MASK_OPAQUE: style = wxSTIPPLE_MASK_OPAQUE;
2363  break;
2364  default: style = a2dSTROKE_SOLID;
2365  }
2366 
2367  if ( m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
2368  {
2369  wxPen dcpen( m_activestroke.GetColour(), 0, style );
2370  m_renderDC->SetPen( dcpen );
2371  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
2372  }
2373  else
2374  {
2375  wxPen dcpen( m_activestroke.GetColour(), ( int ) m_activestroke.GetWidth(), style );
2376  dcpen.SetJoin( m_activestroke.GetJoin() );
2377  dcpen.SetCap( m_activestroke.GetCap() );
2378  if ( !m_activestroke.GetPixelStroke() )
2379  {
2380  double w = m_usertodevice.TransformDistance( m_activestroke.GetWidth() );
2381  dcpen.SetWidth( ( int ) w );
2382  }
2383  m_renderDC->SetPen( dcpen );
2384  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
2385  }
2386 
2387  }
2388  else if ( m_activestroke.GetType() == a2dSTROKE_BITMAP )
2389  {
2390  wxPen dcpen;
2391 
2392  if ( m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
2393  dcpen = wxPen( m_activestroke.GetColour(), 0, wxBRUSHSTYLE_SOLID );
2394  else
2395  {
2396  int width = ( int ) m_activestroke.GetWidth();
2397  if ( !m_activestroke.GetPixelStroke() )
2398  {
2399  a2dAffineMatrix inverted = m_usertodevice;
2400  inverted.Invert();
2401  width = inverted.TransformDistance( m_activestroke.GetWidth() );
2402  }
2403  dcpen = wxPen( m_activestroke.GetColour(), width, wxBRUSHSTYLE_SOLID );
2404  dcpen.SetJoin( m_activestroke.GetJoin() );
2405  dcpen.SetCap( m_activestroke.GetCap() );
2406  }
2407 
2408 #if defined(__WXMSW__)
2409  wxBrushStyle style;
2410  switch( m_activestroke.GetStyle() )
2411  {
2412  case a2dSTROKE_STIPPLE:
2413  style = wxBRUSHSTYLE_STIPPLE;
2414  dcpen.SetStyle( style );
2415  dcpen.SetStipple( m_activestroke.GetStipple() );
2416  break;
2419  if ( 0 ) //m_printingMode )
2420  {
2421  wxBitmap noMask = m_activestroke.GetStipple();
2422  noMask.SetMask( NULL );
2423  style = wxBRUSHSTYLE_STIPPLE;
2424  dcpen.SetStyle( style );
2425  dcpen.SetStipple( noMask );
2426  }
2427  else
2428  {
2429  style = wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE;
2430  dcpen.SetStyle( style );
2431  dcpen.SetStipple( m_activestroke.GetStipple() );
2432  }
2433  break;
2434  default: style = wxBRUSHSTYLE_SOLID;
2435  dcpen.SetStyle( style );
2436  }
2437 #endif
2438 
2439  m_renderDC->SetPen( dcpen );
2440  m_renderDC->SetTextBackground( *wxBLACK );
2441  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
2442  }
2443 
2444  }
2445 }
2446 
2447 void a2dDcContext::DoSetActiveFill()
2448 {
2449  if ( m_renderDC )
2450  {
2451  if ( !m_activefill.GetFilling() )
2452  {
2453  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
2454  m_renderDC->SetTextBackground( *wxBLACK );
2455  }
2456  else if ( m_activefill.GetStyle() == a2dFILL_TRANSPARENT )
2457  {
2458  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
2459  m_renderDC->SetTextBackground( *wxBLACK );
2460  }
2461  else if ( m_activefill.IsNoFill() )
2462  {
2463  m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
2464  //m_renderDC->SetBrush( wxNullBrush );
2465  m_renderDC->SetTextBackground( *wxBLACK );
2466  }
2467  else if ( m_activefill.GetType() == a2dFILL_ONE_COLOUR )
2468  {
2469  wxBrush dcbrush;
2470  wxBrushStyle style;
2471  switch( m_activefill.GetStyle() )
2472  {
2473  case a2dFILL_TRANSPARENT:
2474  style = wxBRUSHSTYLE_TRANSPARENT;
2475  dcbrush.SetColour( m_activefill.GetColour() );
2476  dcbrush.SetStyle( style );
2477  break;
2478  case a2dFILL_SOLID: style = wxBRUSHSTYLE_SOLID;
2479  dcbrush.SetColour( m_activefill.GetColour() );
2480  dcbrush.SetStyle( style );
2481  break;
2483  style = wxBRUSHSTYLE_BDIAGONAL_HATCH;
2484  dcbrush.SetColour( m_activefill.GetColour() );
2485  dcbrush.SetStyle( style );
2486  break;
2488  style = wxBRUSHSTYLE_CROSSDIAG_HATCH;
2489  dcbrush.SetColour( m_activefill.GetColour() );
2490  dcbrush.SetStyle( style );
2491  break;
2493  style = wxBRUSHSTYLE_FDIAGONAL_HATCH;
2494  dcbrush.SetColour( m_activefill.GetColour() );
2495  dcbrush.SetStyle( style );
2496  break;
2497  case a2dFILL_CROSS_HATCH:
2498  style = wxBRUSHSTYLE_CROSS_HATCH;
2499  dcbrush.SetColour( m_activefill.GetColour() );
2500  dcbrush.SetStyle( style );
2501  break;
2503  style = wxBRUSHSTYLE_HORIZONTAL_HATCH;
2504  dcbrush.SetColour( m_activefill.GetColour() );
2505  dcbrush.SetStyle( style );
2506  break;
2508  style = wxBRUSHSTYLE_VERTICAL_HATCH;
2509  dcbrush.SetColour( m_activefill.GetColour() );
2510  dcbrush.SetStyle( style );
2511  break;
2512  default: style = wxBRUSHSTYLE_SOLID;
2513  dcbrush.SetColour( m_activefill.GetColour() );
2514  dcbrush.SetStyle( style );
2515  }
2516 
2517  m_renderDC->SetBrush( dcbrush );
2518  m_renderDC->SetTextBackground( m_activefill.GetColour() );
2519  }
2520  else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
2521  {
2522  wxBrush dcbrush;
2523  wxBrushStyle style;
2524  switch( m_activefill.GetStyle() )
2525  {
2526  case a2dFILL_TRANSPARENT:
2527  style = wxBRUSHSTYLE_TRANSPARENT;
2528  dcbrush.SetColour( m_activefill.GetColour() );
2529  dcbrush.SetStyle( style );
2530  break;
2532  style = wxBRUSHSTYLE_BDIAGONAL_HATCH;
2533  dcbrush.SetColour( m_activefill.GetColour() );
2534  dcbrush.SetStyle( style );
2535  break;
2537  style = wxBRUSHSTYLE_CROSSDIAG_HATCH;
2538  dcbrush.SetColour( m_activefill.GetColour() );
2539  dcbrush.SetStyle( style );
2540  break;
2542  style = wxBRUSHSTYLE_FDIAGONAL_HATCH;
2543  dcbrush.SetColour( m_activefill.GetColour() );
2544  dcbrush.SetStyle( style );
2545  break;
2547  style = wxBRUSHSTYLE_CROSS_HATCH;
2548  dcbrush.SetColour( m_activefill.GetColour() );
2549  dcbrush.SetStyle( style );
2550  break;
2552  style = wxBRUSHSTYLE_HORIZONTAL_HATCH;
2553  dcbrush.SetColour( m_activefill.GetColour() );
2554  dcbrush.SetStyle( style );
2555  break;
2557  style = wxBRUSHSTYLE_VERTICAL_HATCH;
2558  dcbrush.SetColour( m_activefill.GetColour() );
2559  dcbrush.SetStyle( style );
2560  break;
2561  default:
2562  style = wxBRUSHSTYLE_SOLID;
2563  dcbrush.SetColour( m_activefill.GetColour() );
2564  dcbrush.SetStyle( style );
2565  }
2566 
2567  m_renderDC->SetBrush( dcbrush );
2568  m_renderDC->SetTextBackground( m_activefill.GetColour() );
2569  }
2570  else if ( m_activefill.GetType() == a2dFILL_BITMAP )
2571  {
2572  wxBrush dcbrush;
2573  wxBrushStyle style;
2574  switch( m_activefill.GetStyle() )
2575  {
2576  case a2dFILL_STIPPLE:
2577  style = wxBRUSHSTYLE_STIPPLE;
2578  dcbrush.SetColour( m_activefill.GetColour() );
2579  dcbrush.SetStipple( m_activefill.GetStipple() );
2580  dcbrush.SetStyle( style );
2581  break;
2584  if ( 0 ) //m_printingMode )
2585  {
2586  wxBitmap noMask = m_activefill.GetStipple();
2587  noMask.SetMask( NULL );
2588  style = wxBRUSHSTYLE_STIPPLE;
2589  dcbrush.SetColour( m_activefill.GetColour() );
2590  dcbrush.SetStipple( noMask );
2591  }
2592  else
2593  {
2594  style = wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE;
2595  dcbrush.SetColour( m_activefill.GetColour() );
2596  dcbrush.SetStipple( m_activefill.GetStipple() );
2597  }
2598  dcbrush.SetStyle( style );
2599  break;
2600  default: style = wxBRUSHSTYLE_SOLID;
2601  dcbrush.SetColour( m_activefill.GetColour() );
2602  dcbrush.SetStyle( style );
2603  }
2604 
2605  m_renderDC->SetBrush( dcbrush );
2606  m_renderDC->SetTextBackground( m_activefill.GetColour() );
2607  }
2608  }
2609 }
2610 
2611 bool a2dDcContext::SetLogicalFunction( wxRasterOperationMode function )
2612 {
2613  switch( function )
2614  {
2615  case wxINVERT:
2616  m_drawstyle = a2dWIREFRAME_INVERT;
2617  m_activestroke = *a2dBLACK_STROKE;
2618  m_activefill = *a2dTRANSPARENT_FILL;
2619  break;
2620  default:
2621  m_drawstyle = a2dFILLED;
2622  }
2623 
2624  if ( m_renderDC )
2625  m_renderDC->SetLogicalFunction( function );
2626  return true;
2627 }
2628 
2629 void a2dDcContext::SetDrawStyle( a2dDrawStyle drawstyle )
2630 {
2631  m_drawstyle = drawstyle;
2632 
2633  switch( drawstyle )
2634  {
2635  case a2dWIREFRAME_INVERT:
2636  m_activestroke = *a2dBLACK_STROKE;
2637  m_activefill = *a2dTRANSPARENT_FILL;
2638  if ( m_renderDC )
2639  m_renderDC->SetLogicalFunction( wxINVERT );
2640  break;
2641 
2642  case a2dWIREFRAME:
2643  m_activestroke = *a2dBLACK_STROKE;
2644  m_activefill = *a2dTRANSPARENT_FILL;
2645  if ( m_renderDC )
2646  m_renderDC->SetLogicalFunction( wxCOPY );
2647  break;
2648 
2650  m_activestroke = *a2dBLACK_STROKE;
2651  m_activefill = *a2dTRANSPARENT_FILL;
2652  if ( m_renderDC )
2653  m_renderDC->SetLogicalFunction( wxCOPY );
2654  break;
2655 
2657  m_activestroke = *a2dBLACK_STROKE;
2658  m_activefill = *a2dTRANSPARENT_FILL;
2659  if ( m_renderDC )
2660  m_renderDC->SetLogicalFunction( wxINVERT );
2661  break;
2662 
2663  case a2dFILLED:
2664  if ( m_renderDC )
2665  m_renderDC->SetLogicalFunction( wxCOPY );
2666  break;
2667 
2668  default:
2669  wxASSERT( 0 );
2670  }
2671 }
2672 
2673 
2674 void a2dDcContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2675 {
2676  //need to calculate clip in device coordinates from world coordinates
2677  // not even rectangular in the end, so assume a polygon as result.
2678  wxPoint trpoints[4];
2679  double dx, dy;
2680 
2681  m_usertodevice.TransformPoint( x, y, dx, dy );
2682  trpoints[0] = wxPoint( dx, dy );
2683  m_usertodevice.TransformPoint( x, y + h, dx, dy );
2684  trpoints[1] = wxPoint( dx, dy );
2685  m_usertodevice.TransformPoint( x + w, y + h, dx, dy );
2686  trpoints[2] = wxPoint( dx, dy );
2687  m_usertodevice.TransformPoint( x + w, y, dx, dy );
2688  trpoints[3] = wxPoint( dx, dy );
2689 
2690  double xmin = trpoints[0].x;
2691  double ymin = trpoints[0].y;
2692  double xmax = trpoints[0].x;
2693  double ymax = trpoints[0].y;
2694  for ( int i = 1; i < 4; i ++ )
2695  {
2696  xmin = wxMin( xmin, trpoints[i].x );
2697  xmax = wxMax( xmax, trpoints[i].x );
2698  ymin = wxMin( ymin, trpoints[i].y );
2699  ymax = wxMax( ymax, trpoints[i].y );
2700  }
2701  wxRect cliprect = wxRect( xmin, ymin, xmax - xmin, ymax - ymin );
2702  m_clipboxdev = cliprect;
2703  wxRegion clip( cliprect );
2704  m_renderDC->DestroyClippingRegion();
2705 #if wxCHECK_VERSION(2,9,0)
2706  m_renderDC->SetDeviceClippingRegion( clip );
2707 #else
2708  m_renderDC->SetClippingRegion( clip );
2709 #endif
2710 }
2711 
2712 void a2dDcContext::ResetClip()
2713 {
2714  if ( m_renderDC )
2715  m_renderDC->DestroyClippingRegion();
2716  m_clipboxdev = wxRect( 0, 0, m_width, m_height );
2717 }
2718 
2719 #if wxCHECK_VERSION(2,9,0)
2720 void a2dDcContext::DrawBitmap( const wxGraphicsBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2721 #else
2722 void a2dDcContext::DrawGraphicsBitmap( const wxGraphicsBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2723 #endif
2724 {
2725  a2dBitmapData* data = static_cast<a2dBitmapData*>( bmp.GetRefData() );
2726  wxImage image = data->GetImage();
2727 
2728  if ( w == 0 || h == 0 )
2729  return;
2730 
2731  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
2732 
2733  wxPoint centr( ( int ) w / 2, ( int ) h / 2 ); //this doesn't make any difference (BUG?)
2734  //anyway the rotation center is the middle of the image
2735 
2736  double angle = m_usertodevice.GetRotation();
2737 
2738  if ( fabs( angle ) > 0.5 /*degree*/ )
2739  {
2740  image.SetMask( true );
2741  if ( m_yaxis )
2742  image = image.Rotate( angle / 180.0 * wxPI, centr, true, NULL );
2743  else
2744  image = image.Rotate( -angle / 180.0 * wxPI, centr, true, NULL );
2745  }
2746 
2747  int devicew, deviceh;
2748 
2749  devicew = m_usertodevice.TransformDistance( w );
2750  deviceh = fabs( m_usertodevice.TransformDistance( h ) );
2751 
2752  double hx, hy;
2753  m_usertodevice.TransformPoint( x, y, hx, hy );
2754  int devicex = ( int ) ( hx - devicew / 2.0 ); //devicex of projected (imaginairy) image
2755  int devicey = ( int ) ( hy - deviceh / 2.0 ); //devicey of projected (imaginairy) image
2756 
2757  // for drawing transparency
2758  bool imgHasMask = image.HasMask();
2759 
2760  if ( devicew == 0 || deviceh == 0 )
2761  return;
2762 
2763  double sx = image.GetWidth() / ( double ) devicew;
2764  double sy = image.GetHeight() / ( double ) deviceh;
2765 
2766  //don't scale what we do not need, therefore get a subimage
2767  wxRect clipped = m_clipboxdev;
2768  clipped.Intersect( wxRect( devicex, devicey, devicew, deviceh ) );
2769  double deviceClipX = clipped.GetX();
2770  double deviceClipY = clipped.GetY();
2771  double deviceClipW = clipped.GetWidth();
2772  double deviceClipH = clipped.GetHeight();
2773  // translate/rescale this to image coordinates
2774  clipped.SetX( ( clipped.GetX() - devicex ) * sx );
2775  clipped.SetY( ( clipped.GetY() - devicey ) * sy );
2776  clipped.SetWidth( clipped.GetWidth() * sx );
2777  clipped.SetHeight( clipped.GetHeight() * sy );
2778 
2779  //if the subimage image is so small (e.g. extreme zoomin), just draw a rectangle
2780  if ( clipped.GetWidth() < 1 || clipped.GetHeight() < 1 )
2781  {
2782  m_renderDC->DrawRectangle( devicex, devicey, devicew, deviceh );
2783  return;
2784  }
2785 
2786  if ( deviceClipW != devicew || deviceClipH != deviceh )
2787  image = image.GetSubImage( clipped );
2788 
2789  // now we first scale to screen projected size, often limits the amount of pixels to draw
2790  // when size is smaller then original pixel size.
2791  image.Rescale( deviceClipW, deviceClipH );//, wxIMAGE_QUALITY_HIGH );
2792 
2793  // we can not draw images, so first make it a bitmap, slow !
2794  wxBitmap Bitmap( image );
2795 
2796  if ( m_drawstyle == a2dFILLED )
2797  {
2798  wxMemoryDC MemoryDc;
2799  MemoryDc.SelectObject( Bitmap );
2800  // Copy the pre-stretched bitmap to the display device.
2801  m_renderDC->Blit( deviceClipX, deviceClipY, deviceClipW, deviceClipH, &MemoryDc, 0, 0, wxCOPY, imgHasMask );
2802  }
2803  else
2804  {
2805  m_renderDC->DrawRectangle( devicex, devicey, devicew, deviceh );
2806  }
2807 }
2808 
2809 void a2dDcContext::DrawVpath( const a2dVpath* path )
2810 {
2811  unsigned int segments = 0;
2812 
2813  double tstep = 1 / ( double ) SPLINE_STEP;
2814  unsigned int i;
2815  for ( i = 0; i < path->size(); i++ )
2816  {
2817  a2dVpathSegmentPtr seg = path->operator[]( i );
2818  switch ( seg->GetType() )
2819  {
2820  case a2dPATHSEG_CBCURVETO:
2822  segments += SPLINE_STEP;
2823  break;
2824 
2825  case a2dPATHSEG_QBCURVETO:
2827  segments += SPLINE_STEP;
2828  break;
2829 
2830  case a2dPATHSEG_ARCTO:
2832  {
2833  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
2834 
2835  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
2836 
2837  if ( cseg->CalcR( path->operator[]( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
2838  {
2839  double dphi;
2840  unsigned int circlesegments;
2841  double radiusDev = m_usertodevice.TransformDistance( radius );
2842  Aberration( m_displayaberration, phit, radiusDev , dphi, circlesegments );
2843  segments += circlesegments + 1;
2844  }
2845  else
2846  segments ++;
2847  }
2848  break;
2849  default:
2850  segments++;
2851 
2852  }
2853  }
2854 
2855  //TODO memory error because of wrong calculation of segments?? for the moment *2 to be save
2856  m_cpointsDouble.resize( segments * 2 );
2857 
2858  double x, y;
2859  bool move = false;
2860  int count = 0;
2861  bool nostrokeparts = false;
2862 
2863  //first draw as much as possible ( nostroke parts may stop this first round )
2864  for ( i = 0; i < path->size(); i++ )
2865  {
2866  a2dVpathSegmentPtr seg = path->operator[]( i );
2867  switch ( seg->GetType() )
2868  {
2869  case a2dPATHSEG_MOVETO:
2870  if ( count == 0 )
2871  {
2872  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
2873  m_cpointsDouble[count].x = x;
2874  m_cpointsDouble[count].y = y;
2875  count++;
2876  }
2877  else
2878  {
2879  i--;
2880  move = true;
2881  }
2882  break;
2883 
2884  case a2dPATHSEG_LINETO:
2885  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
2886  m_cpointsDouble[count].x = x;
2887  m_cpointsDouble[count].y = y;
2888  count++;
2889  break;
2891  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
2892  m_cpointsDouble[count].x = x;
2893  m_cpointsDouble[count].y = y;
2894  count++;
2895  nostrokeparts = true;
2896  break;
2897 
2899  nostrokeparts = true;
2900  case a2dPATHSEG_CBCURVETO:
2901  {
2902  double xw, yw;
2903 
2904  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
2905  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
2907 
2908  int step;
2909  double t = 0;
2910  for ( step = 0; step <= SPLINE_STEP; step++ )
2911  {
2912  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 );
2913  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 );
2914  m_usertodevice.TransformPoint( xw, yw, x, y );
2915  m_cpointsDouble[count].x = x;
2916  m_cpointsDouble[count].y = y;
2917  count++;
2918  t = t + tstep;
2919  }
2920  }
2921  break;
2922 
2924  nostrokeparts = true;
2925  case a2dPATHSEG_QBCURVETO:
2926  {
2927  double xw, yw;
2928 
2929  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
2930  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
2932 
2933  int step;
2934  double t = 0;
2935  for ( step = 0; step <= SPLINE_STEP; step++ )
2936  {
2937  xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
2938  yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
2939  m_usertodevice.TransformPoint( xw, yw, x, y );
2940  m_cpointsDouble[count].x = x;
2941  m_cpointsDouble[count].y = y;
2942  count++;
2943  t = t + tstep;
2944  }
2945  }
2946  break;
2947 
2949  nostrokeparts = true;
2950  case a2dPATHSEG_ARCTO:
2951  {
2952  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
2953 
2954  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
2955 
2956  if ( cseg->CalcR( path->operator[]( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
2957  {
2958  double dphi;
2959  unsigned int segments;
2960  double radiusDev = m_usertodevice.TransformDistance( radius );
2961  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
2962 
2963  double theta = beginrad;
2964  unsigned int step;
2965 
2966  double x, y;
2967  for ( step = 0; step < segments + 1; step++ )
2968  {
2969  m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
2970  m_cpointsDouble[count].x = x;
2971  m_cpointsDouble[count].y = y;
2972  count++;
2973  theta = theta + dphi;
2974  }
2975  }
2976  else
2977  {
2978  double x, y;
2979  m_usertodevice.TransformPoint( cseg->m_x1, cseg->m_y1, x, y );
2980  m_cpointsDouble[count].x = x;
2981  m_cpointsDouble[count].y = y;
2982  count++;
2983  }
2984  }
2985  default:
2986  break;
2987  break;
2988  }
2989 
2990  if ( move )
2991  {
2992  DeviceDrawLines( count, false );
2993  move = false;
2994  count = 0;
2995  }
2996  else if ( seg->GetClose() != a2dPATHSEG_END_OPEN )
2997  {
2998  if ( nostrokeparts || seg->GetClose() == a2dPATHSEG_END_CLOSED_NOSTROKE )
2999  {
3000  a2dStroke stroke = m_activestroke;
3001  m_activestroke = *a2dTRANSPARENT_STROKE;
3002  DeviceDrawPolygon( count, false, wxODDEVEN_RULE );
3003  m_activestroke = stroke;
3004  nostrokeparts = true;
3005  }
3006  else
3007  {
3008  DeviceDrawPolygon( count, false, wxODDEVEN_RULE );
3009  }
3010 
3011  move = false;
3012  count = 0;
3013  }
3014  else if ( i == path->size() - 1 ) //last segment?
3015  {
3016  DeviceDrawLines( count, false );
3017  }
3018  }
3019 
3020  if ( nostrokeparts )
3021  {
3022  move = false;
3023  count = 0;
3024  nostrokeparts = false;
3025 
3026  double lastmovex = 0;
3027  double lastmovey = 0;
3028 
3029  for ( i = 0; i < path->size(); i++ )
3030  {
3031  a2dVpathSegmentPtr seg = path->operator[]( i );
3032  switch ( seg->GetType() )
3033  {
3034  case a2dPATHSEG_MOVETO:
3035  if ( count == 0 )
3036  {
3037  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
3038  m_cpointsDouble[count].x = x;
3039  m_cpointsDouble[count].y = y;
3040  lastmovex = m_cpointsDouble[count].x;
3041  lastmovey = m_cpointsDouble[count].y;
3042  count++;
3043  }
3044  else
3045  {
3046  i--;
3047  move = true;
3048  }
3049  break;
3050 
3051  case a2dPATHSEG_LINETO:
3052  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
3053  m_cpointsDouble[count].x = x;
3054  m_cpointsDouble[count].y = y;
3055  count++;
3056  break;
3057 
3062  if ( count == 0 )
3063  {
3064  m_usertodevice.TransformPoint( seg->m_x1, seg->m_y1, x, y );
3065  m_cpointsDouble[count].x = x;
3066  m_cpointsDouble[count].y = y;
3067  count++;
3068  }
3069  else
3070  {
3071  i--;
3072  nostrokeparts = true;
3073  }
3074  break;
3075 
3076  case a2dPATHSEG_CBCURVETO:
3077  {
3078  double xw, yw;
3079 
3080  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
3081  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
3083 
3084  int step;
3085  double t = 0;
3086  for ( step = 0; step <= SPLINE_STEP; step++ )
3087  {
3088  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 );
3089  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 );
3090  m_usertodevice.TransformPoint( xw, yw, x, y );
3091  m_cpointsDouble[count].x = x;
3092  m_cpointsDouble[count].y = y;
3093  count++;
3094  t = t + tstep;
3095  }
3096  }
3097  break;
3098 
3099  case a2dPATHSEG_QBCURVETO:
3100  {
3101  double xw, yw;
3102 
3103  double xwl = path->operator[]( i ? i - 1 : 0 )->m_x1;
3104  double ywl = path->operator[]( i ? i - 1 : 0 )->m_y1;
3106 
3107  int step;
3108  double t = 0;
3109  for ( step = 0; step <= SPLINE_STEP; step++ )
3110  {
3111  xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
3112  yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
3113  m_usertodevice.TransformPoint( xw, yw, x, y );
3114  m_cpointsDouble[count].x = x;
3115  m_cpointsDouble[count].y = y;
3116  count++;
3117  t = t + tstep;
3118  }
3119  }
3120  break;
3121 
3122  case a2dPATHSEG_ARCTO:
3123  {
3124  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
3125 
3126  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
3127 
3128  if ( cseg->CalcR( path->operator[]( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
3129  {
3130  double dphi;
3131  unsigned int segments;
3132  double radiusDev = m_usertodevice.TransformDistance( radius );
3133  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
3134 
3135  double theta = beginrad;
3136  unsigned int step;
3137 
3138  double x, y;
3139  for ( step = 0; step < segments + 1; step++ )
3140  {
3141  m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
3142  m_cpointsDouble[count].x = x;
3143  m_cpointsDouble[count].y = y;
3144  count++;
3145  theta = theta + dphi;
3146  }
3147  }
3148  else
3149  {
3150  double x, y;
3151  m_usertodevice.TransformPoint( cseg->m_x1, cseg->m_y1, x, y );
3152  m_cpointsDouble[count].x = x;
3153  m_cpointsDouble[count].y = y;
3154  count++;
3155  }
3156  }
3157  default:
3158  break;
3159 
3160  break;
3161  }
3162 
3163  if ( move || nostrokeparts )
3164  {
3165  DeviceDrawLines( count, false );
3166  move = false;
3167  nostrokeparts = false;
3168  count = 0;
3169  }
3170  else if ( seg->GetClose() != a2dPATHSEG_END_OPEN )
3171  {
3172  if ( seg->GetClose() == a2dPATHSEG_END_CLOSED )
3173  {
3174  m_cpointsDouble[count].x = lastmovex;
3175  m_cpointsDouble[count].y = lastmovey;
3176  count++;
3177  }
3178  DeviceDrawLines( count, false );
3179  nostrokeparts = false;
3180  move = false;
3181  count = 0;
3182  }
3183  else if ( i == path->size() )
3184  {
3185  DeviceDrawLines( count, false );
3186  }
3187  }
3188  }
3189 
3190 }
3191 
3192 
3193 void a2dDcContext::DeviceDrawPolygon( unsigned int n, bool spline, wxPolygonFillMode fillStyle )
3194 {
3195  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
3196 
3197  wxPoint* int_cpts = _convertToIntPointCache( n, &m_cpointsDouble[0] );
3198 
3199  // filter the no filling, in order to draw polylines instead
3200  if ( IsStrokeOnly() )
3201  {
3202  if ( n == 2 )
3203  {
3204  //Draw polyline instead
3205  m_renderDC->DrawLines( n, int_cpts );
3206  // in invert mode do not draw the line back since it will result in drawing nothing.
3207  if ( m_drawstyle == a2dWIREFRAME || m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
3208  m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n - 1].x, int_cpts[n - 1].y );
3209  }
3210  else
3211  {
3212  // i assume drawpolygon makes effective use of the fact that the polygon is transparent/not filled,
3213  // drawing just lines shows no difference in speed on MSW
3214 #if defined(__WXMSW__)
3215 #if wxCHECK_VERSION(2,9,0)
3216  wxMSWDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
3217  WXHDC hdc = dcimpl->GetHDC();
3218 #else
3219  WXHDC hdc = m_renderDC->GetHDC();
3220 #endif
3221  SetPolyFillMode( ( struct HDC__* ) hdc, fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING );
3222  //prevent to do things that are not needed (like bbox calculation and checking things)
3223  //This way is the most direct and fastest possible manner to draw a polygon using API
3224  ( void )Polygon( ( struct HDC__* ) hdc, ( POINT* )int_cpts, n );
3225 //#elif __WXGTK__
3226 #else
3227  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
3228 #endif
3229 
3230  }
3231  }
3232  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR || m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
3233  {
3234  FillPolygon( n, &m_cpointsDouble[0] );
3235 
3236  if ( IsStroked() )
3237  {
3238  m_renderDC->DrawLines( n, int_cpts );
3239  m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n - 1].x, int_cpts[n - 1].y );
3240  }
3241  }
3242  else if ( m_activefill.GetType() == a2dFILL_BITMAP && m_activefill.GetStyle() == a2dFILL_STIPPLE_MASK_OPAQUE_TRANSPARENT )
3243  {
3244 #if defined(__WXMSW__)
3245  m_renderDC->SetTextForeground( *wxBLACK );
3246  m_renderDC->SetTextBackground( *wxWHITE );
3247  m_renderDC->SetLogicalFunction( wxAND_INVERT );
3248 
3249  //the above
3250  COLORREF colFgOld, colBgOld;
3251 
3252 #if wxCHECK_VERSION(2,9,0)
3253  wxMSWDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
3254  WXHDC hdc = dcimpl->GetHDC();
3255 #else
3256  WXHDC hdc = m_renderDC->GetHDC();
3257 #endif
3258 
3259  colBgOld = ::GetBkColor( ( struct HDC__* ) hdc );
3260  colFgOld = ::GetTextColor( ( struct HDC__* ) hdc );
3261 
3262  //just the opposite from what is expected see help on pattern brush
3263  // 1 in mask becomes bk color
3264  ::SetBkColor( ( struct HDC__* ) hdc, m_renderDC->GetTextForeground().GetPixel() );
3265  //just the opposite from what is expected
3266  // 0 in mask becomes text color
3267  ::SetTextColor( ( struct HDC__* ) hdc, m_renderDC->GetTextBackground().GetPixel() );
3268 
3269  int prev = SetPolyFillMode( ( struct HDC__* ) hdc, WINDING );
3270  ( void )Polygon( ( struct HDC__* ) hdc, ( POINT* )int_cpts, n );
3271 
3272  // Set background and foreground colors for fill pattern
3273  //the previous blacked out pixels are now merged with the layer color
3274  //while the non blacked out pixels stay as they are.
3275  m_renderDC->SetTextForeground( *wxBLACK );
3276  //now define what will be the color of the fillpattern parts that are not transparent
3277  m_renderDC->SetTextBackground( m_activefill.GetColour() );
3278  m_renderDC->SetLogicalFunction( wxOR );
3279 
3280  //just the opposite from what is expected see help on pattern brush
3281  // 1 in mask becomes bk color
3282  ::SetBkColor( ( struct HDC__* ) hdc, m_renderDC->GetTextForeground().GetPixel() );
3283  //just the opposite from what is expected
3284  // 0 in mask becomes text color
3285  ::SetTextColor( ( struct HDC__* ) hdc, m_renderDC->GetTextBackground().GetPixel() );
3286  ( void )Polygon( ( struct HDC__* ) hdc, ( POINT* )int_cpts, n );
3287  SetPolyFillMode( ( struct HDC__* ) hdc, prev );
3288 
3289  // restore the colours we changed
3290  ::SetBkMode( ( struct HDC__* ) hdc, TRANSPARENT );
3291  ::SetTextColor( ( struct HDC__* ) hdc, colFgOld );
3292  ::SetBkColor( ( struct HDC__* ) hdc, colBgOld );
3293 
3294  m_renderDC->SetLogicalFunction( wxCOPY );
3295  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
3296  m_renderDC->SetTextBackground( m_activefill.GetColour() );
3297 
3298  //now do the stroke drawing
3299  if ( IsStroked() )
3300  {
3301  m_renderDC->DrawLines( n, int_cpts );
3302  m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n - 1].x, int_cpts[n - 1].y );
3303  }
3304 
3305 //#elif __WXGTK__
3306 #else
3307  wxPen dcpen( m_activestroke.GetColour(), ( int ) m_activestroke.GetWidth(), wxSOLID );
3308  //if ( !m_activestroke.GetPixelStroke() )
3309  // dcpen.SetWidth( ( int )WorldToDeviceXRel( m_activestroke.GetWidth() ) );
3310  m_renderDC->SetPen( dcpen );
3311 
3312  m_renderDC->SetTextForeground( *wxBLACK );
3313  m_renderDC->SetTextBackground( *wxWHITE );
3314  m_renderDC->SetLogicalFunction( wxAND_INVERT );
3315  // BLACK OUT the opaque pixels and leave the rest as is
3316  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
3317  // Set background and foreground colors for fill pattern
3318  //the previous blacked out pixels are now merged with the layer color
3319  //while the non blacked out pixels stay as they are.
3320  m_renderDC->SetTextForeground( *wxBLACK );
3321  //now define what will be the color of the fillpattern parts that are not transparent
3322  m_renderDC->SetTextBackground( m_activefill.GetColour() );
3323  m_renderDC->SetLogicalFunction( wxOR );
3324  //don't understand how but the outline is also depending on logicalfunction
3325  SetStroke( m_activestroke );
3326  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
3327  m_renderDC->SetLogicalFunction( wxCOPY );
3328  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
3329  m_renderDC->SetTextBackground( m_activefill.GetColour() );
3330 
3331  //now do the stroke drawing
3332  if ( IsStroked() )
3333  {
3334  m_renderDC->DrawLines( n, int_cpts );
3335  m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n - 1].x, int_cpts[n - 1].y );
3336  }
3337 #endif
3338  }
3339  else if ( m_activefill.GetType() == a2dFILL_BITMAP &&
3340  ( m_activefill.GetStyle() == a2dFILL_STIPPLE ||
3341  m_activefill.GetStyle() == a2dFILL_STIPPLE_MASK_OPAQUE )
3342  )
3343  {
3344  m_renderDC->SetTextForeground( m_activefill.GetColour() );
3345  m_renderDC->SetTextBackground( m_activefill.GetColour2() );
3346  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
3347  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
3348  m_renderDC->SetTextBackground( m_activefill.GetColour() );
3349  }
3350  else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
3351  {
3352  wxBrush dcbrush( m_activefill.GetColour2() );
3353  wxBrush cur_dcbrush = m_renderDC->GetBrush();
3354  m_renderDC->SetBrush( dcbrush );
3355  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
3356  m_renderDC->SetBrush( cur_dcbrush );
3357  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
3358  }
3359  else
3360  {
3361 #if defined(__WXMSW__)
3362  //prevent to do think that are not needed (like bbox calculation and checking things)
3363  //This way is the most direct and fastest possible manner to draw a polygon using API
3364 
3365  //SetPolyFillMode((struct HDC__ *) hdc,fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
3366  //(void)Polygon((struct HDC__ *) hdc, (POINT*)int_cpts, n);
3367  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
3368 //#elif __WXGTK__
3369 #else
3370  m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
3371 #endif
3372  }
3373 
3374  if ( IsStroked() && m_activestroke.GetType() == a2dSTROKE_OBJECT )
3375  {
3376  //we must make a copy of the device points now because recursive call
3377  //can be made in here, which will change the points stored in the drawer.
3378  //First point repeated extra since it is for outline
3379  wxRealPoint* copy = new wxRealPoint[n + 1];
3380  memcpy( copy, &m_cpointsDouble[0], n * sizeof( wxRealPoint ) );
3381  copy[n].x = m_cpointsDouble[0].x;
3382  copy[n].y = m_cpointsDouble[0].y;
3383 
3384  //!todo m_activestroke->Render( this, m_clipboxworld, n + 1, copy );
3385  delete [] copy;
3386  }
3387 }
3388 
3389 void a2dDcContext::DeviceDrawLines( unsigned int n, bool spline )
3390 {
3391  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
3392 
3393  wxPoint* int_cpts = _convertToIntPointCache( n, &m_cpointsDouble[0] );
3394 
3395  if ( n == 1 )
3396  m_renderDC->DrawCircle( int_cpts[0].x, int_cpts[0].y, 2 );
3397 // m_renderDC->DrawPoint( int_cpts[0].x, int_cpts[0].y );
3398  else
3399  {
3400  m_renderDC->DrawLines( n, int_cpts );
3401 #if defined(__WXMSW__)
3402  // Windows does not draw the last pixel if the pensize is 1.
3403  // especially disturbing for stroke fonts.
3404  if ( n > 1 && m_renderDC->GetPen().GetWidth() == 1 )
3405  m_renderDC->DrawPoint( int_cpts[n - 1].x, int_cpts[n - 1].y );
3406 #endif
3407  }
3408 }
3409 
3410 void a2dDcContext::DeviceDrawLine( double x1, double y1, double x2, double y2 )
3411 {
3412  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
3413 
3414  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y2 ) );
3415 }
3416 
3417 void a2dDcContext::DeviceDrawHorizontalLine( int x1, int y1, int x2, bool use_stroke_color )
3418 {
3419  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
3420 
3421  wxColour color;
3422  if ( use_stroke_color )
3423  {
3424  wxPen pen = m_renderDC->GetPen();
3425  color = wxColour( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
3426  m_renderDC->SetPen( wxPen( color ) );
3427  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y1 ) );
3428  m_renderDC->SetPen( pen );
3429  }
3430  else
3431  {
3432  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y1 ) );
3433  }
3434 }
3435 
3436 void a2dDcContext::DeviceDrawVerticalLine( int x1, int y1, int y2, bool use_stroke_color )
3437 {
3438  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
3439 
3440  wxColour color;
3441  if ( use_stroke_color )
3442  {
3443  wxPen pen = m_renderDC->GetPen();
3444  color = wxColour( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
3445  m_renderDC->SetPen( wxPen( color ) );
3446  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x1 ), Round( y2 ) );
3447  m_renderDC->SetPen( pen );
3448  }
3449  else
3450  {
3451  m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x1 ), Round( y2 ) );
3452  }
3453 }
3454 
3455 void a2dDcContext::DeviceDrawPixel( int x1, int y1, unsigned char r, unsigned char g, unsigned char b , unsigned char a )
3456 {
3457 #if defined(__WXMSW__)
3458 #if wxCHECK_VERSION(2,9,0)
3459  wxMSWDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
3460  WXHDC hdc = dcimpl->GetHDC();
3461 #else
3462  WXHDC hdc = m_renderDC->GetHDC();
3463 #endif
3464  ::SetPixelV( ( struct HDC__* )hdc, x1, y1, RGB( r, g, b ) );
3465 #elif __WXGTK__
3466 
3467 #if wxCHECK_VERSION(2,9,1)
3468  wxWindowDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxWindowDCImpl );
3469  GdkWindow* gtkwin = dcimpl->GetGDKWindow();
3470  if ( gtkwin )
3471  gdk_draw_point( gtkwin, dcimpl->m_penGC, x1, y1 );
3472 #else
3473  wxColour col( r, g, b );
3474  col.CalcPixel( ( ( wxWindowDC* )m_renderDC )->m_cmap );
3475  gdk_gc_set_foreground( ( ( wxWindowDC* )m_renderDC )->m_penGC, col.GetColor() );
3476  gdk_draw_point( ( ( wxWindowDC* ) m_renderDC )->m_window, ( ( wxWindowDC* )m_renderDC )->m_penGC, x1, y1 );
3477 #endif
3478 
3479 #else
3480 
3481 #endif
3482 }
3483 
3484 void a2dDcContext::DeviceDrawBitmap( const wxBitmap& bmp, double x, double y, bool useMask )
3485 {
3486  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
3487  if ( m_drawstyle == a2dWIREFRAME_INVERT )
3488  {
3489  m_renderDC->DrawRectangle( Round( x ), Round( y ), bmp.GetWidth(), bmp.GetHeight() );
3490  }
3491  else
3492  m_renderDC->DrawBitmap( bmp, Round( x ), Round( y ), useMask );
3493 }
3494 
3495 void a2dDcContext::DrawCharDc( wxChar c )
3496 {
3497  double x, y;
3498  x = y = 0.0;
3499  double dx, dy;
3500  double angle = m_usertodevice.GetRotation();
3501  m_usertodevice.TransformPoint( x, y + m_a2dfont.GetLineHeight(), dx, dy );
3502  m_renderDC->DrawRotatedText( wxString( c ), ( int ) dx, ( int ) dy, -angle );
3503 }
3504 
3505 void a2dDcContext::DrawTextDc( const wxString& text, double x, double y )
3506 {
3507  wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
3508 
3509  // Get font size in device units
3510  unsigned int fontsize;
3511  double dx = m_usertodevice.GetValue( 1, 0 );
3512  double dy = m_usertodevice.GetValue( 1, 1 );
3513  fontsize = ( unsigned int ) fabs( m_a2dfont.GetSize() * sqrt( dx * dx + dy * dy ) );
3514  if ( fontsize < 1 )
3515  fontsize = 1;
3516  m_a2dfont.GetFont().SetPointSize( fontsize );
3517 
3518  m_renderDC->SetFont( m_a2dfont.GetFont() );
3519  m_renderDC->SetBackgroundMode( wxTRANSPARENT );
3520  m_renderDC->SetTextForeground( m_activestroke.GetColour() );
3521 
3522  DrawTextGeneric( text, x, y, ( void ( a2dContext::* )( wxChar ) ) & a2dDcContext::DrawCharDc );
3523 }
3524 
3525 #if wxART2D_USE_FREETYPE
3526 extern FT_Library g_freetypeLibrary;
3527 
3528 //! used in freetype rendering
3529 typedef struct
3530 {
3531  wxColour colour;
3532  int xmin, ymax;
3533  int stride;
3534  unsigned char* buf;
3535 }
3536 a2dSpanData;
3537 
3538 //! used in freetype rendering
3539 static void a2dSpanFuncGray( int y, int count, FT_Span* spans, a2dSpanData* user )
3540 {
3541  unsigned int alpha, invalpha, len;
3542  // although colours are chars, using ints is faster in multiplications.
3543  unsigned int r, g, b, rpm, gpm, bpm;
3544  r = user->colour.Red();
3545  g = user->colour.Green();
3546  b = user->colour.Blue();
3547 
3548  unsigned char* buf, *buf2;
3549  buf = user->buf + ( user->ymax - y ) * user->stride - user->xmin * 3;
3550  do
3551  {
3552  buf2 = buf + spans->x * 3;
3553  len = spans->len;
3554  alpha = spans->coverage;
3555  if ( alpha == 255 )
3556  {
3557  while( len )
3558  {
3559  // do not try to replace by *buf2++ = r, etc.
3560  // it turns out that this code actually is faster (for x86).
3561 #ifdef __WXGTK__
3562  buf2[0] = r;
3563  buf2[1] = g;
3564  buf2[2] = b;
3565 #else
3566  buf2[0] = b;
3567  buf2[1] = g;
3568  buf2[2] = r;
3569 #endif
3570  buf2 += 3;
3571  len--;
3572  }
3573  }
3574  else
3575  {
3576  rpm = r * alpha;
3577  gpm = g * alpha;
3578  bpm = b * alpha;
3579  invalpha = 255 - alpha;
3580  while( len )
3581  {
3582  // do not try to replace by *buf2++ = ..., etc.
3583  // it turns out that this code actually is faster (for x86).
3584 #ifdef __WXGTK__
3585  buf2[0] = ( buf2[0] * invalpha + rpm ) / 255;
3586  buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
3587  buf2[2] = ( buf2[2] * invalpha + bpm ) / 255;
3588 #else
3589  buf2[0] = ( buf2[0] * invalpha + bpm ) / 255;
3590  buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
3591  buf2[2] = ( buf2[2] * invalpha + rpm ) / 255;
3592 #endif
3593  buf2 += 3;
3594  len--;
3595  }
3596  }
3597  spans++;
3598  }
3599  while ( --count );
3600 }
3601 #endif
3602 
3603 void a2dDcContext::DrawCharFreetype( wxChar c )
3604 {
3605 #if wxART2D_USE_FREETYPE
3606  // Add offset, to put anchor on lower-left point of bbox.
3607  double dx, dy;
3608  m_usertodevice.TransformPoint( 0.0, m_a2dfont.GetDescent(), dx, dy );
3609 
3610  // Get the glyph and make a copy of it
3611  const a2dGlyph* a2dglyph = m_a2dfont.GetGlyphFreetype( c );
3612  if( !a2dglyph )
3613  return;
3614  FT_Glyph image;
3615  if ( FT_Glyph_Copy( a2dglyph->m_glyph, &image ) != 0 )
3616  return;
3617 
3618  // Generate affine, to scale character from normalized to real size.
3619  a2dAffineMatrix glyphPos;
3620  glyphPos.Scale( m_a2dfont.GetSize() / NORMFONT );
3621  a2dAffineMatrix glyphToDevice = m_usertodevice * glyphPos;
3622 
3623  // Transform glyph and scale it to device coordinates. Also correct for sub-pixel drawing.
3624  FT_Matrix trans_matrix;
3625  trans_matrix.xx = ( FT_Fixed ) ( glyphToDevice.GetValue( 0, 0 ) * 0x10000 );
3626  trans_matrix.xy = ( FT_Fixed ) ( glyphToDevice.GetValue( 1, 0 ) * 0x10000 );
3627  trans_matrix.yx = ( FT_Fixed ) ( -glyphToDevice.GetValue( 0, 1 ) * 0x10000 );
3628  trans_matrix.yy = ( FT_Fixed ) ( -glyphToDevice.GetValue( 1, 1 ) * 0x10000 );
3629  FT_Vector vec;
3630  vec.x = ( int ) ( ( dx - ( int ) dx ) * 64.0 );
3631  vec.y = ( int ) ( ( dy - ( int ) dy ) * -64.0 );
3632  if ( FT_Glyph_Transform( image, &trans_matrix, &vec ) != 0 )
3633  {
3634  wxFAIL_MSG( _( "glyph transform wrong" ) );
3635  FT_Done_Glyph( image );
3636  return;
3637  }
3638 
3639  // Get bounding box of the area which should be drawn.
3640  FT_BBox bbox;
3641  FT_Glyph_Get_CBox( image, ft_glyph_bbox_pixels, &bbox );
3642 
3643  // clip against clipbox.
3644  if ( m_clipboxdev.GetLeft() > ( int ) dx + bbox.xMin )
3645  bbox.xMin = m_clipboxdev.GetLeft() - ( int ) dx;
3646  if ( m_clipboxdev.GetRight() < ( int ) dx + bbox.xMax )
3647  bbox.xMax = m_clipboxdev.GetRight() - ( int ) dx;
3648 
3649  if ( m_clipboxdev.GetTop() >= ( int ) dy - bbox.yMax )
3650  bbox.yMax = ( int ) dy - m_clipboxdev.GetTop();
3651  if ( m_clipboxdev.GetBottom() < ( int ) dy - bbox.yMin )
3652  bbox.yMin = ( int ) dy - m_clipboxdev.GetBottom();
3653 
3654  // If size == 0, nothing has to be drawn.
3655  if ( bbox.xMax - bbox.xMin <= 0 || bbox.yMax - bbox.yMin <= 0 )
3656  {
3657  FT_Done_Glyph( image );
3658  return;
3659  }
3660 
3661  int px = ( int ) dx + bbox.xMin;
3662  int py = ( int ) dy - bbox.yMax;
3663  int w = bbox.xMax - bbox.xMin + 1;
3664  int h = bbox.yMax - bbox.yMin + 1;
3665 
3666  // Obtain background image
3667  wxRect absarea2( px, py, w, h );
3668  wxBitmap sub_bitmap = m_buffer->GetSubBitmap( absarea2 );
3669 
3670 #if defined(__WXMSW__)
3671  BITMAPINFO bi;
3672  bi.bmiHeader.biSize = sizeof( bi.bmiHeader );
3673  bi.bmiHeader.biWidth = w;
3674  bi.bmiHeader.biHeight = -h;
3675  bi.bmiHeader.biPlanes = 1;
3676  bi.bmiHeader.biBitCount = 24;
3677  bi.bmiHeader.biCompression = BI_RGB;
3678  bi.bmiHeader.biSizeImage = 0;
3679  bi.bmiHeader.biClrUsed = 0;
3680  bi.bmiHeader.biClrImportant = 0;
3681 
3682  HBITMAP hbitmap = ( HBITMAP ) sub_bitmap.GetHBITMAP();
3683  HDC hdc = ::GetDC( NULL );
3684  HDC memdc = ::CreateCompatibleDC( hdc );
3685  unsigned char* buf = ( unsigned char* ) malloc( ( 3 * w + sizeof( DWORD ) - 1 ) / sizeof( DWORD ) * sizeof( DWORD ) * h );
3686  ::GetDIBits( memdc, hbitmap, 0, h, buf, &bi, DIB_RGB_COLORS );
3687 #else // defined( __WXMSW__ )
3688  wxImage wximage( sub_bitmap.ConvertToImage() );
3689 #endif // defined( __WXMSW__ )
3690 
3691  // Render glyph to an image
3692  if ( image->format == FT_GLYPH_FORMAT_OUTLINE )
3693  {
3694  a2dSpanData spandata;
3695  spandata.colour = m_activestroke.GetColour();
3696  spandata.xmin = bbox.xMin;
3697  spandata.ymax = bbox.yMax;
3698  spandata.stride = w * 3;
3699 #if defined(__WXMSW__)
3700  // calculate image stride ( = w + padding )
3701  spandata.stride = ( spandata.stride + sizeof( DWORD ) - 1 ) / sizeof( DWORD ) * sizeof( DWORD );
3702  spandata.buf = buf;
3703 #else // defined( __WXMSW__ )
3704  spandata.buf = wximage.GetData();
3705 #endif // defined( __WXMSW__ )
3706  wxASSERT( spandata.buf != NULL );
3707 
3708  FT_Raster_Params params;
3709  params.target = NULL;
3710  params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT | FT_RASTER_FLAG_CLIP;
3711  params.gray_spans = ( FT_SpanFunc ) & a2dSpanFuncGray;
3712  params.black_spans = NULL;
3713  params.bit_test = ( FT_Raster_BitTest_Func ) NULL;
3714  params.bit_set = ( FT_Raster_BitSet_Func ) NULL;
3715  params.user = &spandata;
3716  params.clip_box = bbox;
3717 
3718  FT_Outline& outline = ( ( FT_OutlineGlyph ) image )->outline;
3719  if ( FT_Outline_Render( g_freetypeLibrary, &outline, &params ) == 0 )
3720  {
3721 #if defined( __WXMSW__ )
3722  ::SetDIBits( memdc, hbitmap, 0, h, buf, &bi, DIB_RGB_COLORS );
3723 #else // defined( __WXMSW__ )
3724  wxBitmap sub_bitmap( wximage );
3725 #endif // defined( __WXMSW__ )
3726  DeviceDrawBitmap( sub_bitmap, px, py, false );
3727  }
3728  }
3729  else
3730  wxFAIL_MSG( _( "Non vector fonts are not supported" ) );
3731 
3732 #if defined(__WXMSW__)
3733  free( buf );
3734  ::DeleteDC( memdc );
3735  ::ReleaseDC( NULL, hdc );
3736 #endif // defined( __WXMSW__ )
3737 
3738  FT_Done_Glyph( image );
3739 #else // wxART2D_USE_FREETYPE
3740  DrawCharUnknown( c );
3741 #endif // wxART2D_USE_FREETYPE
3742 }
3743 /*
3744 void a2dDcContext::DrawImage( const a2dImageRGBA& image, double x, double y, double width, double height, wxUint8 Opacity )
3745 {
3746 }
3747 
3748 void a2dDcContext::DrawImage( const wxImage& imagein, double x, double y, double width, double height, wxUint8 Opacity )
3749 {
3750 }
3751 */
3752 
3753 
3754 //-----------------------------------------------------------------------------
3755 // a2dRenderer implementation
3756 //-----------------------------------------------------------------------------
3757 
3758 IMPLEMENT_DYNAMIC_CLASS( a2dRenderer, wxGraphicsRenderer )
3759 
3760 
3761 wxGraphicsContext* a2dRenderer::CreateContext( const wxWindowDC& dc )
3762 {
3763  wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
3764  return NULL;
3765 }
3766 
3767 wxGraphicsContext* a2dRenderer::CreateContext( const wxMemoryDC& dc )
3768 {
3769  //return new a2dDcContext( this, &dc, &(dc.GetSelectedBitmap()) );
3770  wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
3771  return NULL;
3772 }
3773 
3774 wxGraphicsContext* a2dRenderer::CreateContext( wxMemoryDC* dc, wxBitmap* drawable )
3775 {
3776  return new a2dDcContext( this, dc, drawable );
3777 }
3778 
3779 wxGraphicsContext* a2dRenderer::CreateContextFromNativeContext( void* context )
3780 {
3781  wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
3782  return NULL;
3783 }
3784 
3785 #if wxCHECK_VERSION(2, 9, 0)
3786 #if wxUSE_PRINTING_ARCHITECTURE
3787 wxGraphicsContext* a2dRenderer::CreateContext( const wxPrinterDC& dc )
3788 {
3789  wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
3790  return NULL;
3791 }
3792 #ifdef __WXMSW__
3793 wxGraphicsContext* a2dRenderer::CreateContext( const wxEnhMetaFileDC& dc )
3794 {
3795  wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
3796  return NULL;
3797 }
3798 #endif
3799 #endif
3800 #endif //wxCHECK_VERSION(2, 9, 0)
3801 
3802 wxGraphicsContext* a2dRenderer::CreateContextFromNativeWindow( void* window )
3803 {
3804  wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
3805  return NULL;
3806 }
3807 
3808 wxGraphicsContext* a2dRenderer::CreateMeasuringContext()
3809 {
3810  return NULL;
3811  // TODO
3812 }
3813 
3814 wxGraphicsContext* a2dRenderer::CreateContext( wxWindow* window )
3815 {
3816  wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
3817  return NULL;
3818 }
3819 
3820 // Path
3821 
3822 wxGraphicsPath a2dRenderer::CreatePath()
3823 {
3824  wxGraphicsPath path;
3825  path.SetRefData( new a2dPathData( this ) );
3826  return path;
3827 }
3828 
3829 
3830 // Matrix
3831 
3832 wxGraphicsMatrix a2dRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
3833  wxDouble tx, wxDouble ty )
3834 
3835 {
3836  wxGraphicsMatrix m;
3837  a2dMatrixData* data = new a2dMatrixData( this );
3838  data->Set( a, b, c, d, tx, ty ) ;
3839  m.SetRefData( data );
3840  return m;
3841 }
3842 
3843 wxGraphicsPen a2dRenderer::CreatePen( const wxPen& pen )
3844 {
3845  if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
3846  return wxNullGraphicsPen;
3847  else
3848  {
3849  wxGraphicsPen p;
3850  p.SetRefData( new a2dStrokeData( this, pen ) );
3851  return p;
3852  }
3853 }
3854 
3855 wxGraphicsBrush a2dRenderer::CreateBrush( const wxBrush& brush )
3856 {
3857  if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
3858  return wxNullGraphicsBrush;
3859  else
3860  {
3861  wxGraphicsBrush p;
3862  p.SetRefData( new a2dFillData( this, brush ) );
3863  return p;
3864  }
3865 }
3866 
3867 wxGraphicsPen a2dRenderer::CreateStroke( const a2dStroke& stroke )
3868 {
3869  //if ( stroke.GetStyle() == a2dSTROKE_TRANSPARENT )
3870  // return wxNullGraphicsPen;
3871  //else
3872  {
3873  wxGraphicsPen p;
3874  p.SetRefData( new a2dStrokeData( this, stroke ) );
3875  return p;
3876  }
3877 }
3878 
3879 wxGraphicsBrush a2dRenderer::CreateFill( const a2dFill& fill )
3880 {
3881  //if ( fill.GetStyle() == a2dFILL_TRANSPARENT )
3882  // return wxNullGraphicsBrush;
3883  //else
3884  {
3885  wxGraphicsBrush p;
3886  p.SetRefData( new a2dFillData( this, fill ) );
3887  return p;
3888  }
3889 }
3890 
3891 #if wxCHECK_VERSION(2, 9, 1)
3892 wxGraphicsBrush a2dRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1,
3893  wxDouble x2, wxDouble y2,
3894  const wxGraphicsGradientStops& stops )
3895 {
3896  wxGraphicsBrush p;
3897  a2dFillData* d = new a2dFillData( this );
3898  d->CreateLinearGradientBrush( x1, y1, x2, y2, stops );
3899  p.SetRefData( d );
3900  return p;
3901 }
3902 
3903 wxGraphicsBrush a2dRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo,
3904  wxDouble xc, wxDouble yc,
3905  wxDouble radius,
3906  const wxGraphicsGradientStops& stops )
3907 {
3908  wxGraphicsBrush p;
3909  a2dFillData* d = new a2dFillData( this );
3910  d->CreateRadialGradientBrush( xo, yo, xc, yc, radius, stops );
3911  p.SetRefData( d );
3912  return p;
3913 }
3914 
3915 #else //wxCHECK_VERSION(2, 9, 1)
3916 
3917 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
3918 wxGraphicsBrush a2dRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
3919  const wxColour& c1, const wxColour& c2 )
3920 {
3921  wxGraphicsBrush p;
3922  a2dFillData* d = new a2dFillData( this );
3923  d->CreateLinearGradientBrush( x1, y1, x2, y2, c1, c2 );
3924  p.SetRefData( d );
3925  return p;
3926 }
3927 
3928 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
3929 // with radius r and color cColor
3930 wxGraphicsBrush a2dRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
3931  const wxColour& oColor, const wxColour& cColor )
3932 {
3933  wxGraphicsBrush p;
3934  a2dFillData* d = new a2dFillData( this );
3935  d->CreateRadialGradientBrush( xo, yo, xc, yc, radius, oColor, cColor );
3936  p.SetRefData( d );
3937  return p;
3938 }
3939 #endif //wxCHECK_VERSION(2, 9, 1)
3940 
3941 // sets the font
3942 wxGraphicsFont a2dRenderer::CreateFont( const wxFont& font , const wxColour& col )
3943 {
3944  if ( font.Ok() )
3945  {
3946  wxGraphicsFont p;
3947  p.SetRefData( new a2dFontData( this , font, col ) );
3948  return p;
3949  }
3950  else
3951  return wxNullGraphicsFont;
3952 }
3953 
3954 wxGraphicsFont a2dRenderer::CreateFont( const a2dFont& font )
3955 {
3956  wxGraphicsFont p;
3957  p.SetRefData( new a2dFontData( this, font ) );
3958  return p;
3959 }
3960 
3961 wxGraphicsBitmap a2dRenderer::CreateBitmap( const wxBitmap& bmp )
3962 {
3963  if ( bmp.Ok() )
3964  {
3965  wxGraphicsBitmap p;
3966  p.SetRefData( new a2dBitmapData( this , bmp ) );
3967  return p;
3968  }
3969  else
3970  return wxNullGraphicsBitmap;
3971 }
3972 
3973 #if wxCHECK_VERSION(2, 9, 1)
3974 wxGraphicsBitmap a2dRenderer::CreateBitmapFromNativeBitmap( void* bitmap )
3975 {
3976  wxGraphicsBitmap p;
3977  p.SetRefData( new a2dBitmapData( this , ( const wxBitmap& ) bitmap ) );
3978  return p;
3979 }
3980 #endif //wxCHECK_VERSION(2, 9, 1)
3981 
3982 wxGraphicsBitmap a2dRenderer::CreateBitmap( const wxImage& bmp )
3983 {
3984  if ( bmp.Ok() )
3985  {
3986  wxGraphicsBitmap p;
3987  p.SetRefData( new a2dBitmapData( this , bmp ) );
3988  return p;
3989  }
3990  else
3991  return wxNullGraphicsBitmap;
3992 }
3993 
3994 wxGraphicsBitmap a2dRenderer::CreateSubBitmap( const wxGraphicsBitmap& bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
3995 {
3996  wxGraphicsBitmap p;
3997  p.SetRefData( new a2dBitmapData( this , bitmap ) );
3998  return p;
3999 }
4000 
4001 
4002 #endif // wxART2D_USE_GRAPHICS_CONTEXT
4003 
4004 
wxPoint2DDouble a2dPoint2D
this to define if coordinate numbers are integer or doubles
Definition: artglob.h:47
a2dAffineMatrix & Mirror(bool y=true, bool x=false)
mirror a matrix in x, y
Definition: afmatrix.cpp:396
double GetHeight() const
returns height of the boundingbox
Definition: bbox.cpp:334
Base class for all types of strokes, understood by a2dDrawer2D classes.
Definition: stylebase.h:378
bool IsNoStroke() const
Definition: stylebase.h:510
Quadratic Bezier curve.
Definition: polyver.h:984
double m_x2
control point
Definition: polyver.h:1025
static wxUint16 GetPrimitiveThreshold()
get drawing threshold
Definition: artglob.h:143
const a2dStroke * a2dBLACK_STROKE
global a2dStroke stock object for BLACK stroking
const int SPLINE_STEP
number of steps when converting a spline to lines.
Definition: artglob.h:334
Cubic Bezier curve.
Definition: polyver.h:1045
const a2dFill * a2dBLACK_FILL
global a2dFill stock object for BLACK filling
void CBCurveTo(double x1, double y1, double x2, double y2, double x3, double y3, bool withStroke=true)
add a quadratic bezier segment to the path
Definition: polyver.cpp:3934
double m_y2
control point
Definition: polyver.h:1027
double m_y3
control point 2
Definition: polyver.h:1100
Arc Segment.
Definition: polyver.h:1112
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
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
a2dGlobal * a2dGlobals
global a2dCanvasGlobal to have easy access to global settings
Definition: artglob.cpp:34
Arc Segment in a2dVertexList.
Definition: polyver.h:371
vertex array of line and arc segments.
Definition: polyver.h:494
wxColour GetColour() const
return colour 1
Definition: stylebase.cpp:6131
double m_y2
control point 1
Definition: polyver.h:1095
vertex list of line and arc segments.
Definition: polyver.h:600
double TransformDistance(double distance) const
Transform a distance.
Definition: afmatrix.cpp:616
#define NORMFONT
Normalization font size used for bigger size drawing of text.
Definition: stylebase.h:68
a2dDrawStyle
Define the manner in which a2dCanvasView draws to the device.
Definition: artglob.h:280
void SetWidth(float width)
Set width of stroke in world coordinates.
Definition: stylebase.cpp:6262
bool CalcR(const a2dLineSegment &prev, double &radius, double &center_x, double &center_y, double &beginrad, double &midrad, double &endrad, double &phit) const
Calculation of center for the Arc.
Definition: polyver.cpp:411
void Expand(const a2dPoint2D &, const a2dPoint2D &)
expand boundingbox width two points
Definition: bbox.cpp:155
const a2dBoundingBox & Translate(a2dPoint2D &)
translate with given vector
Definition: bbox.cpp:370
double GetMinX() const
get minimum X of the boundingbox
Definition: bbox.cpp:304
const a2dFont * a2dNullFONT
global a2dFont stock object for NO font
#define wxStaticCast(obj, className)
The wxWindows 2.4.2 wxStaticCast is buggy. It evaluates its argument twice.
Definition: gen.h:123
Normal straight line segment in a2dVertexList and a2dVertexArray.
Definition: polyver.h:163
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
the wxGraphicContext based drawing context
double m_x2
control point 1
Definition: polyver.h:1093
A 2x3 affine matrix class for 2D transformations.
Definition: afmatrix.h:53
double GetMaxX() const
get maximum X of the boundingbox
Definition: bbox.cpp:316
holes one glyph from a freetype font.
Definition: stylebase.h:581
double m_x
x endpoint of line
Definition: polyver.h:232
void MapBbox(const a2dAffineMatrix &matrix)
Definition: bbox.cpp:445
used in freetype rendering
Definition: dcdrawer.cpp:2165
double m_y
y endpoint of line
Definition: polyver.h:235
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
Line calculations.
Definition: liner.h:36
double m_y1
y endpoint of line
Definition: polyver.h:922
double GetMaxY() const
get maximum Y of the boundingbox
Definition: bbox.cpp:322
double GetWidth() const
returns width of the boundingbox
Definition: bbox.cpp:328
bool Scale(double scale)
Scale by scale (isotropic scaling i.e. the same in x and y):
Definition: afmatrix.cpp:270
bool Translate(double x, double y)
Translate by dx, dy:
Definition: afmatrix.cpp:420
const a2dStroke * a2dTRANSPARENT_STROKE
global a2dStroke stock object for TRANSPARENT stroking
The a2dBoundingBox class stores one a2dBoundingBox of a a2dCanvasObject.
Definition: bbox.h:39
bool Invert(void)
Invert matrix.
Definition: afmatrix.cpp:197
double GetMinY() const
get minimum Y of the boundingbox
Definition: bbox.cpp:310
float GetWidth() const
Definition: stylebase.cpp:6281
double m_x1
x endpoint of line
Definition: polyver.h:919
#define Round(x)
round to integer such that e.g 2.5 &lt; x &lt; 3.5 becomes 3
Definition: artglob.h:60
Vector Path.
Definition: polyver.h:1211
A pointer class, that automatically calls SmrtPtrOwn/SmrtPtrRelease.
Definition: a2dlist.h:20
const double wxPI
defines PI
Definition: artglob.cpp:28
const a2dFill * a2dTRANSPARENT_FILL
global a2dFill stock object for TRANSPARENT filling
Used internal for scanned ( gradient etc. ) polygon filling.
Definition: artglob.h:306
graphica.cpp Source File -- Sun Oct 12 2014 17:04:21 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation