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