00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "a2dprec.h"
00017
00018 #ifdef __BORLANDC__
00019 #pragma hdrstop
00020 #endif
00021
00022 #ifndef WX_PRECOMP
00023 #include "wx/image.h"
00024 #include "wx/window.h"
00025 #include "wx/dc.h"
00026 #include "wx/utils.h"
00027 #include "wx/dialog.h"
00028 #include "wx/app.h"
00029 #include "wx/bitmap.h"
00030 #include "wx/dcmemory.h"
00031 #include "wx/log.h"
00032 #include "wx/icon.h"
00033 #include "wx/dcprint.h"
00034 #include "wx/module.h"
00035 #endif
00036
00037 #include "wx/artbase/graphica.h"
00038
00039 #include "wx/dc.h"
00040
00041 #include "wx/graphics.h"
00042 #include "wx/rawbmp.h"
00043
00044 #if defined(__WXMSW__)
00045 #include "wx/msw/dc.h"
00046 #include <wx/msw/private.h>
00047 #elif __WXGTK__
00048 #include <gtk/gtk.h>
00049 #include <gdk/gdkrgb.h>
00050 #if wxCHECK_VERSION(2,9,0)
00051 #include "wx/gtk/dcclient.h"
00052 #else
00053 #include "wx/gtk/win_gtk.h"
00054 #endif
00055 #endif
00056
00057 #if wxART2D_USE_FREETYPE
00058 #include <ft2build.h>
00059 #ifdef _MSC_VER
00060
00061
00062 #include <freetype/freetype.h>
00063 #include <freetype/ftoutln.h>
00064 #else // _MSC_VER
00065
00066 #include FT_FREETYPE_H
00067 #include FT_OUTLINE_H
00068 #endif // _MSC_VER
00069 #endif
00070
00071 #if wxART2D_USE_GRAPHICS_CONTEXT
00072
00073 #include <vector>
00074
00075 using namespace std;
00076
00077
00078
00079
00080
00081 const double RAD2DEG = 180.0 / M_PI;
00082
00083
00084
00085
00086
00087 static inline double dmin(double a, double b)
00088 {
00089 return a < b ? a : b;
00090 }
00091 static inline double dmax(double a, double b)
00092 {
00093 return a > b ? a : b;
00094 }
00095
00096 static inline double DegToRad(double deg)
00097 {
00098 return (deg * M_PI) / 180.0;
00099 }
00100 static inline double RadToDeg(double deg)
00101 {
00102 return (deg * 180.0) / M_PI;
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112 #ifndef max
00113 #define max(a,b) (((a) > (b)) ? (a) : (b))
00114 #endif
00115
00116 #ifndef min
00117 #define min(a,b) (((a) < (b)) ? (a) : (b))
00118 #endif
00119
00120
00121
00122
00123
00124
00125 a2dStrokeData::~a2dStrokeData()
00126 {
00127 }
00128
00129 void a2dStrokeData::Init()
00130 {
00131 }
00132
00133 a2dStrokeData::a2dStrokeData( wxGraphicsRenderer* renderer, const wxPen &pen )
00134 : wxGraphicsObjectRefData(renderer)
00135 {
00136 Init();
00137 m_stroke = a2dStroke( pen );
00138 }
00139
00140 a2dStrokeData::a2dStrokeData( wxGraphicsRenderer* renderer, const a2dStroke& stroke )
00141 : wxGraphicsObjectRefData(renderer)
00142 {
00143 Init();
00144 m_stroke = stroke;
00145 }
00146
00147 void a2dStrokeData::Apply( wxGraphicsContext* context )
00148 {
00149 a2dContext* ctext = (a2dContext*) context->GetNativeContext();
00150 ctext->SetStroke( m_stroke );
00151 }
00152
00153
00154
00155
00156
00157 a2dFillData::a2dFillData( wxGraphicsRenderer* renderer )
00158 : wxGraphicsObjectRefData( renderer )
00159 {
00160 Init();
00161 }
00162
00163 a2dFillData::a2dFillData( wxGraphicsRenderer* renderer, const wxBrush &brush )
00164 : wxGraphicsObjectRefData(renderer)
00165 {
00166 Init();
00167 m_fill = a2dFill( brush );
00168 }
00169
00170 a2dFillData::a2dFillData( wxGraphicsRenderer* renderer, const a2dFill& fill )
00171 : wxGraphicsObjectRefData(renderer)
00172 {
00173 Init();
00174 m_fill = fill;
00175 }
00176
00177 a2dFillData::~a2dFillData ()
00178 {
00179 }
00180
00181 void a2dFillData::Apply( wxGraphicsContext* context )
00182 {
00183 a2dContext* ctext = (a2dContext*) context->GetNativeContext();
00184 ctext->SetFill( m_fill );
00185 }
00186
00187 #if wxCHECK_VERSION(2, 9, 1)
00188 void a2dFillData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
00189 const wxGraphicsGradientStops& stops )
00190 {
00191
00192 m_fill = a2dFill();
00193 }
00194
00195 void a2dFillData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
00196 const wxGraphicsGradientStops& stops )
00197 {
00198
00199 m_fill = a2dFill();
00200 }
00201 #else
00202 void a2dFillData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
00203 const wxColour&c1, const wxColour&c2 )
00204 {
00205
00206 m_fill = a2dFill();
00207 }
00208
00209 void a2dFillData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
00210 const wxColour &oColor, const wxColour &cColor )
00211 {
00212
00213 m_fill = a2dFill();
00214 }
00215 #endif
00216
00217
00218 void a2dFillData::Init()
00219 {
00220 }
00221
00222
00223
00224
00225
00226 a2dFontData::a2dFontData( wxGraphicsRenderer* renderer, const wxFont &font,
00227 const wxColour& col ) : wxGraphicsObjectRefData(renderer)
00228 {
00229 m_font = a2dFont( font, font.GetPointSize() );
00230 }
00231
00232 a2dFontData::a2dFontData( wxGraphicsRenderer* renderer, const a2dFont &font )
00233 : wxGraphicsObjectRefData(renderer)
00234 {
00235 m_font = font;
00236 }
00237
00238 a2dFontData::~a2dFontData()
00239 {
00240 }
00241
00242 void a2dFontData::Apply( wxGraphicsContext* context )
00243 {
00244 a2dContext* ctext = (a2dContext*) context->GetNativeContext();
00245 ctext->SetFont( m_font );
00246 }
00247
00248
00249
00250
00251
00252 a2dPathData::a2dPathData( wxGraphicsRenderer* renderer, a2dVpath* path )
00253 : wxGraphicsPathData(renderer)
00254 {
00255 if ( path )
00256 m_path = *path;
00257 else
00258 m_path = a2dVpath();
00259
00260 }
00261
00262 a2dPathData::~a2dPathData()
00263 {
00264 }
00265
00266 wxGraphicsObjectRefData *a2dPathData::Clone() const
00267 {
00268 a2dVpath* p = new a2dVpath( m_path );
00269 return new a2dPathData( GetRenderer() , p );
00270 }
00271
00272
00273 void* a2dPathData::GetNativePath() const
00274 {
00275 return (void*) &m_path;
00276 }
00277
00278 void a2dPathData::UnGetNativePath(void *p) const
00279 {
00280 }
00281
00282
00283
00284
00285
00286 void a2dPathData::MoveToPoint( wxDouble x , wxDouble y )
00287 {
00288 m_path.MoveTo(x,y);
00289 }
00290
00291 void a2dPathData::AddLineToPoint( wxDouble x , wxDouble y )
00292 {
00293 m_path.LineTo(x,y);
00294 }
00295
00296 void a2dPathData::AddPath( const wxGraphicsPathData* path )
00297 {
00298 a2dVpath* p = (a2dVpath*)path->GetNativePath();
00299 m_path = *p;
00300 }
00301
00302 void a2dPathData::CloseSubpath()
00303 {
00304 m_path.Last().SetClose( a2dPATHSEG_END_CLOSED );
00305 }
00306
00307 void a2dPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
00308 {
00309 m_path.CBCurveTo(cx1,cy1,cx2,cy2,x,y);
00310 }
00311
00312
00313 void a2dPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
00314 {
00315 double dx,dy;
00316 a2dVpathSegment seg = m_path.Last();
00317 dx = seg.m_x1;
00318 dy = seg.m_y1;
00319 if (x)
00320 *x = dx;
00321 if (y)
00322 *y = dy;
00323 }
00324
00325 void a2dPathData::AddArc( wxDouble xc, wxDouble yc, wxDouble radius, double startAngle, double endAngle, bool clockwise )
00326 {
00327 if ( (endAngle-startAngle) >= 2*M_PI )
00328 {
00329 double x1 = xc + radius;
00330 double y1 = yc;
00331 double x2 = xc + radius;
00332 double y2 = yc;
00333 double xm = xc - radius;
00334 double ym = yc;
00335 m_path.ArcTo( xc, yc, x2 , y2, xm, ym );
00336 }
00337 else if ( clockwise || (endAngle-startAngle)>=2*M_PI)
00338 {
00339 double x1 = xc + radius * cos( startAngle );
00340 double y1 = yc + radius * sin( startAngle );
00341 double x2 = xc + radius * cos( endAngle );
00342 double y2 = yc + radius * sin( endAngle );
00343
00344
00345
00346 double er;
00347
00348
00349 er = endAngle - startAngle;
00350
00351 if ( er<=0 ) er += 2.0*M_PI;
00352 if ( er>=2.0*M_PI ) er -= 2.0*M_PI;
00353
00354 double midrad;
00355 midrad = er/2.0 + startAngle;
00356
00357 double xm = xc + radius * cos( midrad );
00358 double ym = yc + radius * sin( midrad );
00359
00360
00361 m_path.ArcTo( xc, yc, x2 , y2, xm, ym );
00362 }
00363 else
00364 {
00365 double x1 = xc + radius * cos( startAngle );
00366 double y1 = yc + radius * sin( startAngle );
00367 double x2 = xc + radius * cos( endAngle );
00368 double y2 = yc + radius * sin( endAngle );
00369
00370
00371
00372 double er;
00373
00374
00375 er = endAngle - startAngle;
00376
00377 if ( er<=0 ) er += 2.0*M_PI;
00378 if ( er>=2.0*M_PI ) er -= 2.0*M_PI;
00379
00380 double midrad;
00381 midrad = ( 2.0*M_PI - er/2.0 );
00382
00383 double xm = xc + radius * cos( midrad );
00384 double ym = yc + radius * sin( midrad );
00385
00386
00387 m_path.ArcTo( xc, yc, x2 , y2, xm, ym );
00388 }
00389 }
00390
00391
00392 void a2dPathData::Transform( const wxGraphicsMatrixData* matrix )
00393 {
00394
00395
00396 a2dAffineMatrix m = *((a2dAffineMatrix*) matrix->GetNativeMatrix());
00397 m_path.Transform( m );
00398 }
00399
00400
00401 void a2dPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
00402 {
00403 double x1,y1,x2,y2;
00404
00405
00406 x1 = 0;
00407 y1 = 0;
00408 x2 = 1000;
00409 y2 = 1000;
00410
00411 if ( x2 < x1 )
00412 {
00413 *x = x2;
00414 *w = x1-x2;
00415 }
00416 else
00417 {
00418 *x = x1;
00419 *w = x2-x1;
00420 }
00421
00422 if( y2 < y1 )
00423 {
00424 *y = y2;
00425 *h = y1-y2;
00426 }
00427 else
00428 {
00429 *y = y1;
00430 *h = y2-y1;
00431 }
00432 }
00433
00434 bool a2dPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle ) const
00435 {
00436 return false;
00437 }
00438
00439
00440
00441
00442
00443 a2dMatrixData::a2dMatrixData(wxGraphicsRenderer* renderer, const a2dAffineMatrix* matrix )
00444 : wxGraphicsMatrixData(renderer)
00445 {
00446 if ( matrix )
00447 m_matrix = *matrix;
00448 }
00449
00450 a2dMatrixData::~a2dMatrixData()
00451 {
00452
00453 }
00454
00455 wxGraphicsObjectRefData *a2dMatrixData::Clone() const
00456 {
00457 return new a2dMatrixData(GetRenderer(),&m_matrix);
00458 }
00459
00460
00461 void a2dMatrixData::Concat( const wxGraphicsMatrixData *t )
00462 {
00463 m_matrix *= *((a2dAffineMatrix*) t->GetNativeMatrix());
00464 }
00465
00466
00467 void a2dMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
00468 wxDouble tx, wxDouble ty)
00469 {
00470 m_matrix = a2dAffineMatrix( a, b, c, d, tx, ty );
00471 }
00472
00473
00474 void a2dMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c,
00475 wxDouble* d, wxDouble* tx, wxDouble* ty) const
00476 {
00477 if (a) *a = m_matrix(0,0);
00478 if (b) *b = m_matrix(0,1);
00479 if (c) *c = m_matrix(1,0);
00480 if (d) *d = m_matrix(1,1);
00481 if (tx) *tx= m_matrix(2,0);
00482 if (ty) *ty= m_matrix(2,1);
00483 }
00484
00485
00486 void a2dMatrixData::Invert()
00487 {
00488 m_matrix.Invert();
00489 }
00490
00491
00492 bool a2dMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
00493 {
00494 return m_matrix == *((a2dAffineMatrix*) t->GetNativeMatrix());
00495 }
00496
00497
00498 bool a2dMatrixData::IsIdentity() const
00499 {
00500 return m_matrix.IsIdentity();
00501 }
00502
00503
00504
00505
00506
00507
00508 void a2dMatrixData::Translate( wxDouble dx , wxDouble dy )
00509 {
00510 m_matrix.Translate( dx, dy) ;
00511 }
00512
00513
00514 void a2dMatrixData::Scale( wxDouble xScale , wxDouble yScale )
00515 {
00516 m_matrix.Scale( xScale, yScale, m_matrix(2,0), m_matrix(2,0) ) ;
00517 }
00518
00519
00520 void a2dMatrixData::Rotate( wxDouble angle )
00521 {
00522 m_matrix.Rotate( angle ) ;
00523 }
00524
00525
00526
00527
00528
00529
00530 void a2dMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
00531 {
00532 double lx = *x, ly = *y ;
00533 m_matrix.TransformPoint(lx, ly);
00534 *x = lx;
00535 *y = ly;
00536 }
00537
00538
00539 void a2dMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
00540 {
00541 double lx = *dx, ly = *dy ;
00542
00543 m_matrix.TransformDistance( lx, ly);
00544 *dx = lx;
00545 *dy = ly;
00546 }
00547
00548
00549 void * a2dMatrixData::GetNativeMatrix() const
00550 {
00551 return (void*) &m_matrix;
00552 }
00553
00554
00555
00556
00557
00558 a2dBitmapData::a2dBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ) : wxGraphicsObjectRefData( renderer )
00559 {
00560 wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in a2dBitmapData"));
00561
00562 m_width = bmp.GetWidth();
00563 m_height = bmp.GetHeight();
00564 m_image = bmp.ConvertToImage();
00565 }
00566
00567 a2dBitmapData::a2dBitmapData( wxGraphicsRenderer* renderer, const wxImage& image ) : wxGraphicsObjectRefData( renderer )
00568 {
00569 wxCHECK_RET( image.IsOk(), wxT("Invalid image in a2dBitmapData"));
00570
00571 m_width = image.GetWidth();
00572 m_height = image.GetHeight();
00573 m_image = image;
00574 }
00575
00576 a2dBitmapData::a2dBitmapData( wxGraphicsRenderer* renderer, const wxGraphicsBitmap& a2dbitmap ) : wxGraphicsObjectRefData( renderer )
00577 {
00578 a2dBitmapData* data = (a2dBitmapData*) a2dbitmap.GetRefData();
00579
00580 m_width = data->GetSize().GetWidth();
00581 m_height = data->GetSize().GetHeight();
00582 m_image = data->GetImage();
00583 }
00584
00585 a2dBitmapData::~a2dBitmapData()
00586 {
00587 }
00588
00589
00590
00591
00592
00593 a2dContext::a2dContext( wxGraphicsRenderer* renderer, a2dContext* context )
00594 :
00595 m_width( context->m_width ),
00596 m_height( context->m_height ),
00597 m_drawstyle( a2dFILLED ),
00598 wxGraphicsContext(renderer)
00599 {
00600 Init();
00601 }
00602
00603 a2dContext::a2dContext( wxGraphicsRenderer* renderer, int width, int height )
00604 :
00605 m_width( width ),
00606 m_height( height ),
00607 m_drawstyle( a2dFILLED ),
00608 wxGraphicsContext(renderer)
00609 {
00610 Init();
00611 }
00612
00613 a2dContext::a2dContext( wxGraphicsRenderer* renderer )
00614 :
00615 m_width( 0 ),
00616 m_height( 0 ),
00617 m_drawstyle( a2dFILLED ),
00618 wxGraphicsContext(renderer)
00619 {
00620 Init();
00621 }
00622
00623 void a2dContext::Init()
00624 {
00625 m_activestroke = *a2dBLACK_STROKE;
00626 m_activefill = *a2dBLACK_FILL;
00627 m_a2dfont = *a2dNullFONT;
00628 m_OpacityFactor = 255;
00629 m_displayaberration = 0.5;
00630 m_yaxis = false;
00631 m_drawingthreshold = a2dGlobals->GetPrimitiveThreshold();
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652 a2dContext::~a2dContext()
00653 {
00654 PopState();
00655 PopState();
00656 }
00657
00658 void a2dContext::SetYaxis( bool up )
00659 {
00660 m_yaxis = up;
00661 }
00662
00663 void a2dContext::SetPen( const wxGraphicsPen& pen )
00664 {
00665 wxGraphicsContext::SetPen( pen );
00666
00667 if ( !pen.IsNull() )
00668 ((a2dStrokeData*)pen.GetRefData())->Apply(this);
00669 else
00670 SetStroke( *a2dTRANSPARENT_STROKE );
00671 }
00672
00673 void a2dContext::SetBrush( const wxGraphicsBrush& brush )
00674 {
00675 wxGraphicsContext::SetBrush( brush );
00676
00677 if ( !brush.IsNull() )
00678 ((a2dFillData*)brush.GetRefData())->Apply(this);
00679 else
00680 SetFill( *a2dTRANSPARENT_FILL );
00681 }
00682
00683 void a2dContext::SetFont( const wxGraphicsFont& font )
00684 {
00685 wxGraphicsContext::SetFont( font );
00686 ((a2dFontData*) font.GetRefData())->Apply(this);
00687 }
00688
00689 void a2dContext::SetStroke( const a2dStroke& stroke )
00690 {
00691 switch( m_drawstyle )
00692 {
00693 case a2dWIREFRAME_INVERT:
00694 case a2dWIREFRAME:
00695 case a2dWIREFRAME_ZERO_WIDTH:
00696 m_activestroke = stroke;
00697 break;
00698 case a2dWIREFRAME_INVERT_ZERO_WIDTH:
00699 m_activestroke = *a2dBLACK_STROKE;
00700 break;
00701 case a2dFILLED:
00702 m_activestroke = stroke;
00703 break;
00704 case a2dFIX_STYLE:
00705 break;
00706 case a2dFIX_STYLE_INVERT:
00707 break;
00708 default:
00709 wxASSERT( 0 );
00710 }
00711
00712 m_colour1redStroke = m_activestroke.GetColour().Red();
00713 m_colour1greenStroke = m_activestroke.GetColour().Green();
00714 m_colour1blueStroke = m_activestroke.GetColour().Blue();
00715
00716 if ( m_activestroke.IsNoStroke() || m_activestroke.GetStyle() == a2dSTROKE_TRANSPARENT )
00717 {
00718 m_StrokeOpacityCol1 = 0;
00719 m_StrokeOpacityCol2 = 0;
00720 }
00721 else
00722 {
00723 m_StrokeOpacityCol1 = m_activestroke.GetColour().Alpha() * m_OpacityFactor / 255 ;
00724 m_StrokeOpacityCol2 = m_activestroke.GetColour().Alpha() * m_OpacityFactor / 255 ;
00725 }
00726 DoSetActiveStroke();
00727 }
00728
00729 void a2dContext::SetFill( const a2dFill& fill )
00730 {
00731 switch( m_drawstyle )
00732 {
00733 case a2dWIREFRAME_INVERT:
00734 case a2dWIREFRAME:
00735 case a2dWIREFRAME_ZERO_WIDTH:
00736 case a2dWIREFRAME_INVERT_ZERO_WIDTH:
00737 m_activefill = *a2dTRANSPARENT_FILL;
00738 break;
00739 case a2dFILLED:
00740 m_activefill = fill;
00741 break;
00742 case a2dFIX_STYLE:
00743 case a2dFIX_STYLE_INVERT:
00744 break;
00745 default:
00746 wxASSERT( 0 );
00747 }
00748
00749 m_colour1redFill = m_activefill.GetColour().Red();
00750 m_colour1greenFill = m_activefill.GetColour().Green();
00751 m_colour1blueFill = m_activefill.GetColour().Blue();
00752 m_colour2redFill = m_activefill.GetColour2().Red();
00753 m_colour2greenFill = m_activefill.GetColour2().Green();
00754 m_colour2blueFill = m_activefill.GetColour2().Blue();
00755
00756 if ( !m_activefill.GetFilling() )
00757 {
00758 m_FillOpacityCol1 = 0;
00759 m_FillOpacityCol2 = 0;
00760 }
00761 else if ( m_activefill.GetStyle() == a2dFILL_TRANSPARENT )
00762 {
00763 m_FillOpacityCol1 = 0;
00764 m_FillOpacityCol2 = 0;
00765 }
00766 else if ( m_activefill.IsNoFill() )
00767 {
00768 m_FillOpacityCol1 = 0;
00769 m_FillOpacityCol2 = 0;
00770 }
00771 else
00772 {
00773 m_FillOpacityCol1 = m_activefill.GetColour().Alpha() * m_OpacityFactor / 255;
00774 m_FillOpacityCol2 = m_activefill.GetColour2().Alpha() * m_OpacityFactor / 255;
00775 }
00776
00777 DoSetActiveFill();
00778 }
00779
00780 void a2dContext::SetFont( const a2dFont& font )
00781 {
00782 m_a2dfont = font;
00783 }
00784
00785 void a2dContext::Clip( const wxRegion& region )
00786 {
00787
00788 wxGraphicsPath path = GetRenderer()->CreatePath();
00789 wxRegionIterator ri(region);
00790 while (ri)
00791 {
00792 path.AddRectangle(ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH());
00793 ri++;
00794 }
00795
00796
00797 }
00798
00799 void a2dContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
00800 {
00801
00802
00803 wxPoint trpoints[4];
00804 double dx,dy;
00805
00806 m_usertodevice.TransformPoint( x, y, dx, dy );
00807 trpoints[0] = wxPoint( dx, dy );
00808 m_usertodevice.TransformPoint( x, y + h, dx, dy );
00809 trpoints[1] = wxPoint( dx, dy );
00810 m_usertodevice.TransformPoint( x + w, y + h, dx, dy );
00811 trpoints[2] = wxPoint( dx, dy);
00812 m_usertodevice.TransformPoint( x + w, y, dx, dy );
00813 trpoints[3] = wxPoint( dx, dy );
00814
00815 double xmin = trpoints[0].x;
00816 double ymin = trpoints[0].y;
00817 double xmax = trpoints[0].x;
00818 double ymax = trpoints[0].y;
00819 for ( int i = 1; i < 4; i ++ )
00820 {
00821 xmin = wxMin( xmin, trpoints[i].x );
00822 xmax = wxMax( xmin, trpoints[i].x );
00823 ymin = wxMin( ymin, trpoints[i].y );
00824 ymax = wxMax( ymin, trpoints[i].y );
00825 }
00826 wxRect cliprect = wxRect( xmin, ymin, xmax-xmin, ymax-ymin );
00827 m_clipboxdev = cliprect;
00828 }
00829
00830 void a2dContext::ResetClip()
00831 {
00832 m_clipboxdev = wxRect( 0, 0, m_width, m_height );
00833 }
00834
00835 void a2dContext::DrawPath( const wxGraphicsPath& path, wxPolygonFillMode fillStyle )
00836 {
00837 if ( !m_pen.IsNull() || !m_brush.IsNull() )
00838 {
00839 a2dVpath* cp = (a2dVpath*) path.GetNativePath() ;
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850 DrawVpath( cp );
00851 }
00852 }
00853
00854 void a2dContext::StrokePath( const wxGraphicsPath& path )
00855 {
00856 if ( !m_pen.IsNull() )
00857 {
00858 a2dVpath* cp = (a2dVpath*) path.GetNativePath() ;
00859
00860
00861 a2dFill curfill = m_activefill;
00862 SetFill( *a2dTRANSPARENT_FILL );
00863 DrawVpath( cp );
00864 SetFill( curfill );
00865 }
00866 }
00867
00868 void a2dContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fillStyle )
00869 {
00870 if ( !m_brush.IsNull() )
00871 {
00872 a2dVpath* cp = (a2dVpath*) path.GetNativePath() ;
00873
00874
00875 a2dStroke curstroke = m_activestroke;
00876 m_activestroke = *a2dTRANSPARENT_STROKE;
00877 DrawVpath( cp );
00878 m_activestroke = curstroke;
00879 }
00880 }
00881
00882 void a2dContext::Rotate( wxDouble angle )
00883 {
00884 m_usertodevice.Rotate( angle ) ;
00885 }
00886
00887 void a2dContext::Translate( wxDouble dx , wxDouble dy )
00888 {
00889 m_usertodevice.Translate( dx, dy) ;
00890 }
00891
00892 void a2dContext::Scale( wxDouble xScale , wxDouble yScale )
00893 {
00894 m_usertodevice.Scale( xScale, yScale, 0, 0 ) ;
00895 }
00896
00897
00898 void a2dContext::ConcatTransform( const wxGraphicsMatrix& matrix )
00899 {
00900 a2dAffineMatrix* m = (a2dAffineMatrix*) matrix.GetNativeMatrix();
00901 m_usertodevice *= *m;
00902 }
00903
00904
00905 void a2dContext::SetTransform( const wxGraphicsMatrix& matrix )
00906 {
00907 a2dAffineMatrix* m = (a2dAffineMatrix*) matrix.GetNativeMatrix();
00908 m_usertodevice = *m;
00909 }
00910
00911
00912 wxGraphicsMatrix a2dContext::GetTransform() const
00913 {
00914 wxGraphicsMatrix matrix = CreateMatrix();
00915 a2dAffineMatrix* m = (a2dAffineMatrix*) matrix.GetNativeMatrix();
00916 *m = m_usertodevice;
00917 return matrix;
00918 }
00919
00920 void a2dContext::PushState()
00921 {
00922 }
00923
00924 void a2dContext::PopState()
00925 {
00926 }
00927
00928 #if wxCHECK_VERSION(2,9,0)
00929 void a2dContext::DrawBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h)
00930 #else
00931 void a2dContext::DrawGraphicsBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h)
00932 #endif
00933 {
00934 a2dBitmapData* data = static_cast<a2dBitmapData*>(bmp.GetRefData());
00935 wxImage image = data->GetImage();
00936 }
00937
00938 void a2dContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
00939 {
00940 wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap(bmp);
00941 #if wxCHECK_VERSION(2,9,0)
00942 DrawBitmap(bitmap, x, y, w, h);
00943 #else
00944 DrawGraphicsBitmap(bitmap, x, y, w, h);
00945 #endif
00946 }
00947
00948 void a2dContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
00949 {
00950
00951 }
00952
00953 #if wxCHECK_VERSION(2,9,0)
00954 void a2dContext::DoDrawText( const wxString &str, wxDouble x, wxDouble y )
00955 #else
00956 void a2dContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
00957 #endif
00958 {
00959 if ( str.empty())
00960 return;
00961
00962
00963
00964
00965
00966 a2dBoundingBox bbox = m_a2dfont.GetTextExtent( str, m_yaxis, wxLEFT | wxBOTTOM | wxBBOX, false );
00967 bbox.Translate( x, y );
00968
00969
00970
00971 x = bbox.GetMinX();
00972 y = bbox.GetMinY();
00973
00974
00975 double dx, dy, size;
00976 dx = m_usertodevice.GetValue( 1, 0 );
00977 dy = m_usertodevice.GetValue( 1, 1 );
00978 size = m_a2dfont.GetSize() * sqrt( dx * dx + dy * dy );
00979
00980
00981 a2dBoundingBox worldbbox( bbox );
00982 worldbbox.MapBbox( m_usertodevice );
00983 wxRect devb = wxRect( worldbbox.GetMinX(), worldbbox.GetMinY(), worldbbox.GetWidth(), worldbbox.GetHeight() );
00984
00985
00986 if ( m_clipboxdev.Intersects( devb ) )
00987 {
00988
00989
00990
00991
00992 if ( size > m_drawingthreshold )
00993 {
00994
00995 switch (m_a2dfont.GetType())
00996 {
00997 case a2dFONT_STROKED:
00998 DrawTextStroke( str, x, y );
00999 break;
01000 case a2dFONT_FREETYPE:
01001 DrawTextFreetype( str, x, y );
01002 break;
01003 case a2dFONT_WXDC:
01004 DrawTextDc( str, x, y );
01005 break;
01006 default:
01007 DrawTextUnknown( str, x, y );
01008 }
01009 }
01010
01011 else
01012 DrawTextUnknown( str, x, y, true );
01013 }
01014 }
01015
01016
01017 void a2dContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
01018 wxDouble *descent, wxDouble *externalLeading ) const
01019 {
01020 if ( str.empty())
01021 return;
01022
01023 if (width)
01024 {
01025 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
01026 }
01027
01028 if (height || descent || externalLeading)
01029 {
01030 }
01031 }
01032
01033 void a2dContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
01034 {
01035 widths.Empty();
01036 widths.Add(0, text.length());
01037
01038 if (text.empty())
01039 return;
01040
01041
01042 }
01043
01044 void * a2dContext::GetNativeContext()
01045 {
01046 return this;
01047 }
01048
01049
01050
01051
01052 int a2dContext::ToDeviceLines( a2dVertexArray* points, a2dBoundingBox& devbbox, bool& smallPoly, bool replaceByRectangle )
01053 {
01054 unsigned int segments = 0;
01055
01056 unsigned int i;
01057 for ( i = 0; i < points->size(); i++ )
01058 {
01059 const a2dLineSegmentPtr seg = points->operator[](i);
01060
01061 if ( seg->GetArc() )
01062 {
01063 const a2dArcSegment* cseg = ( const a2dArcSegment* ) (seg.Get());
01064
01065 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01066
01067 if ( cseg->CalcR( *(points->operator[]( i ? i - 1 : 0 )), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01068 {
01069 double dphi;
01070 unsigned int circlesegments;
01071 double radiusDev = m_usertodevice.TransformDistance( radius );
01072 Aberration( m_displayaberration, phit, radiusDev , dphi, circlesegments );
01073 segments += circlesegments + 1;
01074 }
01075 else
01076 segments ++;
01077 }
01078 else
01079 segments++;
01080 }
01081
01082
01083 m_cpointsDouble.resize( segments * 2 );
01084
01085 unsigned int count = 0;
01086 double x, y, lastx, lasty;
01087 for ( i = 0; i < points->size(); i++ )
01088 {
01089 const a2dLineSegmentPtr seg = points->operator[](i);
01090
01091 if ( !seg->GetArc() )
01092 {
01093 m_usertodevice.TransformPoint( seg->m_x, seg->m_y, x, y );
01094
01095
01096 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01097 {
01098 m_cpointsDouble[count].x = x;
01099 m_cpointsDouble[count].y = y;
01100 lastx = x;
01101 lasty = y;
01102 devbbox.Expand( x, y );
01103 count++;
01104 }
01105 }
01106 else
01107 {
01108 const a2dArcSegment* cseg = ( const a2dArcSegment* ) (seg.Get());
01109
01110 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01111
01112 if ( cseg->CalcR( *(points->operator[]( i ? i - 1 : 0 )), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01113 {
01114 double dphi;
01115 unsigned int segments;
01116 double radiusDev = m_usertodevice.TransformDistance( radius );
01117 Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
01118
01119 double theta = beginrad;
01120 unsigned int step;
01121
01122 double x, y;
01123 for ( step = 0; step < segments + 1; step++ )
01124 {
01125 m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
01126
01127
01128 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01129 {
01130 m_cpointsDouble[count].x = x;
01131 m_cpointsDouble[count].y = y;
01132 lastx = x;
01133 lasty = y;
01134 devbbox.Expand( x, y );
01135 count++;
01136 }
01137 theta = theta + dphi;
01138 }
01139 }
01140 else
01141 {
01142 double x, y;
01143 m_usertodevice.TransformPoint( cseg->m_x, cseg->m_y, x, y );
01144
01145
01146 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01147 {
01148 m_cpointsDouble[count].x = x;
01149 m_cpointsDouble[count].y = y;
01150 lastx = x;
01151 lasty = y;
01152 devbbox.Expand( x, y );
01153 count++;
01154 }
01155 }
01156 }
01157 }
01158
01159 return count;
01160 }
01161
01162 int a2dContext::ToDeviceLines( const a2dVertexList *list, a2dBoundingBox& devbbox, bool& smallPoly, bool replaceByRectangle )
01163 {
01164 unsigned int segments = 0;
01165
01166 if ( list->empty() )
01167 return 0;
01168
01169 a2dVertexList::const_iterator iterprev = list->end();
01170 if ( iterprev != list->begin() )
01171 iterprev--;
01172 a2dVertexList::const_iterator iter = list->begin();
01173 while ( iter != list->end() )
01174 {
01175 a2dLineSegment * seg = ( *iter );
01176
01177 if ( seg->GetArc() )
01178 {
01179 a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
01180
01181 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01182
01183 if ( cseg->CalcR( *( *iterprev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01184 {
01185 double dphi;
01186 unsigned int circlesegments;
01187 double radiusDev = m_usertodevice.TransformDistance( radius );
01188 Aberration( m_displayaberration, phit, radiusDev , dphi, circlesegments );
01189 segments += circlesegments + 1;
01190 }
01191 else
01192 segments ++;
01193 }
01194 else
01195 segments++;
01196
01197 iterprev = iter++;
01198 }
01199
01200
01201 m_cpointsDouble.resize( segments * 2 );
01202
01203 unsigned int count = 0;
01204 double x, y, lastx, lasty;
01205 iterprev = list->end();
01206 if ( iterprev != list->begin() )
01207 iterprev--;
01208 iter = list->begin();
01209 while ( iter != list->end() )
01210 {
01211 a2dLineSegment * seg = ( *iter );
01212
01213 if ( !seg->GetArc() )
01214 {
01215 m_usertodevice.TransformPoint( seg->m_x, seg->m_y, x, y );
01216
01217
01218 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01219 {
01220 m_cpointsDouble[count].x = x;
01221 m_cpointsDouble[count].y = y;
01222 lastx = x;
01223 lasty = y;
01224 devbbox.Expand( x, y );
01225 count++;
01226 }
01227 }
01228 else
01229 {
01230 a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
01231
01232 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01233
01234 if ( cseg->CalcR( *( *iterprev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01235 {
01236 double dphi;
01237 unsigned int segments;
01238 double radiusDev = m_usertodevice.TransformDistance( radius );
01239 Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
01240
01241 double theta = beginrad;
01242 unsigned int step;
01243
01244 double x, y;
01245 for ( step = 0; step < segments + 1; step++ )
01246 {
01247 m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
01248
01249
01250 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01251 {
01252 m_cpointsDouble[count].x = x;
01253 m_cpointsDouble[count].y = y;
01254 lastx = x;
01255 lasty = y;
01256 devbbox.Expand( x, y );
01257 count++;
01258 }
01259 theta = theta + dphi;
01260 }
01261 }
01262 else
01263 {
01264 double x, y;
01265 m_usertodevice.TransformPoint( cseg->m_x, cseg->m_y, x, y );
01266
01267
01268 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01269 {
01270 m_cpointsDouble[count].x = x;
01271 m_cpointsDouble[count].y = y;
01272 lastx = x;
01273 lasty = y;
01274 devbbox.Expand( x, y );
01275 count++;
01276 }
01277 }
01278 }
01279 iterprev = iter++;
01280 }
01281
01282 return count;
01283 }
01284
01285
01286 void a2dContext::DrawVpath( const a2dVpath* path )
01287 {
01288 double tstep = 1 / ( double ) SPLINE_STEP;
01289 unsigned int i;
01290
01291 a2dVertexList points;
01292 bool move = false;
01293 int count = 0;
01294 bool nostrokeparts = false;
01295
01296
01297 for ( i = 0; i < path->size(); i++ )
01298 {
01299 a2dVpathSegment& seg = path->Item( i );
01300 switch ( seg.GetType() )
01301 {
01302 case a2dPATHSEG_MOVETO:
01303 if ( count == 0 )
01304 {
01305 points.push_back( new a2dLineSegment( seg.m_x1, seg.m_y1 ) );
01306 count++;
01307 }
01308 else
01309 {
01310 i--;
01311 move = true;
01312 }
01313 break;
01314
01315 case a2dPATHSEG_LINETO:
01316 points.push_back( new a2dLineSegment( seg.m_x1, seg.m_y1 ) );
01317 count++;
01318 break;
01319 case a2dPATHSEG_LINETO_NOSTROKE:
01320 points.push_back( new a2dLineSegment( seg.m_x1, seg.m_y1 ) );
01321 count++;
01322 nostrokeparts = true;
01323 break;
01324
01325 case a2dPATHSEG_CBCURVETO_NOSTROKE:
01326 nostrokeparts = true;
01327 case a2dPATHSEG_CBCURVETO:
01328 {
01329 double xw, yw;
01330
01331 double xwl = path->Item( i ? i - 1 : 0 ).m_x1;
01332 double ywl = path->Item( i ? i - 1 : 0 ).m_y1;
01333 a2dVpathCBCurveSegment& cseg = ( a2dVpathCBCurveSegment& ) seg;
01334
01335 int step;
01336 double t = 0;
01337 for ( step = 0; step <= SPLINE_STEP; step++ )
01338 {
01339 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 );
01340 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 );
01341 points.push_back( new a2dLineSegment( xw, yw ) );
01342 count++;
01343 t = t + tstep;
01344 }
01345 }
01346 break;
01347
01348 case a2dPATHSEG_QBCURVETO_NOSTROKE:
01349 nostrokeparts = true;
01350 case a2dPATHSEG_QBCURVETO:
01351 {
01352 double xw, yw;
01353
01354 double xwl = path->Item( i ? i - 1 : 0 ).m_x1;
01355 double ywl = path->Item( i ? i - 1 : 0 ).m_y1;
01356 a2dVpathQBCurveSegment& cseg = ( a2dVpathQBCurveSegment& ) seg;
01357
01358 int step;
01359 double t = 0;
01360 for ( step = 0; step <= SPLINE_STEP; step++ )
01361 {
01362 xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
01363 yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
01364 points.push_back( new a2dLineSegment( xw, yw ) );
01365 count++;
01366 t = t + tstep;
01367 }
01368 }
01369 break;
01370
01371 case a2dPATHSEG_ARCTO_NOSTROKE:
01372 nostrokeparts = true;
01373 case a2dPATHSEG_ARCTO:
01374 {
01375 a2dVpathArcSegment& cseg = ( a2dVpathArcSegment& ) seg;
01376
01377 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01378
01379 if ( cseg.CalcR( path->Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01380 {
01381 double dphi;
01382 unsigned int segments;
01383 double radiusDev = m_usertodevice.TransformDistance( radius );
01384 Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
01385
01386 double theta = beginrad;
01387 unsigned int step;
01388
01389 for ( step = 0; step < segments + 1; step++ )
01390 {
01391 points.push_back( new a2dLineSegment( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ) ) );
01392 count++;
01393 theta = theta + dphi;
01394 }
01395 }
01396 else
01397 {
01398 points.push_back( new a2dLineSegment( cseg.m_x1, cseg.m_y1 ) );
01399 count++;
01400 }
01401 }
01402 default:
01403 break;
01404 break;
01405 }
01406
01407 if ( move )
01408 {
01409 DrawLines( &points );
01410 move = false;
01411 count = 0;
01412 points.clear();
01413 }
01414 else if ( seg.GetClose() != a2dPATHSEG_END_OPEN )
01415 {
01416 if ( nostrokeparts || seg.GetClose() == a2dPATHSEG_END_CLOSED_NOSTROKE )
01417 {
01418 a2dStroke stroke = m_activestroke;
01419 m_activestroke = *a2dTRANSPARENT_STROKE;
01420 DrawPolygon( &points, wxODDEVEN_RULE );
01421 m_activestroke = stroke;
01422 nostrokeparts = true;
01423 }
01424 else
01425 {
01426 DrawPolygon( &points, wxODDEVEN_RULE );
01427 }
01428
01429 move = false;
01430 count = 0;
01431 points.clear();
01432 }
01433 else if ( i == path->size() - 1 )
01434 {
01435 DrawLines( &points );
01436 }
01437 }
01438
01439 if ( nostrokeparts )
01440 {
01441 points.clear();
01442 move = false;
01443 count = 0;
01444 nostrokeparts = false;
01445
01446 double lastmovex = 0;
01447 double lastmovey = 0;
01448
01449 for ( i = 0; i < path->size(); i++ )
01450 {
01451 a2dVpathSegment& seg = path->Item( i );
01452 switch ( seg.GetType() )
01453 {
01454 case a2dPATHSEG_MOVETO:
01455 if ( count == 0 )
01456 {
01457 points.push_back( new a2dLineSegment( seg.m_x1, seg.m_y1 ) );
01458 lastmovex = seg.m_x1;
01459 lastmovey = seg.m_y1;
01460 count++;
01461 }
01462 else
01463 {
01464 i--;
01465 move = true;
01466 }
01467 break;
01468
01469 case a2dPATHSEG_LINETO:
01470 points.push_back( new a2dLineSegment( seg.m_x1, seg.m_y1 ) );
01471 count++;
01472 break;
01473
01474 case a2dPATHSEG_LINETO_NOSTROKE:
01475 case a2dPATHSEG_CBCURVETO_NOSTROKE:
01476 case a2dPATHSEG_QBCURVETO_NOSTROKE:
01477 case a2dPATHSEG_ARCTO_NOSTROKE:
01478 if ( count == 0 )
01479 {
01480 points.push_back( new a2dLineSegment( seg.m_x1, seg.m_y1 ) );
01481 count++;
01482 }
01483 else
01484 {
01485 i--;
01486 nostrokeparts = true;
01487 }
01488 break;
01489
01490 case a2dPATHSEG_CBCURVETO:
01491 {
01492 double xw, yw;
01493
01494 double xwl = path->Item( i ? i - 1 : 0 ).m_x1;
01495 double ywl = path->Item( i ? i - 1 : 0 ).m_y1;
01496 a2dVpathCBCurveSegment& cseg = ( a2dVpathCBCurveSegment& ) seg;
01497
01498 int step;
01499 double t = 0;
01500 for ( step = 0; step <= SPLINE_STEP; step++ )
01501 {
01502 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 );
01503 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 );
01504 points.push_back( new a2dLineSegment( xw, yw ) );
01505 count++;
01506 t = t + tstep;
01507 }
01508 }
01509 break;
01510
01511 case a2dPATHSEG_QBCURVETO:
01512 {
01513 double xw, yw;
01514
01515 double xwl = path->Item( i ? i - 1 : 0 ).m_x1;
01516 double ywl = path->Item( i ? i - 1 : 0 ).m_y1;
01517 a2dVpathQBCurveSegment& cseg = ( a2dVpathQBCurveSegment& ) seg;
01518
01519 int step;
01520 double t = 0;
01521 for ( step = 0; step <= SPLINE_STEP; step++ )
01522 {
01523 xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
01524 yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
01525 points.push_back( new a2dLineSegment( xw, yw ) );
01526 count++;
01527 t = t + tstep;
01528 }
01529 }
01530 break;
01531
01532 case a2dPATHSEG_ARCTO:
01533 {
01534 a2dVpathArcSegment& cseg = ( a2dVpathArcSegment& ) seg;
01535
01536 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01537
01538 if ( cseg.CalcR( path->Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01539 {
01540 double dphi;
01541 unsigned int segments;
01542 double radiusDev = m_usertodevice.TransformDistance( radius );
01543 Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
01544
01545 double theta = beginrad;
01546 unsigned int step;
01547
01548 for ( step = 0; step < segments + 1; step++ )
01549 {
01550 points.push_back( new a2dLineSegment( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ) ) );
01551 count++;
01552 theta = theta + dphi;
01553 }
01554 }
01555 else
01556 {
01557 points.push_back( new a2dLineSegment( cseg.m_x1, cseg.m_y1 ) );
01558 count++;
01559 }
01560 }
01561 default:
01562 break;
01563
01564 break;
01565 }
01566
01567 if ( move || nostrokeparts )
01568 {
01569 DrawLines( &points );
01570 move = false;
01571 nostrokeparts = false;
01572 points.clear();
01573 count = 0;
01574 }
01575 else if ( seg.GetClose() != a2dPATHSEG_END_OPEN )
01576 {
01577 if ( seg.GetClose() == a2dPATHSEG_END_CLOSED )
01578 {
01579 points.push_back( new a2dLineSegment( lastmovex, lastmovey ) );
01580 count++;
01581 }
01582 DrawLines( &points );
01583 nostrokeparts = false;
01584 move = false;
01585 points.clear();
01586 count = 0;
01587 }
01588 else if ( i == path->size() )
01589 {
01590 DrawLines( &points );
01591 }
01592 }
01593 }
01594
01595 }
01596
01597 void a2dContext::DrawCharUnknown( wxChar c )
01598 {
01599 a2dStroke oldstroke = m_activestroke;
01600
01601 a2dStroke stroke = a2dStroke( m_activestroke.GetColour(), m_a2dfont.GetSize() / 20.0 );
01602 m_activestroke = stroke;
01603
01604 if ( c != wxChar( ' ' ) )
01605 {
01606 double desc = m_a2dfont.GetDescent();
01607 double size = m_a2dfont.GetSize();
01608 double width = m_a2dfont.GetWidth( c );
01609 DrawLine( 0.1 * width, desc, 0.9 * width, desc + size );
01610 DrawLine( 0.9 * width, desc, 0.1 * width, desc + size );
01611 }
01612
01613
01614 m_activestroke = oldstroke;
01615 }
01616
01617 void a2dContext::DrawTextUnknown( const wxString& text, double x, double y, bool words )
01618 {
01619 if ( words && m_a2dfont.Ok() )
01620 {
01621 a2dStroke oldstroke = m_activestroke;
01622
01623 a2dBoundingBox linebbox = m_a2dfont.GetTextExtent( text, m_yaxis );
01624
01625 if ( !m_activefill.IsNoFill() && !m_activefill.GetStyle() == a2dFILL_TRANSPARENT )
01626 {
01627 m_activestroke = *a2dTRANSPARENT_STROKE;
01628 DrawRoundedRectangle( x + linebbox.GetMinX(), y + linebbox.GetMinY(),
01629 linebbox.GetWidth(), linebbox.GetHeight(), 0 );
01630 m_activestroke = oldstroke;
01631 }
01632
01633
01634 a2dStroke strokew = a2dStroke( m_activestroke.GetColour(), 1 );
01635 m_activestroke = strokew;
01636
01637 double h = linebbox.GetHeight();
01638 double w;
01639 wxChar c;
01640 double start = x;
01641 for ( size_t i = 0; i < text.Length(); i++ )
01642 {
01643 c = text[i];
01644 w = m_a2dfont.GetWidth( c );
01645 if ( c == wxChar( ' ' ) )
01646 {
01647 if ( x != start )
01648 DrawLine( start, y + h / 2, x, y + h / 2 );
01649 start = x + w;
01650 }
01651 x += w;
01652 }
01653 if ( x != start )
01654 DrawLine( start, y + h / 2, x, y + h / 2 );
01655
01656
01657 m_activestroke = oldstroke;
01658 }
01659 else
01660 {
01661 a2dBoundingBox linebbox = m_a2dfont.GetTextExtent( text, m_yaxis );
01662
01663 DrawRoundedRectangle( x + linebbox.GetMinX(), y + linebbox.GetMinY(),
01664 linebbox.GetWidth(), linebbox.GetHeight(), 0 );
01665 DrawLine( x + linebbox.GetMinX(), y + linebbox.GetMinY(), x + linebbox.GetMaxX(), y + linebbox.GetMaxY() );
01666 DrawLine( x + linebbox.GetMinX(), y + linebbox.GetMaxY(), x + linebbox.GetMaxX(), y + linebbox.GetMinY() );
01667 }
01668 }
01669
01670
01671 void a2dContext::DrawCharStroke( wxChar c )
01672 {
01673 a2dStroke strokeold = m_activestroke;
01674
01675
01676 a2dStroke stroke = a2dStroke( m_activestroke.GetColour(), 0.0 );
01677 stroke.SetWidth( m_a2dfont.GetStrokeWidth() );
01678 m_activestroke = stroke;
01679
01680 a2dAffineMatrix affineold = m_usertodevice;
01681
01682
01683 a2dAffineMatrix affine;
01684 affine.Scale( m_a2dfont.GetSize() );
01685 m_usertodevice = affine;
01686
01687 a2dVertexList** ptr = m_a2dfont.GetGlyphStroke( c );
01688 if ( ptr )
01689 {
01690 while ( *ptr )
01691 {
01692 DrawLines( *ptr );
01693 ptr++;
01694 }
01695 }
01696
01697 m_usertodevice = affineold;
01698 m_activestroke = strokeold;
01699 }
01700
01701 void a2dContext::DrawTextGeneric( const wxString& text, double x, double y, void ( a2dContext::*drawchar )( wxChar ) )
01702 {
01703
01704 const double h = m_a2dfont.GetLineHeight();
01705 a2dAffineMatrix affine;
01706 if ( !GetYaxis() )
01707 {
01708 affine.Translate( 0.0, -h );
01709 affine.Mirror( true, false );
01710 }
01711
01712 affine.Translate( x, y );
01713
01714 a2dAffineMatrix affineold = m_usertodevice;
01715 a2dAffineMatrix textm = affine;
01716
01717 m_usertodevice = m_usertodevice;
01718
01719 bool textwasvisible = false;
01720
01721 double w = 0.0;
01722 wxChar c = 0;
01723 const size_t n = text.Length();
01724 for ( size_t i = 0; i < n; i++ )
01725 {
01726 const wxChar oldc = c;
01727 c = text[i];
01728 if ( i > 0 )
01729 {
01730 textm *= a2dAffineMatrix( w + m_a2dfont.GetKerning( oldc, c ), 0.0 );
01731 }
01732 m_usertodevice = affineold * textm;
01733
01734 w = m_a2dfont.GetWidth( c );
01735
01736
01737 a2dBoundingBox bbox( 0.0, 0.0, w, h );
01738 bbox.MapBbox( m_usertodevice );
01739 wxRect devb = wxRect( bbox.GetMinX(), bbox.GetMinY(), bbox.GetWidth(), bbox.GetHeight() );
01740
01741
01742 if ( m_clipboxdev.Intersects( devb ) )
01743 {
01744 ( this->*drawchar )( c );
01745 textwasvisible = true;
01746 }
01747 else if ( textwasvisible )
01748 {
01749
01750
01751 break;
01752 }
01753 }
01754
01755
01756 m_usertodevice = affineold;
01757 }
01758
01759
01760
01761
01762
01763 bool a2dContext::MoveUp( int n, wxRealPoint points[] , double horline, int& index, int direction )
01764 {
01765 int walk = ( index + direction + n ) % n;
01766 while ( points[walk].y < horline )
01767 {
01768 if ( points[walk].y < points[index].y )
01769 return false;
01770 else
01771 {
01772
01773 index = walk;
01774 walk = ( index + direction + n ) % n;
01775 }
01776 }
01777 return true;
01778 }
01779
01780
01781
01782 void a2dContext::DetectCriticalPoints( int n, wxRealPoint points[] )
01783 {
01784
01785
01786
01787 bool candidate = false;
01788 int i, j;
01789
01790 for ( i = 0; i < n; i++ )
01791 {
01792
01793 j = ( i + 1 ) % n;
01794
01795
01796 if ( points[i].y > points[j].y )
01797
01798 candidate = true;
01799 else if ( ( points[i].y < points[j].y ) && candidate )
01800 {
01801 bool inserted = false;
01802 a2dCriticalPointList::compatibility_iterator node = m_CRlist.GetFirst();
01803 while ( node )
01804 {
01805
01806 int * ind = node->GetData();
01807 if ( points[*ind].y > points[i].y )
01808 {
01809 m_CRlist.Insert( node, new int( i ) );
01810 inserted = true;
01811 break;
01812 }
01813 node = node->GetNext();
01814 }
01815 if ( !inserted )
01816 m_CRlist.Append( new int( i ) );
01817 candidate = false;
01818 }
01819 }
01820 if ( candidate )
01821 {
01822 for ( i = 0; i < n; i++ )
01823 {
01824
01825 j = ( i + 1 ) % n;
01826
01827
01828 if ( points[i].y > points[j].y )
01829
01830 candidate = true;
01831 else if ( ( points[i].y < points[j].y ) && candidate )
01832 {
01833 bool inserted = false;
01834 a2dCriticalPointList::compatibility_iterator node = m_CRlist.GetFirst();
01835 while ( node )
01836 {
01837
01838 int * ind = node->GetData();
01839 if ( points[*ind].y > points[i].y )
01840 {
01841 m_CRlist.Insert( node, new int( i ) );
01842 inserted = true;
01843 break;
01844 }
01845 node = node->GetNext();
01846 }
01847 if ( !inserted )
01848 m_CRlist.Append( new int( i ) );
01849 candidate = false;
01850 }
01851 }
01852 }
01853 }
01854
01855
01856 static int SortonXs( const a2dAET** first, const a2dAET** second )
01857 {
01858 if ( ( *first )->m_xs < ( *second )->m_xs )
01859 return -1;
01860 else if ( ( *first )->m_xs > ( *second )->m_xs )
01861 return 1;
01862
01863 return 0;
01864 }
01865
01866 void a2dContext::ColourXYLinear( int x1, int x2, int y )
01867 {
01868 int dred = m_colour2redFill - m_colour1redFill;
01869 int dgreen = m_colour2greenFill - m_colour1greenFill;
01870 int dblue = m_colour2blueFill - m_colour1blueFill;
01871
01872 if ( m_dx1 == m_dx2 )
01873 {
01874
01875
01876 double stepcol = m_max_y - m_min_y;
01877
01878 double curcol = y - m_min_y;
01879
01880 a2dStroke current = m_activestroke;
01881 wxColour gradcol( ( unsigned char ) (m_colour1redFill + dred * curcol / stepcol),
01882 ( unsigned char ) (m_colour1greenFill + dgreen * curcol / stepcol),
01883 ( unsigned char ) (m_colour1blueFill + dblue * curcol / stepcol) );
01884 a2dStroke gradientstroke = a2dStroke( gradcol, 0 );
01885 m_activestroke = gradientstroke;
01886 DeviceDrawHorizontalLine( x1, y, x2, true );
01887 m_activestroke = current;
01888 }
01889 else
01890 {
01891 int j;
01892 for ( j = x1; j <= x2; j++ )
01893 {
01894 a2dLine perstroke( j, y, j + m_dy2 - m_dy1, y + m_dx2 - m_dx1 );
01895 a2dPoint2D crossing;
01896 perstroke.CalculateLineParameters();
01897 perstroke.Intersect( m_line, crossing );
01898
01899 double length = sqrt( ( double ) ( crossing.m_x - m_dx1 ) * ( crossing.m_x - m_dx1 ) + ( crossing.m_y - m_dy1 ) * ( crossing.m_y - m_dy1 ) );
01900
01901 if ( length > m_length )
01902 length = m_length;
01903
01904 DeviceDrawPixel( j, y, m_colour1redFill + dred * int( length / m_length ),
01905 m_colour1greenFill + dgreen * int( length / m_length ),
01906 m_colour1blueFill + dblue * int( length / m_length ) );
01907 }
01908 }
01909 }
01910
01911 void a2dContext::ColourXYRadial( int x1, int x2, int y )
01912 {
01913 int dred = m_colour2redFill - m_colour1redFill;
01914 int dgreen = m_colour2greenFill - m_colour1greenFill;
01915 int dblue = m_colour2blueFill - m_colour1blueFill;
01916
01917 int j;
01918 for ( j = x1; j <= x2; j++ )
01919 {
01920 double cradius = sqrt( ( double ) ( j - m_dx1 ) * ( j - m_dx1 ) + ( y - m_dy1 ) * ( y - m_dy1 ) );
01921
01922 double delta;
01923 if ( m_radiusd == 0 )
01924 delta = 0;
01925 else if ( cradius > m_radiusd )
01926 delta = 1;
01927 else
01928 delta = cradius / m_radiusd;
01929
01930 DeviceDrawPixel( j, y, ( unsigned char ) ( m_colour1redFill + dred * delta ),
01931 ( unsigned char ) ( m_colour1greenFill + dgreen * delta ),
01932 ( unsigned char ) ( m_colour1blueFill + dblue * delta ) );
01933 }
01934 }
01935
01936 void a2dContext::FillPolygon( int n, wxRealPoint points[] )
01937 {
01938 wxRect clip;
01939 clip.x = m_clipboxdev.x;
01940 clip.y = m_clipboxdev.y;
01941 clip.width = m_clipboxdev.width;
01942 clip.height = m_clipboxdev.height;
01943
01944 m_min_y = points[0].y;
01945 m_max_y = points[0].y;
01946 m_min_x = points[0].x;
01947 m_max_x = points[0].x;
01948 double centroidx = 0;
01949 double centroidy = 0;
01950 int i;
01951 for ( i = 0; i < n; i++ )
01952 {
01953 m_min_y = wxMin( m_min_y, points[i].y );
01954 m_max_y = wxMax( m_max_y, points[i].y );
01955 m_min_x = wxMin( m_min_x, points[i].x );
01956 m_max_x = wxMax( m_max_x, points[i].x );
01957 centroidx += points[i].x;
01958 centroidy += points[i].y;
01959 }
01960
01961 centroidx /= double( n );
01962 centroidy /= double( n );
01963
01964 int index;
01965
01966 if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
01967 {
01968 double x1 = m_activefill.GetStart().m_x;
01969 double y1 = m_activefill.GetStart().m_y;
01970 double x2 = m_activefill.GetStop().m_x;
01971 double y2 = m_activefill.GetStop().m_y;
01972 m_usertodevice.TransformPoint( x1, y1, m_dx1, m_dy1 );
01973 m_usertodevice.TransformPoint( x2, y2, m_dx2, m_dy2 );
01974 if ( m_dx1 == m_dx2 && m_dy1 == m_dy2 )
01975 {
01976 m_dx1 = centroidx;
01977 m_dy1 = m_min_y;
01978 m_dx2 = centroidx;
01979 m_dy2 = m_max_y;
01980 if ( m_dx1 == m_dx2 && m_dy1 == m_dy2 )
01981 m_dx2 = m_dx2 + 100;
01982 }
01983 m_length = sqrt ( ( m_dx1 - m_dx2 ) * ( m_dx1 - m_dx2 ) + ( m_dy1 - m_dy2 ) * ( m_dy1 - m_dy2 ) );
01984 m_line = a2dLine( m_dx1, m_dy1, m_dx2, m_dy2 );
01985 m_line.CalculateLineParameters();
01986 }
01987 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
01988 {
01989 double xfc = m_activefill.GetFocal().m_x;
01990 double yfc = m_activefill.GetFocal().m_y;
01991 double xe = m_activefill.GetCenter().m_x;
01992 double ye = m_activefill.GetCenter().m_y;
01993 m_usertodevice.TransformPoint( xfc, yfc, m_dx1, m_dy1 );
01994 m_usertodevice.TransformPoint( xe, ye, m_dx2, m_dy2 );
01995 if ( m_dx1 == m_dx2 && m_dy1 == m_dy2 )
01996 {
01997 m_dx1 = centroidx;
01998 m_dy1 = centroidy;
01999 m_dx2 = centroidx;
02000 m_dy2 = m_max_y;
02001
02002 if ( m_dx1 == m_dx2 && m_dy1 == m_dy2 )
02003 m_dx2 = m_dx2 + 10;
02004 }
02005 double dx3, dy3;
02006 m_usertodevice.TransformPoint( xe, ye + m_activefill.GetRadius(), dx3, dy3 );
02007 m_radiusd = sqrt ( ( dx3 - m_dx2 ) * ( dx3 - m_dx2 ) + ( dy3 - m_dy2 ) * ( dy3 - m_dy2 ) );
02008 }
02009
02010 DetectCriticalPoints( n, points );
02011
02012 int min = ( int ) wxMax ( m_min_y, clip.y );
02013 int max = ( int ) wxMin ( m_max_y, clip.y + clip.height );
02014
02015 for ( i = min; i < max; i++ )
02016 {
02017 a2dAETList::compatibility_iterator node = m_AETlist.GetFirst();
02018 int count = m_AETlist.size();
02019 while ( count > 0 )
02020 {
02021 a2dAET * ele = node->GetData();
02022 index = ele->m_index;
02023 int direction = ele->m_direction;
02024 if ( !MoveUp( n, points, i, index, direction ) )
02025 {
02026 a2dAETList::compatibility_iterator h = node;
02027
02028 node = node->GetNext();
02029 delete h->GetData();
02030 m_AETlist.DeleteNode( h );
02031 }
02032 else
02033 {
02034 if ( ele->m_index != index )
02035 {
02036 ele->m_index = index;
02037 int h = ( index + direction + n ) % n;
02038 ele->CalculateLineParameters( points[h], points[index] );
02039 }
02040 if ( ele->m_horizontal )
02041 ele->m_xs = ( int ) points[index].x;
02042 else
02043 ele->CalculateXs( i );
02044 node = node->GetNext();
02045 }
02046 count--;
02047 }
02048
02049 a2dCriticalPointList::compatibility_iterator nodec = m_CRlist.GetFirst();
02050 while ( m_CRlist.size() && points[*nodec->GetData()].y <= i )
02051 {
02052 int DI;
02053 for ( DI = -1; DI <= 1 ; DI += 2 )
02054 {
02055 index = *nodec->GetData();
02056 if ( MoveUp( n, points, i, index, DI ) )
02057 {
02058 a2dAET * ele = new a2dAET();
02059 ele->m_index = index;
02060 ele->m_direction = DI;
02061 int h = ( index + DI + n ) % n;
02062 ele->CalculateLineParameters( points[h], points[index] );
02063 if ( ele->m_horizontal )
02064 ele->m_xs = ( int ) points[index].x;
02065 else
02066 ele->CalculateXs( i );
02067
02068
02069 bool inserted = false;
02070 node = m_AETlist.GetFirst();
02071 while ( node )
02072 {
02073
02074 if ( ele->m_xs < ( node->GetData() )->m_xs )
02075 {
02076 m_AETlist.Insert( node, ele );
02077 inserted = true;
02078 break;
02079 }
02080
02081 node = node->GetNext();
02082 }
02083 if ( !inserted )
02084 m_AETlist.Append( ele );
02085 }
02086 }
02087
02088 a2dCriticalPointList::compatibility_iterator h = nodec;
02089 nodec = nodec->GetNext();
02090 delete h->GetData();
02091 m_CRlist.DeleteNode( h );
02092 }
02093
02094
02095
02096 if ( m_AETlist.GetCount() > 1 )
02097 {
02098 if ( m_AETlist.GetCount() > 2 )
02099 m_AETlist.Sort( SortonXs );
02100 else if ( m_AETlist.GetFirst()->GetData()->m_xs > m_AETlist.GetLast()->GetData()->m_xs )
02101 {
02102 a2dAET * f = m_AETlist.GetFirst()->GetData();
02103 m_AETlist.GetFirst()->SetData( m_AETlist.GetLast()->GetData() );
02104 m_AETlist.GetLast()->SetData( f );
02105 }
02106 }
02107
02108
02109
02110 int out = 0;
02111 node = m_AETlist.GetFirst();
02112 while ( node )
02113 {
02114 a2dAET * ele = node->GetData();
02115 out += ele->m_direction;
02116
02117 if ( out != 0 )
02118 {
02119 int x1 = ( int ) ele->m_xs;
02120 node = node->GetNext();
02121 if ( node )
02122 {
02123 ele = node->GetData();
02124 int x2 = ( int ) ele->m_xs;
02125
02126 if ( x1 < clip.x ) x1 = clip.x;
02127 if ( x2 > clip.x + clip.width ) x2 = clip.x + clip.width;
02128 if ( i >= clip.y && i <= clip.y + clip.height && ( x1 != x2 ) )
02129 {
02130 if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
02131 ColourXYLinear( x1, x2, i );
02132 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
02133 ColourXYRadial( x1, x2, i );
02134 else
02135 DeviceDrawHorizontalLine( x1, i, x2, false );
02136 }
02137 }
02138
02139 }
02140 else
02141 node = node->GetNext();
02142 }
02143 }
02144
02145 a2dAETList::compatibility_iterator node = m_AETlist.GetFirst();
02146 while ( node )
02147 {
02148 a2dAETList::compatibility_iterator h = node;
02149 delete h->GetData();
02150 m_AETlist.DeleteNode( h );
02151 node = m_AETlist.GetFirst();
02152 }
02153
02154 a2dCriticalPointList::compatibility_iterator nodec = m_CRlist.GetFirst();
02155 while ( nodec )
02156 {
02157 a2dCriticalPointList::compatibility_iterator h = nodec;
02158 delete h->GetData();
02159 m_CRlist.DeleteNode( h );
02160 nodec = m_CRlist.GetFirst();
02161 }
02162
02163 }
02164
02165 void a2dContext::DrawPolygon( const a2dVertexList *list, wxPolygonFillMode fillStyle )
02166 {
02167 a2dBoundingBox devbox;
02168 bool smallPoly = false;
02169 int segments = ToDeviceLines( list, devbox, smallPoly );
02170
02171 if ( segments == 0 )
02172 return;
02173
02174 DeviceDrawPolygon( segments, false, fillStyle );
02175 }
02176
02177 void a2dContext::DrawLines( const a2dVertexList* list )
02178 {
02179 a2dBoundingBox devbox;
02180 bool smallPoly = false;
02181 int segments = ToDeviceLines( list, devbox, smallPoly );
02182
02183 if ( segments > 0 )
02184 DeviceDrawLines( segments, false );
02185 }
02186
02187 void a2dContext::DrawLine( double x1, double y1, double x2, double y2 )
02188 {
02189 a2dVertexList points;
02190 points.push_back( new a2dLineSegment( x1, y1 ) );
02191 points.push_back( new a2dLineSegment( x2, y2 ) );
02192 DrawLines( &points );
02193 }
02194
02195 void a2dContext::DeviceDrawPolygon( unsigned int n, bool spline , wxPolygonFillMode fillStyle )
02196 {
02197 wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
02198 }
02199
02200 void a2dContext::DeviceDrawLines( unsigned int n, bool spline )
02201 {
02202 wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
02203 }
02204
02205 void a2dContext::DeviceDrawLine( double x1, double y1, double x2, double y2 )
02206 {
02207 wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
02208 }
02209
02210 void a2dContext::DeviceDrawHorizontalLine( int x1, int y1, int x2, bool WXUNUSED( use_pen ) )
02211 {
02212 wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
02213 }
02214
02215 void a2dContext::DeviceDrawVerticalLine( int x1, int y1, int y2, bool WXUNUSED( use_pen ) )
02216 {
02217 wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
02218 }
02219
02220 void a2dContext::DeviceDrawPixel( int x1, int y1, unsigned char r, unsigned char g, unsigned char b, unsigned char a )
02221 {
02222 wxFAIL_MSG( wxT( "if used, must be implemented in derived class" ) );
02223 }
02224
02225 wxPoint *a2dContext::_convertToIntPointCache( int n, wxRealPoint *pts )
02226 {
02227 m_cpointsInt.resize( n );
02228
02229 for ( int i = 0; i < n; i++ )
02230 {
02231 m_cpointsInt[i].x = Round( pts[i].x );
02232 m_cpointsInt[i].y = Round( pts[i].y );
02233 }
02234 return &m_cpointsInt[0];
02235 }
02236
02237
02238
02239
02240
02241
02242
02243
02244 a2dDcContext::a2dDcContext( wxGraphicsRenderer* renderer, wxMemoryDC* dc, wxBitmap* drawable )
02245 :
02246 a2dContext(renderer, dc->GetSize().GetWidth(), dc->GetSize().GetHeight() )
02247 {
02248 m_buffer = drawable;
02249 m_renderDC = dc;
02250 }
02251
02252 a2dDcContext::a2dDcContext( wxGraphicsRenderer* renderer, wxBitmap* drawable )
02253 :
02254 a2dContext(renderer, drawable->GetWidth(), drawable->GetHeight() )
02255 {
02256 m_buffer = drawable;
02257 m_renderDC = new wxMemoryDC( *drawable );
02258 }
02259
02260 a2dDcContext::~a2dDcContext()
02261 {
02262 }
02263
02264 void a2dDcContext::DoSetActiveStroke()
02265 {
02266 if ( m_renderDC )
02267 {
02268 if ( m_activestroke.GetStyle() == a2dSTROKE_TRANSPARENT )
02269 {
02270 m_renderDC->SetPen( *wxTRANSPARENT_PEN );
02271 }
02272 else if ( m_activestroke.IsNoStroke() )
02273 {
02274 m_renderDC->SetPen( *wxTRANSPARENT_PEN );
02275
02276
02277 }
02278 else if ( m_drawstyle == a2dWIREFRAME_INVERT_ZERO_WIDTH )
02279 {
02280 m_renderDC->SetPen( *wxBLACK_PEN );
02281 }
02282 else if ( m_activestroke.GetType() == a2dSTROKE_ONE_COLOUR )
02283 {
02284 int style;
02285 switch( m_activestroke.GetStyle() )
02286 {
02287 case a2dSTROKE_SOLID: style = wxSOLID;
02288 break;
02289 case a2dSTROKE_TRANSPARENT: style = wxTRANSPARENT;
02290 break;
02291 case a2dSTROKE_DOT: style = wxDOT;
02292 break;
02293 case a2dSTROKE_DOT_DASH: style = wxDOT_DASH;
02294 break;
02295 case a2dSTROKE_LONG_DASH: style = wxLONG_DASH;
02296 break;
02297 case a2dSTROKE_SHORT_DASH: style = wxSHORT_DASH;
02298 break;
02299 case a2dSTROKE_BDIAGONAL_HATCH: style = wxBDIAGONAL_HATCH;
02300 break;
02301 case a2dSTROKE_CROSSDIAG_HATCH: style = wxCROSSDIAG_HATCH;
02302 break;
02303 case a2dSTROKE_FDIAGONAL_HATCH: style = wxFDIAGONAL_HATCH;
02304 break;
02305 case a2dSTROKE_CROSS_HATCH: style = wxCROSS_HATCH;
02306 break;
02307 case a2dSTROKE_HORIZONTAL_HATCH: style = wxHORIZONTAL_HATCH;
02308 break;
02309 case a2dSTROKE_VERTICAL_HATCH: style = wxVERTICAL_HATCH;
02310 break;
02311 case a2dSTROKE_STIPPLE: style = wxSTIPPLE;
02312 break;
02313 case a2dSTROKE_STIPPLE_MASK_OPAQUE: style = wxSTIPPLE_MASK_OPAQUE;
02314 break;
02315 default: style = a2dSTROKE_SOLID;
02316 }
02317
02318 if ( m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
02319 {
02320 wxPen dcpen( m_activestroke.GetColour(), 0, style );
02321 m_renderDC->SetPen( dcpen );
02322 m_renderDC->SetTextForeground( m_activestroke.GetColour() );
02323 }
02324 else
02325 {
02326 wxPen dcpen( m_activestroke.GetColour(), ( int ) m_activestroke.GetWidth(), style );
02327 dcpen.SetJoin( m_activestroke.GetJoin() );
02328 dcpen.SetCap( m_activestroke.GetCap() );
02329 if ( !m_activestroke.GetPixelStroke() )
02330 {
02331 double w = m_usertodevice.TransformDistance( m_activestroke.GetWidth() );
02332 dcpen.SetWidth( ( int ) w );
02333 }
02334 m_renderDC->SetPen( dcpen );
02335 m_renderDC->SetTextForeground( m_activestroke.GetColour() );
02336 }
02337
02338 }
02339 else if ( m_activestroke.GetType() == a2dSTROKE_BITMAP )
02340 {
02341 wxPen dcpen;
02342
02343 if ( m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
02344 dcpen = wxPen( m_activestroke.GetColour(), 0, wxBRUSHSTYLE_SOLID );
02345 else
02346 {
02347 int width = (int) m_activestroke.GetWidth();
02348 if ( !m_activestroke.GetPixelStroke() )
02349 {
02350 a2dAffineMatrix inverted = m_usertodevice;
02351 inverted.Invert();
02352 width = inverted.TransformDistance( m_activestroke.GetWidth() );
02353 }
02354 dcpen = wxPen( m_activestroke.GetColour(), width, wxBRUSHSTYLE_SOLID );
02355 dcpen.SetJoin( m_activestroke.GetJoin() );
02356 dcpen.SetCap( m_activestroke.GetCap() );
02357 }
02358
02359 #if defined(__WXMSW__)
02360 wxBrushStyle style;
02361 switch( m_activestroke.GetStyle() )
02362 {
02363 case a2dSTROKE_STIPPLE:
02364 style = wxBRUSHSTYLE_STIPPLE;
02365 dcpen.SetStyle( style );
02366 dcpen.SetStipple( m_activestroke.GetStipple() );
02367 break;
02368 case a2dSTROKE_STIPPLE_MASK_OPAQUE_TRANSPARENT:
02369 case a2dSTROKE_STIPPLE_MASK_OPAQUE:
02370 if ( 0 )
02371 {
02372 wxBitmap noMask = m_activestroke.GetStipple();
02373 noMask.SetMask( NULL );
02374 style = wxBRUSHSTYLE_STIPPLE;
02375 dcpen.SetStyle( style );
02376 dcpen.SetStipple( noMask );
02377 }
02378 else
02379 {
02380 style = wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE;
02381 dcpen.SetStyle( style );
02382 dcpen.SetStipple( m_activestroke.GetStipple() );
02383 }
02384 break;
02385 default: style = wxBRUSHSTYLE_SOLID;
02386 dcpen.SetStyle( style );
02387 }
02388 #endif
02389
02390 m_renderDC->SetPen( dcpen );
02391 m_renderDC->SetTextBackground( *wxBLACK );
02392 m_renderDC->SetTextForeground( m_activestroke.GetColour() );
02393 }
02394
02395 }
02396 }
02397
02398 void a2dDcContext::DoSetActiveFill()
02399 {
02400 if ( m_renderDC )
02401 {
02402 if ( !m_activefill.GetFilling() )
02403 {
02404 m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
02405 m_renderDC->SetTextBackground( *wxBLACK );
02406 }
02407 else if ( m_activefill.GetStyle() == a2dFILL_TRANSPARENT )
02408 {
02409 m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
02410 m_renderDC->SetTextBackground( *wxBLACK );
02411 }
02412 else if ( m_activefill.IsNoFill() )
02413 {
02414 m_renderDC->SetBrush( *wxTRANSPARENT_BRUSH );
02415
02416 m_renderDC->SetTextBackground( *wxBLACK );
02417 }
02418 else if ( m_activefill.GetType() == a2dFILL_ONE_COLOUR )
02419 {
02420 wxBrush dcbrush;
02421 wxBrushStyle style;
02422 switch( m_activefill.GetStyle() )
02423 {
02424 case a2dFILL_TRANSPARENT:
02425 style = wxBRUSHSTYLE_TRANSPARENT;
02426 dcbrush.SetColour( m_activefill.GetColour() );
02427 dcbrush.SetStyle( style );
02428 break;
02429 case a2dFILL_SOLID: style = wxBRUSHSTYLE_SOLID;
02430 dcbrush.SetColour( m_activefill.GetColour() );
02431 dcbrush.SetStyle( style );
02432 break;
02433 case a2dFILL_BDIAGONAL_HATCH:
02434 style = wxBRUSHSTYLE_BDIAGONAL_HATCH;
02435 dcbrush.SetColour( m_activefill.GetColour() );
02436 dcbrush.SetStyle( style );
02437 break;
02438 case a2dFILL_CROSSDIAG_HATCH:
02439 style = wxBRUSHSTYLE_CROSSDIAG_HATCH;
02440 dcbrush.SetColour( m_activefill.GetColour() );
02441 dcbrush.SetStyle( style );
02442 break;
02443 case a2dFILL_FDIAGONAL_HATCH:
02444 style = wxBRUSHSTYLE_FDIAGONAL_HATCH;
02445 dcbrush.SetColour( m_activefill.GetColour() );
02446 dcbrush.SetStyle( style );
02447 break;
02448 case a2dFILL_CROSS_HATCH:
02449 style = wxBRUSHSTYLE_CROSS_HATCH;
02450 dcbrush.SetColour( m_activefill.GetColour() );
02451 dcbrush.SetStyle( style );
02452 break;
02453 case a2dFILL_HORIZONTAL_HATCH:
02454 style = wxBRUSHSTYLE_HORIZONTAL_HATCH;
02455 dcbrush.SetColour( m_activefill.GetColour() );
02456 dcbrush.SetStyle( style );
02457 break;
02458 case a2dFILL_VERTICAL_HATCH:
02459 style = wxBRUSHSTYLE_VERTICAL_HATCH;
02460 dcbrush.SetColour( m_activefill.GetColour() );
02461 dcbrush.SetStyle( style );
02462 break;
02463 default: style = wxBRUSHSTYLE_SOLID;
02464 dcbrush.SetColour( m_activefill.GetColour() );
02465 dcbrush.SetStyle( style );
02466 }
02467
02468 m_renderDC->SetBrush( dcbrush );
02469 m_renderDC->SetTextBackground( m_activefill.GetColour() );
02470 }
02471 else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
02472 {
02473 wxBrush dcbrush;
02474 wxBrushStyle style;
02475 switch( m_activefill.GetStyle() )
02476 {
02477 case a2dFILL_TRANSPARENT:
02478 style = wxBRUSHSTYLE_TRANSPARENT;
02479 dcbrush.SetColour( m_activefill.GetColour() );
02480 dcbrush.SetStyle( style );
02481 break;
02482 case a2dFILL_TWOCOL_BDIAGONAL_HATCH:
02483 style = wxBRUSHSTYLE_BDIAGONAL_HATCH;
02484 dcbrush.SetColour( m_activefill.GetColour() );
02485 dcbrush.SetStyle( style );
02486 break;
02487 case a2dFILL_TWOCOL_CROSSDIAG_HATCH:
02488 style = wxBRUSHSTYLE_CROSSDIAG_HATCH;
02489 dcbrush.SetColour( m_activefill.GetColour() );
02490 dcbrush.SetStyle( style );
02491 break;
02492 case a2dFILL_TWOCOL_FDIAGONAL_HATCH:
02493 style = wxBRUSHSTYLE_FDIAGONAL_HATCH;
02494 dcbrush.SetColour( m_activefill.GetColour() );
02495 dcbrush.SetStyle( style );
02496 break;
02497 case a2dFILL_TWOCOL_CROSS_HATCH:
02498 style = wxBRUSHSTYLE_CROSS_HATCH;
02499 dcbrush.SetColour( m_activefill.GetColour() );
02500 dcbrush.SetStyle( style );
02501 break;
02502 case a2dFILL_TWOCOL_HORIZONTAL_HATCH:
02503 style = wxBRUSHSTYLE_HORIZONTAL_HATCH;
02504 dcbrush.SetColour( m_activefill.GetColour() );
02505 dcbrush.SetStyle( style );
02506 break;
02507 case a2dFILL_TWOCOL_VERTICAL_HATCH:
02508 style = wxBRUSHSTYLE_VERTICAL_HATCH;
02509 dcbrush.SetColour( m_activefill.GetColour() );
02510 dcbrush.SetStyle( style );
02511 break;
02512 default:
02513 style = wxBRUSHSTYLE_SOLID;
02514 dcbrush.SetColour( m_activefill.GetColour() );
02515 dcbrush.SetStyle( style );
02516 }
02517
02518 m_renderDC->SetBrush( dcbrush );
02519 m_renderDC->SetTextBackground( m_activefill.GetColour() );
02520 }
02521 else if ( m_activefill.GetType() == a2dFILL_BITMAP )
02522 {
02523 wxBrush dcbrush;
02524 wxBrushStyle style;
02525 switch( m_activefill.GetStyle() )
02526 {
02527 case a2dFILL_STIPPLE:
02528 style = wxBRUSHSTYLE_STIPPLE;
02529 dcbrush.SetColour( m_activefill.GetColour() );
02530 dcbrush.SetStipple( m_activefill.GetStipple() );
02531 dcbrush.SetStyle( style );
02532 break;
02533 case a2dFILL_STIPPLE_MASK_OPAQUE_TRANSPARENT:
02534 case a2dFILL_STIPPLE_MASK_OPAQUE:
02535 if ( 0 )
02536 {
02537 wxBitmap noMask = m_activefill.GetStipple();
02538 noMask.SetMask( NULL );
02539 style = wxBRUSHSTYLE_STIPPLE;
02540 dcbrush.SetColour( m_activefill.GetColour() );
02541 dcbrush.SetStipple( noMask );
02542 }
02543 else
02544 {
02545 style = wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE;
02546 dcbrush.SetColour( m_activefill.GetColour() );
02547 dcbrush.SetStipple( m_activefill.GetStipple() );
02548 }
02549 dcbrush.SetStyle( style );
02550 break;
02551 default: style = wxBRUSHSTYLE_SOLID;
02552 dcbrush.SetColour( m_activefill.GetColour() );
02553 dcbrush.SetStyle( style );
02554 }
02555
02556 m_renderDC->SetBrush( dcbrush );
02557 m_renderDC->SetTextBackground( m_activefill.GetColour() );
02558 }
02559 }
02560 }
02561
02562 bool a2dDcContext::SetLogicalFunction( wxRasterOperationMode function )
02563 {
02564 switch( function )
02565 {
02566 case wxINVERT:
02567 m_drawstyle = a2dWIREFRAME_INVERT;
02568 m_activestroke = *a2dBLACK_STROKE;
02569 m_activefill = *a2dTRANSPARENT_FILL;
02570 break;
02571 default:
02572 m_drawstyle = a2dFILLED;
02573 }
02574
02575 if ( m_renderDC )
02576 m_renderDC->SetLogicalFunction( function );
02577 return true;
02578 }
02579
02580 void a2dDcContext::SetDrawStyle( a2dDrawStyle drawstyle )
02581 {
02582 m_drawstyle = drawstyle;
02583
02584 switch( drawstyle )
02585 {
02586 case a2dWIREFRAME_INVERT:
02587 m_activestroke = *a2dBLACK_STROKE;
02588 m_activefill = *a2dTRANSPARENT_FILL;
02589 if ( m_renderDC )
02590 m_renderDC->SetLogicalFunction( wxINVERT );
02591 break;
02592
02593 case a2dWIREFRAME:
02594 m_activestroke = *a2dBLACK_STROKE;
02595 m_activefill = *a2dTRANSPARENT_FILL;
02596 if ( m_renderDC )
02597 m_renderDC->SetLogicalFunction( wxCOPY );
02598 break;
02599
02600 case a2dWIREFRAME_ZERO_WIDTH:
02601 m_activestroke = *a2dBLACK_STROKE;
02602 m_activefill = *a2dTRANSPARENT_FILL;
02603 if ( m_renderDC )
02604 m_renderDC->SetLogicalFunction( wxCOPY );
02605 break;
02606
02607 case a2dWIREFRAME_INVERT_ZERO_WIDTH:
02608 m_activestroke = *a2dBLACK_STROKE;
02609 m_activefill = *a2dTRANSPARENT_FILL;
02610 if ( m_renderDC )
02611 m_renderDC->SetLogicalFunction( wxINVERT );
02612 break;
02613
02614 case a2dFILLED:
02615 if ( m_renderDC )
02616 m_renderDC->SetLogicalFunction( wxCOPY );
02617 break;
02618
02619 default:
02620 wxASSERT( 0 );
02621 }
02622 }
02623
02624
02625 void a2dDcContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
02626 {
02627
02628
02629 wxPoint trpoints[4];
02630 double dx,dy;
02631
02632 m_usertodevice.TransformPoint( x, y, dx, dy );
02633 trpoints[0] = wxPoint( dx, dy );
02634 m_usertodevice.TransformPoint( x, y + h, dx, dy );
02635 trpoints[1] = wxPoint( dx, dy );
02636 m_usertodevice.TransformPoint( x + w, y + h, dx, dy );
02637 trpoints[2] = wxPoint( dx, dy);
02638 m_usertodevice.TransformPoint( x + w, y, dx, dy );
02639 trpoints[3] = wxPoint( dx, dy );
02640
02641 double xmin = trpoints[0].x;
02642 double ymin = trpoints[0].y;
02643 double xmax = trpoints[0].x;
02644 double ymax = trpoints[0].y;
02645 for ( int i = 1; i < 4; i ++ )
02646 {
02647 xmin = wxMin( xmin, trpoints[i].x );
02648 xmax = wxMax( xmax, trpoints[i].x );
02649 ymin = wxMin( ymin, trpoints[i].y );
02650 ymax = wxMax( ymax, trpoints[i].y );
02651 }
02652 wxRect cliprect = wxRect( xmin, ymin, xmax-xmin, ymax-ymin );
02653 m_clipboxdev = cliprect;
02654 wxRegion clip( cliprect );
02655 m_renderDC->DestroyClippingRegion();
02656 #if wxCHECK_VERSION(2,9,0)
02657 m_renderDC->SetDeviceClippingRegion( clip );
02658 #else
02659 m_renderDC->SetClippingRegion( clip );
02660 #endif
02661 }
02662
02663 void a2dDcContext::ResetClip()
02664 {
02665 if ( m_renderDC )
02666 m_renderDC->DestroyClippingRegion();
02667 m_clipboxdev = wxRect( 0, 0, m_width, m_height );
02668 }
02669
02670 #if wxCHECK_VERSION(2,9,0)
02671 void a2dDcContext::DrawBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h)
02672 #else
02673 void a2dDcContext::DrawGraphicsBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h)
02674 #endif
02675 {
02676 a2dBitmapData* data = static_cast<a2dBitmapData*>(bmp.GetRefData());
02677 wxImage image = data->GetImage();
02678
02679 if ( w == 0 || h == 0 )
02680 return;
02681
02682 wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
02683
02684 wxPoint centr( ( int ) w / 2, ( int ) h / 2 );
02685
02686
02687 double angle = m_usertodevice.GetRotation();
02688
02689 if ( fabs(angle) > 0.5 )
02690 {
02691 image.SetMask( true );
02692 if ( m_yaxis )
02693 image = image.Rotate( angle / 180.0 * wxPI, centr, true, NULL );
02694 else
02695 image = image.Rotate( -angle / 180.0 * wxPI, centr, true, NULL );
02696 }
02697
02698 int devicew, deviceh;
02699
02700 devicew = m_usertodevice.TransformDistance( w );
02701 deviceh = fabs( m_usertodevice.TransformDistance( h ) );
02702
02703 double hx, hy;
02704 m_usertodevice.TransformPoint( x, y, hx, hy );
02705 int devicex = ( int ) ( hx - devicew / 2.0 );
02706 int devicey = ( int ) ( hy - deviceh / 2.0 );
02707
02708
02709 bool imgHasMask = image.HasMask();
02710
02711 if ( devicew == 0 || deviceh == 0 )
02712 return;
02713
02714 double sx = image.GetWidth() / (double) devicew;
02715 double sy = image.GetHeight() / (double) deviceh;
02716
02717
02718 wxRect clipped = m_clipboxdev;
02719 clipped.Intersect( wxRect( devicex, devicey, devicew, deviceh ) );
02720 double deviceClipX = clipped.GetX();
02721 double deviceClipY = clipped.GetY();
02722 double deviceClipW = clipped.GetWidth();
02723 double deviceClipH = clipped.GetHeight();
02724
02725 clipped.SetX( (clipped.GetX() - devicex) * sx );
02726 clipped.SetY( (clipped.GetY() - devicey) * sy );
02727 clipped.SetWidth( clipped.GetWidth() * sx );
02728 clipped.SetHeight( clipped.GetHeight() * sy );
02729
02730
02731 if ( clipped.GetWidth() < 1 || clipped.GetHeight() < 1 )
02732 {
02733 m_renderDC->DrawRectangle( devicex, devicey, devicew, deviceh );
02734 return;
02735 }
02736
02737 if ( deviceClipW != devicew || deviceClipH != deviceh )
02738 image = image.GetSubImage( clipped );
02739
02740
02741
02742 image.Rescale( deviceClipW, deviceClipH );
02743
02744
02745 wxBitmap Bitmap( image );
02746
02747 if ( m_drawstyle == a2dFILLED )
02748 {
02749 wxMemoryDC MemoryDc;
02750 MemoryDc.SelectObject( Bitmap );
02751
02752 m_renderDC->Blit( deviceClipX, deviceClipY, deviceClipW, deviceClipH, &MemoryDc, 0, 0, wxCOPY, imgHasMask );
02753 }
02754 else
02755 {
02756 m_renderDC->DrawRectangle( devicex, devicey, devicew, deviceh );
02757 }
02758 }
02759
02760 void a2dDcContext::DrawVpath( const a2dVpath* path )
02761 {
02762 unsigned int segments = 0;
02763
02764 double tstep = 1 / ( double ) SPLINE_STEP;
02765 unsigned int i;
02766 for ( i = 0; i < path->size(); i++ )
02767 {
02768 a2dVpathSegment& seg = path->Item( i );
02769 switch ( seg.GetType() )
02770 {
02771 case a2dPATHSEG_CBCURVETO:
02772 case a2dPATHSEG_CBCURVETO_NOSTROKE:
02773 segments += SPLINE_STEP;
02774 break;
02775
02776 case a2dPATHSEG_QBCURVETO:
02777 case a2dPATHSEG_QBCURVETO_NOSTROKE:
02778 segments += SPLINE_STEP;
02779 break;
02780
02781 case a2dPATHSEG_ARCTO:
02782 case a2dPATHSEG_ARCTO_NOSTROKE:
02783 {
02784 a2dVpathArcSegment& cseg = ( a2dVpathArcSegment& ) seg;
02785
02786 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
02787
02788 if ( cseg.CalcR( path->Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
02789 {
02790 double dphi;
02791 unsigned int circlesegments;
02792 double radiusDev = m_usertodevice.TransformDistance( radius );
02793 Aberration( m_displayaberration, phit, radiusDev , dphi, circlesegments );
02794 segments += circlesegments + 1;
02795 }
02796 else
02797 segments ++;
02798 }
02799 break;
02800 default:
02801 segments++;
02802
02803 }
02804 }
02805
02806
02807 m_cpointsDouble.resize( segments * 2 );
02808
02809 double x, y;
02810 bool move = false;
02811 int count = 0;
02812 bool nostrokeparts = false;
02813
02814
02815 for ( i = 0; i < path->size(); i++ )
02816 {
02817 a2dVpathSegment& seg = path->Item( i );
02818 switch ( seg.GetType() )
02819 {
02820 case a2dPATHSEG_MOVETO:
02821 if ( count == 0 )
02822 {
02823 m_usertodevice.TransformPoint( seg.m_x1, seg.m_y1, x, y );
02824 m_cpointsDouble[count].x = x;
02825 m_cpointsDouble[count].y = y;
02826 count++;
02827 }
02828 else
02829 {
02830 i--;
02831 move = true;
02832 }
02833 break;
02834
02835 case a2dPATHSEG_LINETO:
02836 m_usertodevice.TransformPoint( seg.m_x1, seg.m_y1, x, y );
02837 m_cpointsDouble[count].x = x;
02838 m_cpointsDouble[count].y = y;
02839 count++;
02840 break;
02841 case a2dPATHSEG_LINETO_NOSTROKE:
02842 m_usertodevice.TransformPoint( seg.m_x1, seg.m_y1, x, y );
02843 m_cpointsDouble[count].x = x;
02844 m_cpointsDouble[count].y = y;
02845 count++;
02846 nostrokeparts = true;
02847 break;
02848
02849 case a2dPATHSEG_CBCURVETO_NOSTROKE:
02850 nostrokeparts = true;
02851 case a2dPATHSEG_CBCURVETO:
02852 {
02853 double xw, yw;
02854
02855 double xwl = path->Item( i ? i - 1 : 0 ).m_x1;
02856 double ywl = path->Item( i ? i - 1 : 0 ).m_y1;
02857 a2dVpathCBCurveSegment& cseg = ( a2dVpathCBCurveSegment& ) seg;
02858
02859 int step;
02860 double t = 0;
02861 for ( step = 0; step <= SPLINE_STEP; step++ )
02862 {
02863 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 );
02864 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 );
02865 m_usertodevice.TransformPoint( xw, yw, x, y );
02866 m_cpointsDouble[count].x = x;
02867 m_cpointsDouble[count].y = y;
02868 count++;
02869 t = t + tstep;
02870 }
02871 }
02872 break;
02873
02874 case a2dPATHSEG_QBCURVETO_NOSTROKE:
02875 nostrokeparts = true;
02876 case a2dPATHSEG_QBCURVETO:
02877 {
02878 double xw, yw;
02879
02880 double xwl = path->Item( i ? i - 1 : 0 ).m_x1;
02881 double ywl = path->Item( i ? i - 1 : 0 ).m_y1;
02882 a2dVpathQBCurveSegment& cseg = ( a2dVpathQBCurveSegment& ) seg;
02883
02884 int step;
02885 double t = 0;
02886 for ( step = 0; step <= SPLINE_STEP; step++ )
02887 {
02888 xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
02889 yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
02890 m_usertodevice.TransformPoint( xw, yw, x, y );
02891 m_cpointsDouble[count].x = x;
02892 m_cpointsDouble[count].y = y;
02893 count++;
02894 t = t + tstep;
02895 }
02896 }
02897 break;
02898
02899 case a2dPATHSEG_ARCTO_NOSTROKE:
02900 nostrokeparts = true;
02901 case a2dPATHSEG_ARCTO:
02902 {
02903 a2dVpathArcSegment& cseg = ( a2dVpathArcSegment& ) seg;
02904
02905 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
02906
02907 if ( cseg.CalcR( path->Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
02908 {
02909 double dphi;
02910 unsigned int segments;
02911 double radiusDev = m_usertodevice.TransformDistance( radius );
02912 Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
02913
02914 double theta = beginrad;
02915 unsigned int step;
02916
02917 double x, y;
02918 for ( step = 0; step < segments + 1; step++ )
02919 {
02920 m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
02921 m_cpointsDouble[count].x = x;
02922 m_cpointsDouble[count].y = y;
02923 count++;
02924 theta = theta + dphi;
02925 }
02926 }
02927 else
02928 {
02929 double x, y;
02930 m_usertodevice.TransformPoint( cseg.m_x1, cseg.m_y1, x, y );
02931 m_cpointsDouble[count].x = x;
02932 m_cpointsDouble[count].y = y;
02933 count++;
02934 }
02935 }
02936 default:
02937 break;
02938 break;
02939 }
02940
02941 if ( move )
02942 {
02943 DeviceDrawLines( count, false );
02944 move = false;
02945 count = 0;
02946 }
02947 else if ( seg.GetClose() != a2dPATHSEG_END_OPEN )
02948 {
02949 if ( nostrokeparts || seg.GetClose() == a2dPATHSEG_END_CLOSED_NOSTROKE )
02950 {
02951 a2dStroke stroke = m_activestroke;
02952 m_activestroke = *a2dTRANSPARENT_STROKE;
02953 DeviceDrawPolygon( count, false, wxODDEVEN_RULE );
02954 m_activestroke = stroke;
02955 nostrokeparts = true;
02956 }
02957 else
02958 {
02959 DeviceDrawPolygon( count, false, wxODDEVEN_RULE );
02960 }
02961
02962 move = false;
02963 count = 0;
02964 }
02965 else if ( i == path->GetCount() - 1 )
02966 {
02967 DeviceDrawLines( count, false );
02968 }
02969 }
02970
02971 if ( nostrokeparts )
02972 {
02973 move = false;
02974 count = 0;
02975 nostrokeparts = false;
02976
02977 double lastmovex = 0;
02978 double lastmovey = 0;
02979
02980 for ( i = 0; i < path->GetCount(); i++ )
02981 {
02982 a2dVpathSegment& seg = path->Item( i );
02983 switch ( seg.GetType() )
02984 {
02985 case a2dPATHSEG_MOVETO:
02986 if ( count == 0 )
02987 {
02988 m_usertodevice.TransformPoint( seg.m_x1, seg.m_y1, x, y );
02989 m_cpointsDouble[count].x = x;
02990 m_cpointsDouble[count].y = y;
02991 lastmovex = m_cpointsDouble[count].x;
02992 lastmovey = m_cpointsDouble[count].y;
02993 count++;
02994 }
02995 else
02996 {
02997 i--;
02998 move = true;
02999 }
03000 break;
03001
03002 case a2dPATHSEG_LINETO:
03003 m_usertodevice.TransformPoint( seg.m_x1, seg.m_y1, x, y );
03004 m_cpointsDouble[count].x = x;
03005 m_cpointsDouble[count].y = y;
03006 count++;
03007 break;
03008
03009 case a2dPATHSEG_LINETO_NOSTROKE:
03010 case a2dPATHSEG_CBCURVETO_NOSTROKE:
03011 case a2dPATHSEG_QBCURVETO_NOSTROKE:
03012 case a2dPATHSEG_ARCTO_NOSTROKE:
03013 if ( count == 0 )
03014 {
03015 m_usertodevice.TransformPoint( seg.m_x1, seg.m_y1, x, y );
03016 m_cpointsDouble[count].x = x;
03017 m_cpointsDouble[count].y = y;
03018 count++;
03019 }
03020 else
03021 {
03022 i--;
03023 nostrokeparts = true;
03024 }
03025 break;
03026
03027 case a2dPATHSEG_CBCURVETO:
03028 {
03029 double xw, yw;
03030
03031 double xwl = path->Item( i ? i - 1 : 0 ).m_x1;
03032 double ywl = path->Item( i ? i - 1 : 0 ).m_y1;
03033 a2dVpathCBCurveSegment& cseg = ( a2dVpathCBCurveSegment& ) seg;
03034
03035 int step;
03036 double t = 0;
03037 for ( step = 0; step <= SPLINE_STEP; step++ )
03038 {
03039 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 );
03040 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 );
03041 m_usertodevice.TransformPoint( xw, yw, x, y );
03042 m_cpointsDouble[count].x = x;
03043 m_cpointsDouble[count].y = y;
03044 count++;
03045 t = t + tstep;
03046 }
03047 }
03048 break;
03049
03050 case a2dPATHSEG_QBCURVETO:
03051 {
03052 double xw, yw;
03053
03054 double xwl = path->Item( i ? i - 1 : 0 ).m_x1;
03055 double ywl = path->Item( i ? i - 1 : 0 ).m_y1;
03056 a2dVpathQBCurveSegment& cseg = ( a2dVpathQBCurveSegment& ) seg;
03057
03058 int step;
03059 double t = 0;
03060 for ( step = 0; step <= SPLINE_STEP; step++ )
03061 {
03062 xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
03063 yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
03064 m_usertodevice.TransformPoint( xw, yw, x, y );
03065 m_cpointsDouble[count].x = x;
03066 m_cpointsDouble[count].y = y;
03067 count++;
03068 t = t + tstep;
03069 }
03070 }
03071 break;
03072
03073 case a2dPATHSEG_ARCTO:
03074 {
03075 a2dVpathArcSegment& cseg = ( a2dVpathArcSegment& ) seg;
03076
03077 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
03078
03079 if ( cseg.CalcR( path->Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
03080 {
03081 double dphi;
03082 unsigned int segments;
03083 double radiusDev = m_usertodevice.TransformDistance( radius );
03084 Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
03085
03086 double theta = beginrad;
03087 unsigned int step;
03088
03089 double x, y;
03090 for ( step = 0; step < segments + 1; step++ )
03091 {
03092 m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
03093 m_cpointsDouble[count].x = x;
03094 m_cpointsDouble[count].y = y;
03095 count++;
03096 theta = theta + dphi;
03097 }
03098 }
03099 else
03100 {
03101 double x, y;
03102 m_usertodevice.TransformPoint( cseg.m_x1, cseg.m_y1, x, y );
03103 m_cpointsDouble[count].x = x;
03104 m_cpointsDouble[count].y = y;
03105 count++;
03106 }
03107 }
03108 default:
03109 break;
03110
03111 break;
03112 }
03113
03114 if ( move || nostrokeparts )
03115 {
03116 DeviceDrawLines( count, false );
03117 move = false;
03118 nostrokeparts = false;
03119 count = 0;
03120 }
03121 else if ( seg.GetClose() != a2dPATHSEG_END_OPEN )
03122 {
03123 if ( seg.GetClose() == a2dPATHSEG_END_CLOSED )
03124 {
03125 m_cpointsDouble[count].x = lastmovex;
03126 m_cpointsDouble[count].y = lastmovey;
03127 count++;
03128 }
03129 DeviceDrawLines( count, false );
03130 nostrokeparts = false;
03131 move = false;
03132 count = 0;
03133 }
03134 else if ( i == path->GetCount() )
03135 {
03136 DeviceDrawLines( count, false );
03137 }
03138 }
03139 }
03140
03141 }
03142
03143
03144 void a2dDcContext::DeviceDrawPolygon( unsigned int n, bool spline, wxPolygonFillMode fillStyle )
03145 {
03146 wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
03147
03148 wxPoint *int_cpts = _convertToIntPointCache( n, &m_cpointsDouble[0] );
03149
03150
03151 if ( IsStrokeOnly() )
03152 {
03153 if ( n == 2 )
03154 {
03155
03156 m_renderDC->DrawLines( n, int_cpts );
03157
03158 if ( m_drawstyle == a2dWIREFRAME || m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
03159 m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n-1].x, int_cpts[n-1].y );
03160 }
03161 else
03162 {
03163
03164 #if defined(__WXMSW__)
03165 #if wxCHECK_VERSION(2,9,0)
03166 wxMSWDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
03167 WXHDC hdc = dcimpl->GetHDC();
03168 #else
03169 WXHDC hdc = m_renderDC->GetHDC();
03170 #endif
03171 SetPolyFillMode( ( struct HDC__ * ) hdc, fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING );
03172
03173
03174 ( void )Polygon( ( struct HDC__ * ) hdc, ( POINT* )int_cpts, n );
03175
03176 #else
03177 m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
03178 #endif
03179
03180 }
03181 }
03182 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR || m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
03183 {
03184 FillPolygon( n, &m_cpointsDouble[0] );
03185
03186 if ( IsStroked() )
03187 {
03188 m_renderDC->DrawLines( n, int_cpts );
03189 m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n-1].x, int_cpts[n-1].y );
03190 }
03191 }
03192 else if ( m_activefill.GetType() == a2dFILL_BITMAP && m_activefill.GetStyle() == a2dFILL_STIPPLE_MASK_OPAQUE_TRANSPARENT )
03193 {
03194 #if defined(__WXMSW__)
03195 m_renderDC->SetTextForeground( *wxBLACK );
03196 m_renderDC->SetTextBackground( *wxWHITE );
03197 m_renderDC->SetLogicalFunction( wxAND_INVERT );
03198
03199
03200 COLORREF colFgOld, colBgOld;
03201
03202 #if wxCHECK_VERSION(2,9,0)
03203 wxMSWDCImpl* dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
03204 WXHDC hdc = dcimpl->GetHDC();
03205 #else
03206 WXHDC hdc = m_renderDC->GetHDC();
03207 #endif
03208
03209 colBgOld = ::GetBkColor( ( struct HDC__ * ) hdc );
03210 colFgOld = ::GetTextColor( ( struct HDC__ * ) hdc );
03211
03212
03213
03214 ::SetBkColor( ( struct HDC__ * ) hdc, m_renderDC->GetTextForeground().GetPixel() );
03215
03216
03217 ::SetTextColor( ( struct HDC__ * ) hdc, m_renderDC->GetTextBackground().GetPixel() );
03218
03219 int prev = SetPolyFillMode( ( struct HDC__ * ) hdc, WINDING );
03220 ( void )Polygon( ( struct HDC__ * ) hdc, ( POINT* )int_cpts, n );
03221
03222
03223
03224
03225 m_renderDC->SetTextForeground( *wxBLACK );
03226
03227 m_renderDC->SetTextBackground( m_activefill.GetColour() );
03228 m_renderDC->SetLogicalFunction( wxOR );
03229
03230
03231
03232 ::SetBkColor( ( struct HDC__ * ) hdc, m_renderDC->GetTextForeground().GetPixel() );
03233
03234
03235 ::SetTextColor( ( struct HDC__ * ) hdc, m_renderDC->GetTextBackground().GetPixel() );
03236 ( void )Polygon( ( struct HDC__ * ) hdc, ( POINT* )int_cpts, n );
03237 SetPolyFillMode( ( struct HDC__ * ) hdc, prev );
03238
03239
03240 ::SetBkMode( ( struct HDC__ * ) hdc, TRANSPARENT );
03241 ::SetTextColor( ( struct HDC__ * ) hdc, colFgOld );
03242 ::SetBkColor( ( struct HDC__ * ) hdc, colBgOld );
03243
03244 m_renderDC->SetLogicalFunction( wxCOPY );
03245 m_renderDC->SetTextForeground( m_activestroke.GetColour() );
03246 m_renderDC->SetTextBackground( m_activefill.GetColour() );
03247
03248
03249 if ( IsStroked() )
03250 {
03251 m_renderDC->DrawLines( n, int_cpts );
03252 m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n-1].x, int_cpts[n-1].y );
03253 }
03254
03255
03256 #else
03257 wxPen dcpen( m_activestroke.GetColour(), ( int ) m_activestroke.GetWidth(), wxSOLID );
03258
03259
03260 m_renderDC->SetPen( dcpen );
03261
03262 m_renderDC->SetTextForeground( *wxBLACK );
03263 m_renderDC->SetTextBackground( *wxWHITE );
03264 m_renderDC->SetLogicalFunction( wxAND_INVERT );
03265
03266 m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
03267
03268
03269
03270 m_renderDC->SetTextForeground( *wxBLACK );
03271
03272 m_renderDC->SetTextBackground( m_activefill.GetColour() );
03273 m_renderDC->SetLogicalFunction( wxOR );
03274
03275 SetStroke( m_activestroke );
03276 m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
03277 m_renderDC->SetLogicalFunction( wxCOPY );
03278 m_renderDC->SetTextForeground( m_activestroke.GetColour() );
03279 m_renderDC->SetTextBackground( m_activefill.GetColour() );
03280
03281
03282 if ( IsStroked() )
03283 {
03284 m_renderDC->DrawLines( n, int_cpts );
03285 m_renderDC->DrawLine( int_cpts[0].x, int_cpts[0].y, int_cpts[n-1].x, int_cpts[n-1].y );
03286 }
03287 #endif
03288 }
03289 else if ( m_activefill.GetType() == a2dFILL_BITMAP &&
03290 ( m_activefill.GetStyle() == a2dFILL_STIPPLE ||
03291 m_activefill.GetStyle() == a2dFILL_STIPPLE_MASK_OPAQUE )
03292 )
03293 {
03294 m_renderDC->SetTextForeground( m_activefill.GetColour() );
03295 m_renderDC->SetTextBackground( m_activefill.GetColour2() );
03296 m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
03297 m_renderDC->SetTextForeground( m_activestroke.GetColour() );
03298 m_renderDC->SetTextBackground( m_activefill.GetColour() );
03299 }
03300 else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
03301 {
03302 wxBrush dcbrush( m_activefill.GetColour2() );
03303 wxBrush cur_dcbrush = m_renderDC->GetBrush();
03304 m_renderDC->SetBrush( dcbrush );
03305 m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
03306 m_renderDC->SetBrush( cur_dcbrush );
03307 m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
03308 }
03309 else
03310 {
03311 #if defined(__WXMSW__)
03312
03313
03314
03315
03316
03317 m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
03318
03319 #else
03320 m_renderDC->DrawPolygon( n, int_cpts, 0, 0, fillStyle );
03321 #endif
03322 }
03323
03324 if ( IsStroked() && m_activestroke.GetType() == a2dSTROKE_OBJECT )
03325 {
03326
03327
03328
03329 wxRealPoint * copy = new wxRealPoint[n+1];
03330 memcpy( copy, &m_cpointsDouble[0], n * sizeof( wxRealPoint ) );
03331 copy[n].x = m_cpointsDouble[0].x;
03332 copy[n].y = m_cpointsDouble[0].y;
03333
03334
03335 delete [] copy;
03336 }
03337 }
03338
03339 void a2dDcContext::DeviceDrawLines( unsigned int n, bool spline )
03340 {
03341 wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
03342
03343 wxPoint *int_cpts = _convertToIntPointCache( n, &m_cpointsDouble[0] );
03344
03345 if ( n == 1 )
03346 m_renderDC->DrawCircle( int_cpts[0].x, int_cpts[0].y, 2 );
03347
03348 else
03349 {
03350 m_renderDC->DrawLines( n, int_cpts );
03351 #if defined(__WXMSW__)
03352
03353
03354 if ( n > 1 && m_renderDC->GetPen().GetWidth() == 1 )
03355 m_renderDC->DrawPoint( int_cpts[n-1].x, int_cpts[n-1].y );
03356 #endif
03357 }
03358 }
03359
03360 void a2dDcContext::DeviceDrawLine( double x1, double y1, double x2, double y2 )
03361 {
03362 wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
03363
03364 m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y2 ) );
03365 }
03366
03367 void a2dDcContext::DeviceDrawHorizontalLine( int x1, int y1, int x2, bool use_stroke_color)
03368 {
03369 wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
03370
03371 wxColour color;
03372 if (use_stroke_color)
03373 {
03374 wxPen pen = m_renderDC->GetPen();
03375 color = wxColour( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
03376 m_renderDC->SetPen( wxPen( color ) );
03377 m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y1 ) );
03378 m_renderDC->SetPen( pen );
03379 }
03380 else
03381 {
03382 m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x2 ), Round( y1 ) );
03383 }
03384 }
03385
03386 void a2dDcContext::DeviceDrawVerticalLine( int x1, int y1, int y2, bool use_stroke_color)
03387 {
03388 wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
03389
03390 wxColour color;
03391 if (use_stroke_color)
03392 {
03393 wxPen pen = m_renderDC->GetPen();
03394 color = wxColour( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
03395 m_renderDC->SetPen( wxPen( color ) );
03396 m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x1 ), Round( y2 ) );
03397 m_renderDC->SetPen( pen );
03398 }
03399 else
03400 {
03401 m_renderDC->DrawLine( Round( x1 ), Round( y1 ), Round( x1 ), Round( y2 ) );
03402 }
03403 }
03404
03405 void a2dDcContext::DeviceDrawPixel( int x1, int y1, unsigned char r, unsigned char g, unsigned char b , unsigned char a )
03406 {
03407 #if defined(__WXMSW__)
03408 #if wxCHECK_VERSION(2,9,0)
03409 wxMSWDCImpl * dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxMSWDCImpl );
03410 WXHDC hdc = dcimpl->GetHDC();
03411 #else
03412 WXHDC hdc = m_renderDC->GetHDC();
03413 #endif
03414 ::SetPixelV( ( struct HDC__ * )hdc, x1, y1, RGB( r, g, b ) );
03415 #elif __WXGTK__
03416
03417 #if wxCHECK_VERSION(2,9,1)
03418 wxWindowDCImpl * dcimpl = wxStaticCast( m_renderDC->GetImpl(), wxWindowDCImpl );
03419 GdkWindow* gtkwin = dcimpl->GetGDKWindow();
03420 if ( gtkwin )
03421 gdk_draw_point( gtkwin, dcimpl->m_penGC, x1, y1 );
03422 #else
03423 wxColour col( r, g, b );
03424 col.CalcPixel( ( ( wxWindowDC* )m_renderDC )->m_cmap );
03425 gdk_gc_set_foreground( ( ( wxWindowDC* )m_renderDC )->m_penGC, col.GetColor() );
03426 gdk_draw_point( ( ( wxWindowDC* ) m_renderDC )->m_window, ( ( wxWindowDC* )m_renderDC )->m_penGC, x1, y1 );
03427 #endif
03428
03429 #else
03430
03431 #endif
03432 }
03433
03434 void a2dDcContext::DeviceDrawBitmap( const wxBitmap &bmp, double x, double y, bool useMask )
03435 {
03436 wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
03437 if ( m_drawstyle == a2dWIREFRAME_INVERT )
03438 {
03439 m_renderDC->DrawRectangle( Round( x ), Round( y ), bmp.GetWidth(), bmp.GetHeight() );
03440 }
03441 else
03442 m_renderDC->DrawBitmap( bmp, Round( x ), Round( y ), useMask );
03443 }
03444
03445 void a2dDcContext::DrawCharDc( wxChar c )
03446 {
03447 double x, y;
03448 x = y = 0.0;
03449 double dx, dy;
03450 double angle = m_usertodevice.GetRotation();
03451 m_usertodevice.TransformPoint( x, y + m_a2dfont.GetLineHeight(), dx, dy );
03452 m_renderDC->DrawRotatedText( wxString( c ), ( int ) dx, ( int ) dy, -angle );
03453 }
03454
03455 void a2dDcContext::DrawTextDc( const wxString& text, double x, double y )
03456 {
03457 wxASSERT_MSG( m_renderDC, wxT( "no renderDc set" ) );
03458
03459
03460 unsigned int fontsize;
03461 double dx = m_usertodevice.GetValue( 1, 0 );
03462 double dy = m_usertodevice.GetValue( 1, 1 );
03463 fontsize = ( unsigned int ) fabs( m_a2dfont.GetSize() * sqrt( dx * dx + dy * dy ) );
03464 if ( fontsize < 1 )
03465 fontsize = 1;
03466 m_a2dfont.GetFont().SetPointSize( fontsize );
03467
03468 m_renderDC->SetFont( m_a2dfont.GetFont() );
03469 m_renderDC->SetBackgroundMode( wxTRANSPARENT );
03470 m_renderDC->SetTextForeground( m_activestroke.GetColour() );
03471
03472 DrawTextGeneric( text, x, y, ( void ( a2dContext::* )( wxChar ) ) & a2dDcContext::DrawCharDc );
03473 }
03474
03475 #if wxART2D_USE_FREETYPE
03476 extern FT_Library g_freetypeLibrary;
03477
03478
03479 typedef struct
03480 {
03481 wxColour colour;
03482 int xmin, ymax;
03483 int stride;
03484 unsigned char* buf;
03485 }
03486 a2dSpanData;
03487
03488
03489 static void a2dSpanFuncGray( int y, int count, FT_Span* spans, a2dSpanData* user )
03490 {
03491 unsigned int alpha, invalpha, len;
03492
03493 unsigned int r, g, b, rpm, gpm, bpm;
03494 r = user->colour.Red();
03495 g = user->colour.Green();
03496 b = user->colour.Blue();
03497
03498 unsigned char *buf, *buf2;
03499 buf = user->buf + ( user->ymax - y ) * user->stride - user->xmin * 3;
03500 do
03501 {
03502 buf2 = buf + spans->x * 3;
03503 len = spans->len;
03504 alpha = spans->coverage;
03505 if ( alpha == 255 )
03506 {
03507 do
03508 {
03509
03510
03511 #ifdef __WXGTK__
03512 buf2[0] = r;
03513 buf2[1] = g;
03514 buf2[2] = b;
03515 #else
03516 buf2[0] = b;
03517 buf2[1] = g;
03518 buf2[2] = r;
03519 #endif
03520 buf2 += 3;
03521 }
03522 while( --len );
03523 }
03524 else
03525 {
03526 rpm = r * alpha;
03527 gpm = g * alpha;
03528 bpm = b * alpha;
03529 invalpha = 255 - alpha;
03530 do
03531 {
03532
03533
03534 #ifdef __WXGTK__
03535 buf2[0] = ( buf2[0] * invalpha + rpm ) / 255;
03536 buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
03537 buf2[2] = ( buf2[2] * invalpha + bpm ) / 255;
03538 #else
03539 buf2[0] = ( buf2[0] * invalpha + bpm ) / 255;
03540 buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
03541 buf2[2] = ( buf2[2] * invalpha + rpm ) / 255;
03542 #endif
03543 buf2 += 3;
03544 }
03545 while( --len );
03546 }
03547 spans++;
03548 }
03549 while ( --count );
03550 }
03551 #endif
03552
03553
03554 void a2dDcContext::DrawCharFreetype( wxChar c )
03555 {
03556 #if wxART2D_USE_FREETYPE
03557
03558 double dx, dy;
03559 m_usertodevice.TransformPoint( 0.0, m_a2dfont.GetDescent(), dx, dy );
03560
03561
03562 const a2dGlyph* a2dglyph = m_a2dfont.GetGlyphFreetype( c );
03563 if( !a2dglyph )
03564 return;
03565 FT_Glyph image;
03566 if ( FT_Glyph_Copy( a2dglyph->m_glyph, &image ) != 0 )
03567 return;
03568
03569
03570 a2dAffineMatrix glyphPos;
03571 glyphPos.Scale( m_a2dfont.GetSize() / FTNORMFONT );
03572 a2dAffineMatrix glyphToDevice = m_usertodevice * glyphPos;
03573
03574
03575 FT_Matrix trans_matrix;
03576 trans_matrix.xx = ( FT_Fixed ) ( glyphToDevice.GetValue( 0, 0 ) * 0x10000 );
03577 trans_matrix.xy = ( FT_Fixed ) ( glyphToDevice.GetValue( 1, 0 ) * 0x10000 );
03578 trans_matrix.yx = ( FT_Fixed ) ( -glyphToDevice.GetValue( 0, 1 ) * 0x10000 );
03579 trans_matrix.yy = ( FT_Fixed ) ( -glyphToDevice.GetValue( 1, 1 ) * 0x10000 );
03580 FT_Vector vec;
03581 vec.x = ( int ) ( ( dx - ( int ) dx ) * 64.0 );
03582 vec.y = ( int ) ( ( dy - ( int ) dy ) * -64.0 );
03583 if ( FT_Glyph_Transform( image, &trans_matrix, &vec ) != 0 )
03584 {
03585 wxFAIL_MSG( _( "glyph transform wrong" ) );
03586 FT_Done_Glyph( image );
03587 return;
03588 }
03589
03590
03591 FT_BBox bbox;
03592 FT_Glyph_Get_CBox( image, ft_glyph_bbox_pixels, &bbox );
03593
03594
03595 if ( m_clipboxdev.GetLeft() > ( int ) dx + bbox.xMin )
03596 bbox.xMin = m_clipboxdev.GetLeft() - ( int ) dx;
03597 if ( m_clipboxdev.GetRight() < ( int ) dx + bbox.xMax )
03598 bbox.xMax = m_clipboxdev.GetRight() - ( int ) dx;
03599
03600 if ( m_clipboxdev.GetTop() >= (int) dy - bbox.yMax )
03601 bbox.yMax = (int) dy - m_clipboxdev.GetTop();
03602 if ( m_clipboxdev.GetBottom() < (int) dy - bbox.yMin )
03603 bbox.yMin = (int) dy - m_clipboxdev.GetBottom();
03604
03605
03606 if ( bbox.xMax - bbox.xMin <= 0 || bbox.yMax - bbox.yMin <= 0 )
03607 {
03608 FT_Done_Glyph( image );
03609 return;
03610 }
03611
03612 int px = ( int ) dx + bbox.xMin;
03613 int py = ( int ) dy - bbox.yMax;
03614 int w = bbox.xMax - bbox.xMin + 1;
03615 int h = bbox.yMax - bbox.yMin + 1;
03616
03617
03618 wxRect absarea2( px, py, w, h );
03619 wxBitmap sub_bitmap = m_buffer->GetSubBitmap( absarea2 );
03620
03621 #if defined(__WXMSW__)
03622 BITMAPINFO bi;
03623 bi.bmiHeader.biSize = sizeof( bi.bmiHeader );
03624 bi.bmiHeader.biWidth = w;
03625 bi.bmiHeader.biHeight = -h;
03626 bi.bmiHeader.biPlanes = 1;
03627 bi.bmiHeader.biBitCount = 24;
03628 bi.bmiHeader.biCompression = BI_RGB;
03629 bi.bmiHeader.biSizeImage = 0;
03630 bi.bmiHeader.biClrUsed = 0;
03631 bi.bmiHeader.biClrImportant = 0;
03632
03633 HBITMAP hbitmap = ( HBITMAP ) sub_bitmap.GetHBITMAP();
03634 HDC hdc = ::GetDC( NULL );
03635 HDC memdc = ::CreateCompatibleDC( hdc );
03636 unsigned char *buf = ( unsigned char * ) malloc( ( 3 * w + sizeof( DWORD ) - 1 ) / sizeof( DWORD ) * sizeof( DWORD ) * h );
03637 ::GetDIBits( memdc, hbitmap, 0, h, buf, &bi, DIB_RGB_COLORS );
03638 #else // defined( __WXMSW__ )
03639 wxImage wximage( sub_bitmap.ConvertToImage() );
03640 #endif // defined( __WXMSW__ )
03641
03642
03643 if ( image->format == FT_GLYPH_FORMAT_OUTLINE )
03644 {
03645 a2dSpanData spandata;
03646 spandata.colour = m_activestroke.GetColour();
03647 spandata.xmin = bbox.xMin;
03648 spandata.ymax = bbox.yMax;
03649 spandata.stride = w * 3;
03650 #if defined(__WXMSW__)
03651
03652 spandata.stride = ( spandata.stride + sizeof( DWORD ) - 1 ) / sizeof( DWORD ) * sizeof( DWORD );
03653 spandata.buf = buf;
03654 #else // defined( __WXMSW__ )
03655 spandata.buf = wximage.GetData();
03656 #endif // defined( __WXMSW__ )
03657 wxASSERT( spandata.buf != NULL );
03658
03659 FT_Raster_Params params;
03660 params.target = NULL;
03661 params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT | FT_RASTER_FLAG_CLIP;
03662 params.gray_spans = ( FT_SpanFunc ) & a2dSpanFuncGray;
03663 params.black_spans = NULL;
03664 params.bit_test = ( FT_Raster_BitTest_Func ) NULL;
03665 params.bit_set = ( FT_Raster_BitSet_Func ) NULL;
03666 params.user = &spandata;
03667 params.clip_box = bbox;
03668
03669 FT_Outline& outline = ( ( FT_OutlineGlyph ) image )->outline;
03670 if ( FT_Outline_Render( g_freetypeLibrary, &outline, ¶ms ) == 0 )
03671 {
03672 #if defined( __WXMSW__ )
03673 ::SetDIBits( memdc, hbitmap, 0, h, buf, &bi, DIB_RGB_COLORS );
03674 #else // defined( __WXMSW__ )
03675 wxBitmap sub_bitmap( wximage );
03676 #endif // defined( __WXMSW__ )
03677 DeviceDrawBitmap( sub_bitmap, px, py, false );
03678 }
03679 }
03680 else
03681 wxFAIL_MSG( _( "Non vector fonts are not supported" ) );
03682
03683 #if defined(__WXMSW__)
03684 free( buf );
03685 ::DeleteDC( memdc );
03686 ::ReleaseDC( NULL, hdc );
03687 #endif // defined( __WXMSW__ )
03688
03689 FT_Done_Glyph( image );
03690 #else // wxART2D_USE_FREETYPE
03691 DrawCharUnknown( c );
03692 #endif // wxART2D_USE_FREETYPE
03693 }
03694
03695
03696
03697
03698
03699
03700
03701
03702
03703
03704
03705
03706
03707
03708
03709 IMPLEMENT_DYNAMIC_CLASS(a2dRenderer,wxGraphicsRenderer)
03710
03711
03712 wxGraphicsContext * a2dRenderer::CreateContext( const wxWindowDC& dc)
03713 {
03714 wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
03715 return NULL;
03716 }
03717
03718 wxGraphicsContext * a2dRenderer::CreateContext( const wxMemoryDC& dc )
03719 {
03720 wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
03721 return NULL;
03722 }
03723
03724 wxGraphicsContext * a2dRenderer::CreateContext( wxMemoryDC* dc, wxBitmap* drawable )
03725 {
03726 return new a2dDcContext( this, dc, drawable );
03727 }
03728
03729 wxGraphicsContext * a2dRenderer::CreateContextFromNativeContext( void * context )
03730 {
03731 wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
03732 return NULL;
03733 }
03734
03735 #if wxCHECK_VERSION(2, 9, 0)
03736 #if wxUSE_PRINTING_ARCHITECTURE
03737 wxGraphicsContext * a2dRenderer::CreateContext( const wxPrinterDC& dc)
03738 {
03739 wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
03740 return NULL;
03741 }
03742 #ifdef __WXMSW__
03743 wxGraphicsContext * a2dRenderer::CreateContext( const wxEnhMetaFileDC& dc)
03744 {
03745 wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
03746 return NULL;
03747 }
03748 #endif
03749 #endif
03750 #endif //wxCHECK_VERSION(2, 9, 0)
03751
03752 wxGraphicsContext * a2dRenderer::CreateContextFromNativeWindow( void * window )
03753 {
03754 wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
03755 return NULL;
03756 }
03757
03758 wxGraphicsContext * a2dRenderer::CreateMeasuringContext()
03759 {
03760 return NULL;
03761
03762 }
03763
03764 wxGraphicsContext * a2dRenderer::CreateContext( wxWindow* window )
03765 {
03766 wxFAIL_MSG( wxT( "only drawable buffers for a2dContext" ) );
03767 return NULL;
03768 }
03769
03770
03771
03772 wxGraphicsPath a2dRenderer::CreatePath()
03773 {
03774 wxGraphicsPath path;
03775 path.SetRefData( new a2dPathData(this) );
03776 return path;
03777 }
03778
03779
03780
03781
03782 wxGraphicsMatrix a2dRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
03783 wxDouble tx, wxDouble ty)
03784
03785 {
03786 wxGraphicsMatrix m;
03787 a2dMatrixData* data = new a2dMatrixData( this );
03788 data->Set( a,b,c,d,tx,ty ) ;
03789 m.SetRefData(data);
03790 return m;
03791 }
03792
03793 wxGraphicsPen a2dRenderer::CreatePen(const wxPen& pen)
03794 {
03795 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
03796 return wxNullGraphicsPen;
03797 else
03798 {
03799 wxGraphicsPen p;
03800 p.SetRefData(new a2dStrokeData( this, pen ));
03801 return p;
03802 }
03803 }
03804
03805 wxGraphicsBrush a2dRenderer::CreateBrush(const wxBrush& brush )
03806 {
03807 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
03808 return wxNullGraphicsBrush;
03809 else
03810 {
03811 wxGraphicsBrush p;
03812 p.SetRefData(new a2dFillData( this, brush ));
03813 return p;
03814 }
03815 }
03816
03817 wxGraphicsPen a2dRenderer::CreateStroke(const a2dStroke& stroke )
03818 {
03819
03820
03821
03822 {
03823 wxGraphicsPen p;
03824 p.SetRefData(new a2dStrokeData( this, stroke ));
03825 return p;
03826 }
03827 }
03828
03829 wxGraphicsBrush a2dRenderer::CreateFill(const a2dFill& fill )
03830 {
03831
03832
03833
03834 {
03835 wxGraphicsBrush p;
03836 p.SetRefData(new a2dFillData( this, fill ));
03837 return p;
03838 }
03839 }
03840
03841 #if wxCHECK_VERSION(2, 9, 1)
03842 wxGraphicsBrush a2dRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
03843 wxDouble x2, wxDouble y2,
03844 const wxGraphicsGradientStops& stops)
03845 {
03846 wxGraphicsBrush p;
03847 a2dFillData* d = new a2dFillData( this );
03848 d->CreateLinearGradientBrush(x1, y1, x2, y2, stops);
03849 p.SetRefData(d);
03850 return p;
03851 }
03852
03853 wxGraphicsBrush a2dRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
03854 wxDouble xc, wxDouble yc,
03855 wxDouble radius,
03856 const wxGraphicsGradientStops& stops)
03857 {
03858 wxGraphicsBrush p;
03859 a2dFillData* d = new a2dFillData( this );
03860 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius, stops);
03861 p.SetRefData(d);
03862 return p;
03863 }
03864
03865 #else //wxCHECK_VERSION(2, 9, 1)
03866
03867
03868 wxGraphicsBrush a2dRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
03869 const wxColour&c1, const wxColour&c2)
03870 {
03871 wxGraphicsBrush p;
03872 a2dFillData* d = new a2dFillData( this );
03873 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
03874 p.SetRefData(d);
03875 return p;
03876 }
03877
03878
03879
03880 wxGraphicsBrush a2dRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
03881 const wxColour &oColor, const wxColour &cColor)
03882 {
03883 wxGraphicsBrush p;
03884 a2dFillData* d = new a2dFillData( this );
03885 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
03886 p.SetRefData(d);
03887 return p;
03888 }
03889 #endif //wxCHECK_VERSION(2, 9, 1)
03890
03891
03892 wxGraphicsFont a2dRenderer::CreateFont( const wxFont &font , const wxColour &col )
03893 {
03894 if ( font.Ok() )
03895 {
03896 wxGraphicsFont p;
03897 p.SetRefData(new a2dFontData( this , font, col ));
03898 return p;
03899 }
03900 else
03901 return wxNullGraphicsFont;
03902 }
03903
03904 wxGraphicsFont a2dRenderer::CreateFont( const a2dFont& font )
03905 {
03906 wxGraphicsFont p;
03907 p.SetRefData( new a2dFontData( this, font ));
03908 return p;
03909 }
03910
03911 wxGraphicsBitmap a2dRenderer::CreateBitmap( const wxBitmap& bmp )
03912 {
03913 if ( bmp.Ok() )
03914 {
03915 wxGraphicsBitmap p;
03916 p.SetRefData(new a2dBitmapData( this , bmp ));
03917 return p;
03918 }
03919 else
03920 return wxNullGraphicsBitmap;
03921 }
03922
03923 #if wxCHECK_VERSION(2, 9, 1)
03924 wxGraphicsBitmap a2dRenderer::CreateBitmapFromNativeBitmap( void* bitmap )
03925 {
03926 }
03927 #endif //wxCHECK_VERSION(2, 9, 1)
03928
03929 wxGraphicsBitmap a2dRenderer::CreateBitmap( const wxImage& bmp )
03930 {
03931 if ( bmp.Ok() )
03932 {
03933 wxGraphicsBitmap p;
03934 p.SetRefData(new a2dBitmapData( this , bmp ));
03935 return p;
03936 }
03937 else
03938 return wxNullGraphicsBitmap;
03939 }
03940
03941 wxGraphicsBitmap a2dRenderer::CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
03942 {
03943 wxGraphicsBitmap p;
03944 p.SetRefData( new a2dBitmapData( this , bitmap ) );
03945 return p;
03946 }
03947
03948
03949 #endif // wxART2D_USE_GRAPHICS_CONTEXT
03950
03951