KiCad PCB EDA Suite
Loading...
Searching...
No Matches
PNG_plotter.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
23#include <trigo.h>
24#include <wx/image.h>
25
26#include <cmath>
27
28
30 m_surface( nullptr ),
31 m_context( nullptr ),
33 m_width( 0 ),
34 m_height( 0 ),
35 m_antialias( false ),
36 m_backgroundColor( COLOR4D( 0, 0, 0, 0 ) ),
38{
39 // The base class destructor calls fclose() on m_outputFile; ours is unused.
40 m_outputFile = nullptr;
41}
42
43
45{
46 if( m_context )
47 {
48 cairo_destroy( m_context );
49 m_context = nullptr;
50 }
51
52 if( m_surface )
53 {
54 cairo_surface_destroy( m_surface );
55 m_surface = nullptr;
56 }
57}
58
59
60bool PNG_PLOTTER::OpenFile( const wxString& aFullFilename )
61{
62 // The cairo surface accumulates draws in memory; the file is written in EndPlot.
63 m_filename = aFullFilename;
64 m_outputFile = nullptr;
65 return true;
66}
67
68
69bool PNG_PLOTTER::StartPlot( const wxString& aPageNumber )
70{
71 // Cairo image surfaces are limited to INT16_MAX in either dimension. Beyond that, surface
72 // creation returns CAIRO_STATUS_INVALID_SIZE. Reject up front rather than risking a silent
73 // multi-gigabyte allocation that fails late.
74 constexpr int MAX_PNG_DIMENSION = 32767;
75
76 if( m_width <= 0 || m_height <= 0 || m_width > MAX_PNG_DIMENSION || m_height > MAX_PNG_DIMENSION )
77 return false;
78
79 if( m_context )
80 {
81 cairo_destroy( m_context );
82 m_context = nullptr;
83 }
84
85 if( m_surface )
86 {
87 cairo_surface_destroy( m_surface );
88 m_surface = nullptr;
89 }
90
91 m_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, m_width, m_height );
92
93 if( cairo_surface_status( m_surface ) != CAIRO_STATUS_SUCCESS )
94 {
95 cairo_surface_destroy( m_surface );
96 m_surface = nullptr;
97 return false;
98 }
99
100 m_context = cairo_create( m_surface );
101
102 if( cairo_status( m_context ) != CAIRO_STATUS_SUCCESS )
103 {
104 cairo_destroy( m_context );
105 m_context = nullptr;
106 cairo_surface_destroy( m_surface );
107 m_surface = nullptr;
108 return false;
109 }
110
111 cairo_set_antialias( m_context, m_antialias ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE );
112
113 if( m_backgroundColor.a > 0 )
114 {
115 cairo_set_source_rgba( m_context, m_backgroundColor.r, m_backgroundColor.g, m_backgroundColor.b,
117 cairo_paint( m_context );
118 }
119
120 cairo_set_line_cap( m_context, CAIRO_LINE_CAP_ROUND );
121 cairo_set_line_join( m_context, CAIRO_LINE_JOIN_ROUND );
122
123 // Force the SetColor / SetCurrentLineWidth caches to miss on the first call so the new
124 // Cairo context picks up the requested state (the background paint above set the source
125 // colour to m_backgroundColor, so caching "BLACK" from a previous plot would skip the
126 // necessary cairo_set_source_rgba).
129
130 return true;
131}
132
133
135{
136 if( !m_context )
137 return false;
138
139 cairo_surface_flush( m_surface );
140
141 // Two valid usage patterns: OpenFile()+StartPlot()+EndPlot() writes to m_filename here,
142 // while StartPlot()+EndPlot()+SaveFile() leaves rendering in the surface for an explicit
143 // save. Tearing down the surface in EndPlot would break the second pattern. Cleanup
144 // happens at the next StartPlot or in the destructor.
145 if( !m_filename.IsEmpty() )
146 return SaveFile( m_filename );
147
148 return true;
149}
150
151
152bool PNG_PLOTTER::SaveFile( const wxString& aPath )
153{
154 if( !m_surface )
155 return false;
156
157 cairo_status_t status = cairo_surface_write_to_png( m_surface, aPath.ToUTF8().data() );
158
159 return status == CAIRO_STATUS_SUCCESS;
160}
161
162
163void PNG_PLOTTER::SetCurrentLineWidth( int aWidth, void* aData )
164{
165 if( aWidth == m_currentPenWidth )
166 return;
167
168 m_currentPenWidth = aWidth;
169
170 if( m_context )
171 {
172 double deviceWidth = userToDeviceSize( static_cast<double>( aWidth ) );
173 cairo_set_line_width( m_context, deviceWidth > 0 ? deviceWidth : 1.0 );
174 }
175}
176
177
178void PNG_PLOTTER::SetColor( const COLOR4D& aColor )
179{
180 COLOR4D effective;
181
182 if( m_colorMode )
183 {
184 effective = aColor;
185
186 if( m_negativeMode )
187 {
188 effective.r = 1.0 - effective.r;
189 effective.g = 1.0 - effective.g;
190 effective.b = 1.0 - effective.b;
191 }
192 }
193 else
194 {
195 double k = ( aColor == COLOR4D::WHITE ) ? 1.0 : 0.0;
196
197 if( m_negativeMode )
198 k = 1.0 - k;
199
200 effective = COLOR4D( k, k, k, 1.0 );
201 }
202
203 if( effective == m_currentColor )
204 return;
205
206 m_currentColor = effective;
207
208 if( m_context )
209 cairo_set_source_rgba( m_context, effective.r, effective.g, effective.b, effective.a );
210}
211
212
214{
215 if( m_context )
216 cairo_set_operator( m_context, aClear ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_OVER );
217}
218
219
220void PNG_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
221{
222 if( !m_context )
223 return;
224
225 if( aLineStyle == LINE_STYLE::SOLID || aLineStyle == LINE_STYLE::DEFAULT )
226 {
227 cairo_set_dash( m_context, nullptr, 0, 0 );
228 return;
229 }
230
231 // Dash patterns are in device units (pixels), scaled by line width
232 double base = std::max( 1.0, userToDeviceSize( static_cast<double>( aLineWidth ) ) );
233 double dash[6];
234 int num_dashes = 0;
235
236 switch( aLineStyle )
237 {
238 case LINE_STYLE::DASH:
239 dash[0] = 4.0 * base;
240 dash[1] = 2.0 * base;
241 num_dashes = 2;
242 break;
243
244 case LINE_STYLE::DOT:
245 dash[0] = 1.0 * base;
246 dash[1] = 2.0 * base;
247 num_dashes = 2;
248 break;
249
251 dash[0] = 4.0 * base;
252 dash[1] = 2.0 * base;
253 dash[2] = 1.0 * base;
254 dash[3] = 2.0 * base;
255 num_dashes = 4;
256 break;
257
259 dash[0] = 4.0 * base;
260 dash[1] = 2.0 * base;
261 dash[2] = 1.0 * base;
262 dash[3] = 2.0 * base;
263 dash[4] = 1.0 * base;
264 dash[5] = 2.0 * base;
265 num_dashes = 6;
266 break;
267
268 default:
269 cairo_set_dash( m_context, nullptr, 0, 0 );
270 return;
271 }
272
273 cairo_set_dash( m_context, dash, num_dashes, 0 );
274}
275
276
277void PNG_PLOTTER::SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil, double aScale, bool aMirror )
278{
279 m_plotOffset = aOffset;
280 m_IUsPerDecimil = aIusPerDecimil;
281 m_plotScale = aScale;
282 m_plotMirror = aMirror;
283
284 // 10000 decimils per inch; m_dpi pixels per inch.
286}
287
288
289void PNG_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T aFill, int aWidth, int aCornerRadius )
290{
291 if( !m_context )
292 return;
293
294 VECTOR2D start = userToDeviceCoordinates( p1 );
296
297 double x = std::min( start.x, end.x );
298 double y = std::min( start.y, end.y );
299 double width = std::abs( end.x - start.x );
300 double height = std::abs( end.y - start.y );
301
302 if( aFill == FILL_T::NO_FILL )
303 {
304 SetCurrentLineWidth( aWidth );
305 strokeRect( x, y, width, height );
306 }
307 else
308 {
309 fillRect( x, y, width, height );
310 }
311}
312
313
314void PNG_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill, int aWidth )
315{
316 if( !m_context )
317 return;
318
320 double radius = userToDeviceSize( static_cast<double>( aDiameter ) / 2.0 );
321
322 if( aFill == FILL_T::NO_FILL )
323 {
324 SetCurrentLineWidth( aWidth );
326 }
327 else
328 {
330 }
331}
332
333
334void PNG_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle, const EDA_ANGLE& aAngle, double aRadius,
335 FILL_T aFill, int aWidth )
336{
337 if( !m_context )
338 return;
339
340 VECTOR2D center = userToDeviceCoordinates( VECTOR2I( aCenter.x, aCenter.y ) );
341 double deviceRadius = userToDeviceSize( aRadius );
342
343 double startRad = aStartAngle.AsRadians();
344 double endRad = ( aStartAngle + aAngle ).AsRadians();
345
346 if( aAngle.AsDegrees() < 0 )
347 cairo_arc_negative( m_context, center.x, center.y, deviceRadius, startRad, endRad );
348 else
349 cairo_arc( m_context, center.x, center.y, deviceRadius, startRad, endRad );
350
351 if( aFill == FILL_T::NO_FILL )
352 {
353 SetCurrentLineWidth( aWidth );
354 cairo_stroke( m_context );
355 }
356 else
357 {
358 cairo_fill( m_context );
359 }
360}
361
362
363void PNG_PLOTTER::PenTo( const VECTOR2I& aPos, char aPlume )
364{
365 if( !m_context )
366 return;
367
368 VECTOR2D pos = userToDeviceCoordinates( aPos );
369
370 switch( aPlume )
371 {
372 case 'U':
373 cairo_move_to( m_context, pos.x, pos.y );
374 m_penState = 'U';
375 break;
376
377 case 'D':
378 if( m_penState == 'Z' )
379 cairo_move_to( m_context, pos.x, pos.y );
380 else
381 cairo_line_to( m_context, pos.x, pos.y );
382
383 m_penState = 'D';
384 break;
385
386 case 'Z':
387 if( m_penState != 'Z' )
388 {
389 cairo_stroke( m_context );
390 m_penState = 'Z';
391 m_penLastpos.x = -1;
392 m_penLastpos.y = -1;
393 }
394 break;
395 }
396
397 m_penLastpos = VECTOR2I( pos.x, pos.y );
398}
399
400
401void PNG_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill, int aWidth, void* aData )
402{
403 if( !m_context || aCornerList.size() < 2 )
404 return;
405
406 VECTOR2D start = userToDeviceCoordinates( aCornerList[0] );
407 cairo_move_to( m_context, start.x, start.y );
408
409 for( size_t i = 1; i < aCornerList.size(); i++ )
410 {
411 VECTOR2D pt = userToDeviceCoordinates( aCornerList[i] );
412 cairo_line_to( m_context, pt.x, pt.y );
413 }
414
415 if( aFill != FILL_T::NO_FILL )
416 {
417 cairo_close_path( m_context );
418 cairo_fill( m_context );
419 }
420 else
421 {
422 SetCurrentLineWidth( aWidth );
423 cairo_stroke( m_context );
424 }
425}
426
427
428void PNG_PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aScaleFactor )
429{
430 if( !m_context || !aImage.IsOk() )
431 return;
432
433 int imgW = aImage.GetWidth();
434 int imgH = aImage.GetHeight();
435
436 if( imgW == 0 || imgH == 0 )
437 return;
438
439 // wxImage stores RGB data; convert to Cairo's premultiplied native-endian ARGB32.
440 cairo_surface_t* imgSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, imgW, imgH );
441
442 if( cairo_surface_status( imgSurface ) != CAIRO_STATUS_SUCCESS )
443 {
444 cairo_surface_destroy( imgSurface );
445 return;
446 }
447
448 const unsigned char* srcData = aImage.GetData();
449 const unsigned char* alphaData = aImage.HasAlpha() ? aImage.GetAlpha() : nullptr;
450 unsigned char* dstBytes = cairo_image_surface_get_data( imgSurface );
451 int dstStride = cairo_image_surface_get_stride( imgSurface );
452
453 for( int y = 0; y < imgH; y++ )
454 {
455 const unsigned char* srcRow = srcData + y * imgW * 3;
456 const unsigned char* alphaRow = alphaData ? alphaData + y * imgW : nullptr;
457 uint32_t* dstRow = reinterpret_cast<uint32_t*>( dstBytes + y * dstStride );
458
459 if( !alphaRow )
460 {
461 for( int x = 0; x < imgW; x++ )
462 {
463 uint32_t r = srcRow[x * 3 + 0];
464 uint32_t g = srcRow[x * 3 + 1];
465 uint32_t b = srcRow[x * 3 + 2];
466 dstRow[x] = ( 0xFFu << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
467 }
468 }
469 else
470 {
471 for( int x = 0; x < imgW; x++ )
472 {
473 uint32_t r = srcRow[x * 3 + 0];
474 uint32_t g = srcRow[x * 3 + 1];
475 uint32_t b = srcRow[x * 3 + 2];
476 uint32_t a = alphaRow[x];
477
478 if( a < 255 )
479 {
480 r = ( r * a + 127 ) / 255;
481 g = ( g * a + 127 ) / 255;
482 b = ( b * a + 127 ) / 255;
483 }
484
485 dstRow[x] = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
486 }
487 }
488 }
489
490 cairo_surface_mark_dirty( imgSurface );
491
492 VECTOR2D pos = userToDeviceCoordinates( aPos );
493 double drawW = userToDeviceSize( static_cast<double>( imgW ) * aScaleFactor );
494 double drawH = userToDeviceSize( static_cast<double>( imgH ) * aScaleFactor );
495
496 // aPos is the image centre; adjust to top-left for Cairo
497 pos.x -= drawW / 2.0;
498 pos.y -= drawH / 2.0;
499
500 cairo_save( m_context );
501 cairo_translate( m_context, pos.x, pos.y );
502 cairo_scale( m_context, drawW / imgW, drawH / imgH );
503 cairo_set_source_surface( m_context, imgSurface, 0, 0 );
504 cairo_paint( m_context );
505 cairo_restore( m_context );
506
507 cairo_surface_destroy( imgSurface );
508}
509
510
511void PNG_PLOTTER::FlashPadCircle( const VECTOR2I& aPadPos, int aDiameter, void* aData )
512{
513 Circle( aPadPos, aDiameter, FILL_T::FILLED_SHAPE, 0 );
514}
515
516
517void PNG_PLOTTER::FlashPadOval( const VECTOR2I& aPadPos, const VECTOR2I& aSize, const EDA_ANGLE& aPadOrient,
518 void* aData )
519{
520 // An oval is a thick segment between two semicircle centres with round end caps.
521 int width = std::min( aSize.x, aSize.y );
522 int len = std::max( aSize.x, aSize.y ) - width;
523
524 if( len == 0 )
525 {
526 FlashPadCircle( aPadPos, width, aData );
527 return;
528 }
529
531
532 if( aSize.x > aSize.y )
533 {
534 delta.x = len / 2;
535 delta.y = 0;
536 }
537 else
538 {
539 delta.x = 0;
540 delta.y = len / 2;
541 }
542
543 RotatePoint( delta, aPadOrient );
544
545 VECTOR2I start = aPadPos - delta;
546 VECTOR2I end = aPadPos + delta;
547
548 ThickSegment( start, end, width, aData );
549}
550
551
552void PNG_PLOTTER::FlashPadRect( const VECTOR2I& aPadPos, const VECTOR2I& aSize, const EDA_ANGLE& aPadOrient,
553 void* aData )
554{
555 std::vector<VECTOR2I> corners;
556
557 int dx = aSize.x / 2;
558 int dy = aSize.y / 2;
559
560 corners.push_back( VECTOR2I( -dx, -dy ) );
561 corners.push_back( VECTOR2I( -dx, dy ) );
562 corners.push_back( VECTOR2I( dx, dy ) );
563 corners.push_back( VECTOR2I( dx, -dy ) );
564
565 for( VECTOR2I& corner : corners )
566 {
567 RotatePoint( corner, aPadOrient );
568 corner += aPadPos;
569 }
570
571 PlotPoly( corners, FILL_T::FILLED_SHAPE, 0, aData );
572}
573
574
575void PNG_PLOTTER::FlashPadRoundRect( const VECTOR2I& aPadPos, const VECTOR2I& aSize, int aCornerRadius,
576 const EDA_ANGLE& aOrient, void* aData )
577{
578 SHAPE_POLY_SET outline;
579 TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient, aCornerRadius, 0.0, 0, 0,
581
582 if( outline.OutlineCount() > 0 )
583 {
584 const SHAPE_LINE_CHAIN& poly = outline.COutline( 0 );
585 std::vector<VECTOR2I> corners;
586
587 for( int i = 0; i < poly.PointCount(); i++ )
588 corners.push_back( poly.CPoint( i ) );
589
590 PlotPoly( corners, FILL_T::FILLED_SHAPE, 0, aData );
591 }
592}
593
594
595void PNG_PLOTTER::FlashPadCustom( const VECTOR2I& aPadPos, const VECTOR2I& aSize, const EDA_ANGLE& aPadOrient,
596 SHAPE_POLY_SET* aPolygons, void* aData )
597{
598 if( !aPolygons || aPolygons->OutlineCount() == 0 )
599 return;
600
601 for( int i = 0; i < aPolygons->OutlineCount(); i++ )
602 {
603 const SHAPE_LINE_CHAIN& outline = aPolygons->COutline( i );
604 std::vector<VECTOR2I> corners;
605
606 for( int j = 0; j < outline.PointCount(); j++ )
607 corners.push_back( outline.CPoint( j ) );
608
609 PlotPoly( corners, FILL_T::FILLED_SHAPE, 0, aData );
610 }
611}
612
613
614void PNG_PLOTTER::FlashPadTrapez( const VECTOR2I& aPadPos, const VECTOR2I* aCorners, const EDA_ANGLE& aPadOrient,
615 void* aData )
616{
617 std::vector<VECTOR2I> corners;
618
619 for( int i = 0; i < 4; i++ )
620 {
621 VECTOR2I corner = aCorners[i];
622 RotatePoint( corner, aPadOrient );
623 corner += aPadPos;
624 corners.push_back( corner );
625 }
626
627 PlotPoly( corners, FILL_T::FILLED_SHAPE, 0, aData );
628}
629
630
631void PNG_PLOTTER::FlashRegularPolygon( const VECTOR2I& aShapePos, int aDiameter, int aCornerCount,
632 const EDA_ANGLE& aOrient, void* aData )
633{
634 std::vector<VECTOR2I> corners;
635 double radius = aDiameter / 2.0;
636 EDA_ANGLE delta = ANGLE_360 / aCornerCount;
637
638 for( int i = 0; i < aCornerCount; i++ )
639 {
640 EDA_ANGLE angle = aOrient + delta * i;
641 VECTOR2I corner( radius * cos( angle.AsRadians() ), radius * sin( angle.AsRadians() ) );
642 corner += aShapePos;
643 corners.push_back( corner );
644 }
645
646 PlotPoly( corners, FILL_T::FILLED_SHAPE, 0, aData );
647}
648
649
651{
652 VECTOR2D pos( aCoordinate.x, aCoordinate.y );
653
654 pos.x -= m_plotOffset.x;
655 pos.y -= m_plotOffset.y;
656
657 pos.x = pos.x * m_plotScale / m_iuPerDeviceUnit;
658 pos.y = pos.y * m_plotScale / m_iuPerDeviceUnit;
659
660 if( m_plotMirror )
661 pos.x = m_width - pos.x;
662
663 // pcbnew is Y-up, Cairo is Y-down; gerbview already emits Y-down so the caller decides.
664 if( m_yaxisReversed )
665 pos.y = m_height - pos.y;
666
667 return pos;
668}
669
670
672{
673 return VECTOR2D( userToDeviceSize( static_cast<double>( aSize.x ) ),
674 userToDeviceSize( static_cast<double>( aSize.y ) ) );
675}
676
677
678double PNG_PLOTTER::userToDeviceSize( double aSize ) const
679{
680 return std::abs( aSize * m_plotScale / m_iuPerDeviceUnit );
681}
682
683
684void PNG_PLOTTER::fillRect( double aX, double aY, double aWidth, double aHeight )
685{
686 if( !m_context )
687 return;
688
689 cairo_rectangle( m_context, aX, aY, aWidth, aHeight );
690 cairo_fill( m_context );
691}
692
693
694void PNG_PLOTTER::strokeRect( double aX, double aY, double aWidth, double aHeight )
695{
696 if( !m_context )
697 return;
698
699 cairo_rectangle( m_context, aX, aY, aWidth, aHeight );
700 cairo_stroke( m_context );
701}
702
703
704void PNG_PLOTTER::fillCircle( double aCx, double aCy, double aRadius )
705{
706 if( !m_context )
707 return;
708
709 cairo_arc( m_context, aCx, aCy, aRadius, 0, 2 * M_PI );
710 cairo_fill( m_context );
711}
712
713
714void PNG_PLOTTER::strokeCircle( double aCx, double aCy, double aRadius )
715{
716 if( !m_context )
717 return;
718
719 cairo_arc( m_context, aCx, aCy, aRadius, 0, 2 * M_PI );
720 cairo_stroke( m_context );
721}
@ ERROR_INSIDE
static const COLOR4D WHITE
Definition color4d.h:405
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
double AsDegrees() const
Definition eda_angle.h:116
double AsRadians() const
Definition eda_angle.h:120
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
double r
Red component.
Definition color4d.h:393
double g
Green component.
Definition color4d.h:394
double a
Alpha component.
Definition color4d.h:396
double b
Blue component.
Definition color4d.h:395
bool m_plotMirror
Definition plotter.h:701
bool m_yaxisReversed
Definition plotter.h:704
double m_iuPerDeviceUnit
Definition plotter.h:698
VECTOR2I m_plotOffset
Definition plotter.h:700
VECTOR2I m_penLastpos
Definition plotter.h:714
int GetPlotterArcHighDef() const
Definition plotter.h:275
char m_penState
Definition plotter.h:713
int m_currentPenWidth
Definition plotter.h:712
double m_plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition plotter.h:690
FILE * m_outputFile
Output file.
Definition plotter.h:707
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:540
bool m_negativeMode
Definition plotter.h:711
double m_IUsPerDecimil
Definition plotter.h:696
bool m_colorMode
Definition plotter.h:710
wxString m_filename
Definition plotter.h:717
virtual void SetCurrentLineWidth(int aWidth, void *aData=nullptr) override
Set the line width for the next drawing.
void fillCircle(double aCx, double aCy, double aRadius)
virtual void FlashPadRect(const VECTOR2I &aPadPos, const VECTOR2I &aSize, const EDA_ANGLE &aPadOrient, void *aData) override
cairo_surface_t * m_surface
virtual void PenTo(const VECTOR2I &aPos, char aPlume) override
Moveto/lineto primitive, moves the 'pen' to the specified direction.
virtual ~PNG_PLOTTER()
virtual void FlashRegularPolygon(const VECTOR2I &aShapePos, int aDiameter, int aCornerCount, const EDA_ANGLE &aOrient, void *aData) override
Flash a regular polygon.
virtual void SetDash(int aLineWidth, LINE_STYLE aLineStyle) override
virtual void Circle(const VECTOR2I &aCenter, int aDiameter, FILL_T aFill, int aWidth) override
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T aFill, int aWidth, int aCornerRadius=0) override
virtual void Arc(const VECTOR2D &aCenter, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aRadius, FILL_T aFill, int aWidth) override
bool SaveFile(const wxString &aPath)
Save the rendered image to a PNG file.
virtual void FlashPadOval(const VECTOR2I &aPadPos, const VECTOR2I &aSize, const EDA_ANGLE &aPadOrient, void *aData) override
COLOR4D m_currentColor
virtual bool EndPlot() override
COLOR4D m_backgroundColor
virtual VECTOR2D userToDeviceCoordinates(const VECTOR2I &aCoordinate) override
Transform coordinates from user space (IU) to device space (pixels).
void fillRect(double aX, double aY, double aWidth, double aHeight)
cairo_t * m_context
void strokeCircle(double aCx, double aCy, double aRadius)
virtual void FlashPadCircle(const VECTOR2I &aPadPos, int aDiameter, void *aData) override
virtual void SetColor(const COLOR4D &aColor) override
virtual void FlashPadTrapez(const VECTOR2I &aPadPos, const VECTOR2I *aCorners, const EDA_ANGLE &aPadOrient, void *aData) override
Flash a trapezoidal pad.
virtual void FlashPadRoundRect(const VECTOR2I &aPadPos, const VECTOR2I &aSize, int aCornerRadius, const EDA_ANGLE &aOrient, void *aData) override
virtual VECTOR2D userToDeviceSize(const VECTOR2I &aSize) override
Transform a size from user space to device space.
virtual void FlashPadCustom(const VECTOR2I &aPadPos, const VECTOR2I &aSize, const EDA_ANGLE &aPadOrient, SHAPE_POLY_SET *aPolygons, void *aData) override
virtual bool OpenFile(const wxString &aFullFilename) override
Open or create the plot file aFullFilename.
void strokeRect(double aX, double aY, double aWidth, double aHeight)
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth, void *aData=nullptr) override
Draw a polygon ( filled or not ).
void SetClearCompositing(bool aClear)
Switch the Cairo compositing operator between CLEAR and OVER.
virtual void PlotImage(const wxImage &aImage, const VECTOR2I &aPos, double aScaleFactor) override
Only PostScript plotters can plot bitmaps.
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
virtual bool StartPlot(const wxString &aPageNumber) override
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
@ BLACK
Definition color4d.h:44
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle with rounded corners and/or chamfered corners to a polygon.
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
FILL_T
Definition eda_shape.h:59
@ NO_FILL
Definition eda_shape.h:60
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:61
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
constexpr int DEFAULT_PNG_DPI
Definition plotter_png.h:28
LINE_STYLE
Dashed line types.
VECTOR2I center
int radius
VECTOR2I end
int delta
#define M_PI
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686