KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
40#include <trigo.h>
41#include <plotters/plotter.h>
43#include <bezier_curves.h>
44#include <callback_gal.h>
45#include <math/util.h> // for KiROUND
46
48{
49 m_plotScale = 1;
50 m_currentPenWidth = -1; // To-be-set marker
51 m_penState = 'Z'; // End-of-path idle
52 m_plotMirror = false; // Plot mirror option flag
54 m_yaxisReversed = false;
55 m_outputFile = nullptr;
56 m_colorMode = false; // Starts as a BW plot
57 m_negativeMode = false;
58
59 // Temporary init to avoid not initialized vars, will be set later
60 m_IUsPerDecimil = 1; // will be set later to the actual value
61 m_iuPerDeviceUnit = 1; // will be set later to the actual value
62 m_renderSettings = nullptr;
63}
64
65
67{
68 // Emergency cleanup, but closing the file is usually made in EndPlot().
69 if( m_outputFile )
70 fclose( m_outputFile );
71}
72
73
74bool PLOTTER::OpenFile( const wxString& aFullFilename )
75{
76 m_filename = aFullFilename;
77
78 wxASSERT( !m_outputFile );
79
80 // Open the file in text mode (not suitable for all plotters but only for most of them.
81 m_outputFile = wxFopen( m_filename, wxT( "wt" ) );
82
83 if( m_outputFile == nullptr )
84 return false ;
85
86 return true;
87}
88
89
91{
92 VECTOR2I pos = aCoordinate - m_plotOffset;
93
94 double x = pos.x * m_plotScale;
95 double y = ( m_paperSize.y - pos.y * m_plotScale );
96
97 if( m_plotMirror )
98 {
100 x = ( m_paperSize.x - pos.x * m_plotScale );
101 else
102 y = pos.y * m_plotScale;
103 }
104
105 if( m_yaxisReversed )
106 y = m_paperSize.y - y;
107
110
111 return VECTOR2D( x, y );
112}
113
114
116{
117 return VECTOR2D( size.x * m_plotScale * m_iuPerDeviceUnit,
119}
120
121
122double PLOTTER::userToDeviceSize( double size ) const
123{
124 return size * m_plotScale * m_iuPerDeviceUnit;
125}
126
127
128#define IU_PER_MILS ( m_IUsPerDecimil * 10 )
129
130
131double PLOTTER::GetDotMarkLenIU( int aLineWidth ) const
132{
133 return userToDeviceSize( m_renderSettings->GetDotLength( aLineWidth ) );
134}
135
136
137double PLOTTER::GetDashMarkLenIU( int aLineWidth ) const
138{
139 return userToDeviceSize( m_renderSettings->GetDashLength( aLineWidth ) );
140}
141
142
143double PLOTTER::GetDashGapLenIU( int aLineWidth ) const
144{
145 return userToDeviceSize( m_renderSettings->GetGapLength( aLineWidth ) );
146}
147
148#include <wx/log.h>
149void PLOTTER::Arc( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd, FILL_T aFill,
150 int aWidth )
151{
152 VECTOR2D aCenter = CalcArcCenter( aStart, aMid, aEnd );
153
154 EDA_ANGLE startAngle( aStart - aCenter );
155 EDA_ANGLE endAngle( aEnd - aCenter );
156
157 // < 0: left, 0 : on the line, > 0 : right
158 double det = ( aEnd - aStart ).Cross( aMid - aStart );
159
160 int cw = det <= 0;
161 EDA_ANGLE angle = endAngle - startAngle;
162
163 if( cw )
164 angle.Normalize();
165 else
166 angle.NormalizeNegative();
167
168 double radius = ( aStart - aCenter ).EuclideanNorm();
169 Arc( aCenter, startAngle, angle, radius, aFill, aWidth );
170}
171
172
173void PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle, const EDA_ANGLE& aAngle,
174 double aRadius, FILL_T aFill, int aWidth )
175{
176 polyArc( aCenter, aStartAngle, aAngle, aRadius, aFill, aWidth );
177}
178
179
180void PLOTTER::polyArc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
181 const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill, int aWidth )
182{
183 EDA_ANGLE startAngle = aStartAngle;
184 EDA_ANGLE endAngle = startAngle + aAngle;
185 const EDA_ANGLE delta( 5.0, DEGREES_T ); // increment to draw arc
186 VECTOR2I start, end;
187 const int sign = 1;
188
189 if( aAngle < ANGLE_0 )
190 std::swap( startAngle, endAngle );
191
192 SetCurrentLineWidth( aWidth );
193
194 start.x = KiROUND( aCenter.x + aRadius * startAngle.Cos() );
195 start.y = KiROUND( aCenter.y + sign * aRadius * startAngle.Sin() );
196
197 if( aFill != FILL_T::NO_FILL )
198 {
199 MoveTo( aCenter );
200 LineTo( start );
201 }
202 else
203 {
204 MoveTo( start );
205 }
206
207 for( EDA_ANGLE ii = startAngle + delta; ii < endAngle; ii += delta )
208 {
209 end.x = KiROUND( aCenter.x + aRadius * ii.Cos() );
210 end.y = KiROUND( aCenter.y + sign * aRadius * ii.Sin() );
211 LineTo( end );
212 }
213
214 end.x = KiROUND( aCenter.x + aRadius * endAngle.Cos() );
215 end.y = KiROUND( aCenter.y + sign * aRadius * endAngle.Sin() );
216
217 if( aFill != FILL_T::NO_FILL )
218 {
219 LineTo( end );
220 FinishTo( aCenter );
221 }
222 else
223 {
224 FinishTo( end );
225 }
226}
227
228
229void PLOTTER::BezierCurve( const VECTOR2I& aStart, const VECTOR2I& aControl1,
230 const VECTOR2I& aControl2, const VECTOR2I& aEnd,
231 int aTolerance, int aLineThickness )
232{
233 // Generic fallback: Quadratic Bezier curve plotted as a polyline
234
235 std::vector<VECTOR2I> ctrlPoints;
236 ctrlPoints.reserve( 4 );
237
238 ctrlPoints.push_back( aStart );
239 ctrlPoints.push_back( aControl1 );
240 ctrlPoints.push_back( aControl2 );
241 ctrlPoints.push_back( aEnd );
242
243 BEZIER_POLY bezier_converter( ctrlPoints );
244
245 std::vector<VECTOR2I> approxPoints;
246 bezier_converter.GetPoly( approxPoints, aTolerance );
247
248 SetCurrentLineWidth( aLineThickness );
249 MoveTo( aStart );
250
251 for( unsigned ii = 1; ii < approxPoints.size()-1; ii++ )
252 LineTo( approxPoints[ii] );
253
254 FinishTo( aEnd );
255}
256
257
258void PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aScaleFactor )
259{
260 VECTOR2I size( aImage.GetWidth() * aScaleFactor, aImage.GetHeight() * aScaleFactor );
261
262 VECTOR2I start = aPos;
263 start.x -= size.x / 2;
264 start.y -= size.y / 2;
265
266 VECTOR2I end = start;
267 end.x += size.x;
268 end.y += size.y;
269
270 Rect( start, end, FILL_T::NO_FILL );
271}
272
273
274void PLOTTER::markerSquare( const VECTOR2I& position, int radius )
275{
276 double r = KiROUND( radius / 1.4142 );
277 std::vector<VECTOR2I> corner_list;
278 VECTOR2I corner;
279
280 corner_list.reserve( 4 );
281
282 corner.x = position.x + r;
283 corner.y = position.y + r;
284 corner_list.push_back( corner );
285 corner.x = position.x + r;
286 corner.y = position.y - r;
287 corner_list.push_back( corner );
288 corner.x = position.x - r;
289 corner.y = position.y - r;
290 corner_list.push_back( corner );
291 corner.x = position.x - r;
292 corner.y = position.y + r;
293 corner_list.push_back( corner );
294 corner.x = position.x + r;
295 corner.y = position.y + r;
296 corner_list.push_back( corner );
297
298 PlotPoly( corner_list, FILL_T::NO_FILL, GetCurrentLineWidth() );
299}
300
301
302void PLOTTER::markerCircle( const VECTOR2I& position, int radius )
303{
304 Circle( position, radius * 2, FILL_T::NO_FILL, GetCurrentLineWidth() );
305}
306
307
308void PLOTTER::markerLozenge( const VECTOR2I& position, int radius )
309{
310 std::vector<VECTOR2I> corner_list;
311 VECTOR2I corner;
312
313 corner_list.reserve( 4 );
314
315 corner.x = position.x;
316 corner.y = position.y + radius;
317 corner_list.push_back( corner );
318 corner.x = position.x + radius;
319 corner.y = position.y,
320 corner_list.push_back( corner );
321 corner.x = position.x;
322 corner.y = position.y - radius;
323 corner_list.push_back( corner );
324 corner.x = position.x - radius;
325 corner.y = position.y;
326 corner_list.push_back( corner );
327 corner.x = position.x;
328 corner.y = position.y + radius;
329 corner_list.push_back( corner );
330
331 PlotPoly( corner_list, FILL_T::NO_FILL, GetCurrentLineWidth() );
332}
333
334
335void PLOTTER::markerHBar( const VECTOR2I& pos, int radius )
336{
337 MoveTo( VECTOR2I( pos.x - radius, pos.y ) );
338 FinishTo( VECTOR2I( pos.x + radius, pos.y ) );
339}
340
341
342void PLOTTER::markerSlash( const VECTOR2I& pos, int radius )
343{
344 MoveTo( VECTOR2I( pos.x - radius, pos.y - radius ) );
345 FinishTo( VECTOR2I( pos.x + radius, pos.y + radius ) );
346}
347
348
349void PLOTTER::markerBackSlash( const VECTOR2I& pos, int radius )
350{
351 MoveTo( VECTOR2I( pos.x + radius, pos.y - radius ) );
352 FinishTo( VECTOR2I( pos.x - radius, pos.y + radius ) );
353}
354
355
356void PLOTTER::markerVBar( const VECTOR2I& pos, int radius )
357{
358 MoveTo( VECTOR2I( pos.x, pos.y - radius ) );
359 FinishTo( VECTOR2I( pos.x, pos.y + radius ) );
360}
361
362
363void PLOTTER::Marker( const VECTOR2I& position, int diametre, unsigned aShapeId )
364{
365 int radius = diametre / 2;
366
367 /* Marker are composed by a series of 'parts' superimposed; not every
368 combination make sense, obviously. Since they are used in order I
369 tried to keep the uglier/more complex constructions at the end.
370 Also I avoided the |/ |\ -/ -\ construction because they're *very*
371 ugly... if needed they could be added anyway... I'd like to see
372 a board with more than 58 drilling/slotting tools!
373 If Visual C++ supported the 0b literals they would be optimally
374 and easily encoded as an integer array. We have to do with octal */
375 static const unsigned char marker_patterns[MARKER_COUNT] = {
376
377 // Bit order: O Square Lozenge - | \ /
378 // First choice: simple shapes
379 0003, // X
380 0100, // O
381 0014, // +
382 0040, // Sq
383 0020, // Lz
384
385 // Two simple shapes
386 0103, // X O
387 0017, // X +
388 0043, // X Sq
389 0023, // X Lz
390 0114, // O +
391 0140, // O Sq
392 0120, // O Lz
393 0054, // + Sq
394 0034, // + Lz
395 0060, // Sq Lz
396
397 // Three simple shapes
398 0117, // X O +
399 0143, // X O Sq
400 0123, // X O Lz
401 0057, // X + Sq
402 0037, // X + Lz
403 0063, // X Sq Lz
404 0154, // O + Sq
405 0134, // O + Lz
406 0074, // + Sq Lz
407
408 // Four simple shapes
409 0174, // O Sq Lz +
410 0163, // X O Sq Lz
411 0157, // X O Sq +
412 0137, // X O Lz +
413 0077, // X Sq Lz +
414
415 // This draws *everything *
416 0177, // X O Sq Lz +
417
418 // Here we use the single bars... so the cross is forbidden
419 0110, // O -
420 0104, // O |
421 0101, // O /
422 0050, // Sq -
423 0044, // Sq |
424 0041, // Sq /
425 0030, // Lz -
426 0024, // Lz |
427 0021, // Lz /
428 0150, // O Sq -
429 0144, // O Sq |
430 0141, // O Sq /
431 0130, // O Lz -
432 0124, // O Lz |
433 0121, // O Lz /
434 0070, // Sq Lz -
435 0064, // Sq Lz |
436 0061, // Sq Lz /
437 0170, // O Sq Lz -
438 0164, // O Sq Lz |
439 0161, // O Sq Lz /
440
441 // Last resort: the backlash component (easy to confound)
442 0102, // \ O
443 0042, // \ Sq
444 0022, // \ Lz
445 0142, // \ O Sq
446 0122, // \ O Lz
447 0062, // \ Sq Lz
448 0162 // \ O Sq Lz
449 };
450
451 if( aShapeId >= MARKER_COUNT )
452 {
453 // Fallback shape
454 markerCircle( position, radius );
455 }
456 else
457 {
458 // Decode the pattern and draw the corresponding parts
459 unsigned char pat = marker_patterns[aShapeId];
460
461 if( pat & 0001 )
462 markerSlash( position, radius );
463
464 if( pat & 0002 )
465 markerBackSlash( position, radius );
466
467 if( pat & 0004 )
468 markerVBar( position, radius );
469
470 if( pat & 0010 )
471 markerHBar( position, radius );
472
473 if( pat & 0020 )
474 markerLozenge( position, radius );
475
476 if( pat & 0040 )
477 markerSquare( position, radius );
478
479 if( pat & 0100 )
480 markerCircle( position, radius );
481 }
482}
483
484
485void PLOTTER::segmentAsOval( const VECTOR2I& start, const VECTOR2I& end, int aWidth,
486 OUTLINE_MODE aTraceMode )
487{
488 VECTOR2I center( ( start.x + end.x ) / 2, ( start.y + end.y ) / 2 );
489 VECTOR2I size( end.x - start.x, end.y - start.y );
490 EDA_ANGLE orient( size );
491 orient = -orient; // this is due to our Y axis orientation
492
493 size.x = size.EuclideanNorm() + aWidth;
494 size.y = aWidth;
495
496 FlashPadOval( center, size, orient, aTraceMode, nullptr );
497}
498
499
500void PLOTTER::sketchOval( const VECTOR2I& aPos, const VECTOR2I& aSize, const EDA_ANGLE& aOrient,
501 int aWidth )
502{
503 SetCurrentLineWidth( aWidth );
504
505 EDA_ANGLE orient( aOrient );
506 VECTOR2I size( aSize );
507
508 if( size.x > size.y )
509 {
510 std::swap( size.x, size.y );
511 orient += ANGLE_90;
512 }
513
514 int deltaxy = size.y - size.x; /* distance between centers of the oval */
515 int radius = size.x / 2;
516
517 // Build a vertical oval shape giving the start and end points of arcs and edges,
518 // and the middle point of arcs
519 std::vector<VECTOR2I> corners;
520 corners.reserve( 6 );
521 // Shape is (x = corner and arc ends, c = arc centre)
522 // xcx
523 //
524 // xcx
525 int half_height = deltaxy / 2;
526 corners.emplace_back( -radius, -half_height );
527 corners.emplace_back( -radius, half_height );
528 corners.emplace_back( 0, half_height );
529 corners.emplace_back( radius, half_height );
530 corners.emplace_back( radius, -half_height );
531 corners.emplace_back( 0, -half_height );
532
533 // Rotate and move to the actual position
534 for( size_t ii = 0; ii < corners.size(); ii++ )
535 {
536 RotatePoint( corners[ii], orient );
537 corners[ii] += aPos;
538 }
539
540 // Gen shape (2 lines and 2 180 deg arcs):
541 MoveTo( corners[0] );
542 FinishTo( corners[1] );
543
544 Arc( corners[2], -orient, ANGLE_180, radius, FILL_T::NO_FILL );
545
546 MoveTo( corners[3] );
547 FinishTo( corners[4] );
548
549 Arc( corners[5], -orient, -ANGLE_180, radius, FILL_T::NO_FILL );
550}
551
552
553void PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end, int width,
554 OUTLINE_MODE tracemode, void* aData )
555{
556 if( tracemode == FILLED )
557 {
558 if( start == end )
559 {
560 Circle( start, width, FILL_T::FILLED_SHAPE, 0 );
561 }
562 else
563 {
564 SetCurrentLineWidth( width );
565 MoveTo( start );
566 FinishTo( end );
567 }
568 }
569 else
570 {
572 segmentAsOval( start, end, width, tracemode );
573 }
574}
575
576
577void PLOTTER::ThickArc( const VECTOR2D& centre, const EDA_ANGLE& aStartAngle,
578 const EDA_ANGLE& aAngle, double aRadius, int aWidth,
579 OUTLINE_MODE aTraceMode, void* aData )
580{
581 if( aTraceMode == FILLED )
582 {
583 Arc( centre, aStartAngle, aAngle, aRadius, FILL_T::NO_FILL, aWidth );
584 }
585 else
586 {
588 Arc( centre, aStartAngle, aAngle, aRadius - ( aWidth - m_currentPenWidth ) / 2,
589 FILL_T::NO_FILL, -1 );
590 Arc( centre, aStartAngle, aAngle, aRadius + ( aWidth - m_currentPenWidth ) / 2,
591 FILL_T::NO_FILL, -1 );
592 }
593}
594
595
596void PLOTTER::ThickArc( const EDA_SHAPE& aArcShape, OUTLINE_MODE aTraceMode, void* aData )
597{
598 VECTOR2D center = aArcShape.getCenter();
599 VECTOR2D mid = aArcShape.GetArcMid();
600 VECTOR2D start = aArcShape.GetStart();
601 VECTOR2D end = aArcShape.GetEnd();
602
603 EDA_ANGLE startAngle( start - center );
604 EDA_ANGLE endAngle( end - center );
605 EDA_ANGLE angle = endAngle - startAngle;
606
607 // < 0: left, 0 : on the line, > 0 : right
608 double det = ( end - start ).Cross( mid - start );
609
610 if( det <= 0 ) // cw
611 angle.Normalize();
612 else
613 angle.NormalizeNegative();
614
615 double radius = ( start - center ).EuclideanNorm();
616
617 ThickArc( center, startAngle, angle, radius, aArcShape.GetWidth(), aTraceMode, aData );
618}
619
620
621void PLOTTER::ThickRect( const VECTOR2I& p1, const VECTOR2I& p2, int width,
622 OUTLINE_MODE tracemode, void* aData )
623{
624 if( tracemode == FILLED )
625 {
626 Rect( p1, p2, FILL_T::NO_FILL, width );
627 }
628 else
629 {
631 VECTOR2I offsetp1( p1.x - ( width - m_currentPenWidth ) / 2,
632 p1.y - (width - m_currentPenWidth) / 2 );
633 VECTOR2I offsetp2( p2.x + ( width - m_currentPenWidth ) / 2,
634 p2.y + (width - m_currentPenWidth) / 2 );
635 Rect( offsetp1, offsetp2, FILL_T::NO_FILL, -1 );
636 offsetp1.x += ( width - m_currentPenWidth );
637 offsetp1.y += ( width - m_currentPenWidth );
638 offsetp2.x -= ( width - m_currentPenWidth );
639 offsetp2.y -= ( width - m_currentPenWidth );
640 Rect( offsetp1, offsetp2, FILL_T::NO_FILL, -1 );
641 }
642}
643
644
645void PLOTTER::ThickCircle( const VECTOR2I& pos, int diametre, int width, OUTLINE_MODE tracemode,
646 void* aData )
647{
648 if( tracemode == FILLED )
649 {
650 Circle( pos, diametre, FILL_T::NO_FILL, width );
651 }
652 else
653 {
655 Circle( pos, diametre - width + m_currentPenWidth, FILL_T::NO_FILL, -1 );
656 Circle( pos, diametre + width - m_currentPenWidth, FILL_T::NO_FILL, -1 );
657 }
658}
659
660
661void PLOTTER::FilledCircle( const VECTOR2I& pos, int diametre, OUTLINE_MODE tracemode, void* aData )
662{
663 if( tracemode == FILLED )
664 {
665 Circle( pos, diametre, FILL_T::FILLED_SHAPE, 0 );
666 }
667 else
668 {
670 Circle( pos, diametre, FILL_T::NO_FILL, -1 );
671 }
672}
673
674
675void PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int aWidth, void* aData )
676{
677 std::vector<VECTOR2I> cornerList;
678 cornerList.reserve( aCornerList.PointCount() );
679
680 for( int ii = 0; ii < aCornerList.PointCount(); ii++ )
681 cornerList.emplace_back( aCornerList.CPoint( ii ) );
682
683 if( aCornerList.IsClosed() && cornerList.front() != cornerList.back() )
684 cornerList.emplace_back( aCornerList.CPoint( 0 ) );
685
686 PlotPoly( cornerList, aFill, aWidth, aData );
687}
688
689
690void PLOTTER::Text( const VECTOR2I& aPos,
691 const COLOR4D& aColor,
692 const wxString& aText,
693 const EDA_ANGLE& aOrient,
694 const VECTOR2I& aSize,
695 enum GR_TEXT_H_ALIGN_T aH_justify,
696 enum GR_TEXT_V_ALIGN_T aV_justify,
697 int aPenWidth,
698 bool aItalic,
699 bool aBold,
700 bool aMultilineAllowed,
701 KIFONT::FONT* aFont,
702 const KIFONT::METRICS& aFontMetrics,
703 void* aData )
704{
706
707 SetColor( aColor );
708
709 if( aPenWidth == 0 && aBold ) // Use default values if aPenWidth == 0
710 aPenWidth = GetPenSizeForBold( std::min( aSize.x, aSize.y ) );
711
712 if( aPenWidth < 0 )
713 aPenWidth = -aPenWidth;
714
715 CALLBACK_GAL callback_gal( empty_opts,
716 // Stroke callback
717 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
718 {
719 SetCurrentLineWidth( aPenWidth );
720 MoveTo( aPt1 );
721 LineTo( aPt2 );
722 PenFinish();
723 },
724 // Polygon callback
725 [&]( const SHAPE_LINE_CHAIN& aPoly )
726 {
727 PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, aData );
728 } );
729
730 TEXT_ATTRIBUTES attributes;
731 attributes.m_Angle = aOrient;
732 attributes.m_StrokeWidth = aPenWidth;
733 attributes.m_Italic = aItalic;
734 attributes.m_Bold = aBold;
735 attributes.m_Halign = aH_justify;
736 attributes.m_Valign = aV_justify;
737 attributes.m_Size = aSize;
738
739 // if Size.x is < 0, the text is mirrored (we have no other param to know a text is mirrored)
740 if( attributes.m_Size.x < 0 )
741 {
742 attributes.m_Size.x = -attributes.m_Size.x;
743 attributes.m_Mirrored = true;
744 }
745
746 if( !aFont )
747 aFont = KIFONT::FONT::GetFont();
748
749 aFont->Draw( &callback_gal, aText, aPos, attributes, aFontMetrics );
750}
751
752void PLOTTER::PlotText( const VECTOR2I& aPos,
753 const COLOR4D& aColor,
754 const wxString& aText,
755 const TEXT_ATTRIBUTES& aAttributes,
756 KIFONT::FONT* aFont,
757 const KIFONT::METRICS& aFontMetrics,
758 void* aData )
759{
761
762 TEXT_ATTRIBUTES attributes = aAttributes;
763 int penWidth = attributes.m_StrokeWidth;
764
765 SetColor( aColor );
766 SetCurrentLineWidth( penWidth, aData );
767
768 if( penWidth == 0 && attributes.m_Bold ) // Use default values if aPenWidth == 0
769 penWidth = GetPenSizeForBold( std::min( attributes.m_Size.x, attributes.m_Size.y ) );
770
771 if( penWidth < 0 )
772 penWidth = -penWidth;
773
774 attributes.m_StrokeWidth = penWidth;
775
776 CALLBACK_GAL callback_gal( empty_opts,
777 // Stroke callback
778 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
779 {
780 MoveTo( aPt1 );
781 LineTo( aPt2 );
782 PenFinish();
783 },
784 // Polygon callback
785 [&]( const SHAPE_LINE_CHAIN& aPoly )
786 {
787 PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, aData );
788 } );
789
790 if( !aFont )
791 aFont = KIFONT::FONT::GetFont();
792
793 aFont->Draw( &callback_gal, aText, aPos, attributes, aFontMetrics );
794}
Bezier curves to polygon converter.
Definition: bezier_curves.h:38
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
EDA_ANGLE Normalize()
Definition: eda_angle.h:221
EDA_ANGLE NormalizeNegative()
Definition: eda_angle.h:238
double Sin() const
Definition: eda_angle.h:170
double Cos() const
Definition: eda_angle.h:189
VECTOR2I getCenter() const
Definition: eda_shape.cpp:538
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:130
virtual int GetWidth() const
Definition: eda_shape.h:115
VECTOR2I GetArcMid() const
Definition: eda_shape.cpp:582
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:131
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics) const
Draw a string.
Definition: font.cpp:257
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr)
Definition: font.cpp:146
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
double GetGapLength(int aLineWidth) const
double GetDotLength(int aLineWidth) const
double GetDashLength(int aLineWidth) const
double GetDotMarkLenIU(int aLineWidth) const
Definition: plotter.cpp:131
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:553
virtual void PlotImage(const wxImage &aImage, const VECTOR2I &aPos, double aScaleFactor)
Only PostScript plotters can plot bitmaps.
Definition: plotter.cpp:258
virtual void ThickRect(const VECTOR2I &p1, const VECTOR2I &p2, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:621
virtual void ThickCircle(const VECTOR2I &pos, int diametre, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:645
static const unsigned MARKER_COUNT
Draw a marker (used for the drill map).
Definition: plotter.h:485
double GetDashGapLenIU(int aLineWidth) const
Definition: plotter.cpp:143
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition: plotter.cpp:74
bool m_mirrorIsHorizontal
Definition: plotter.h:658
PLOTTER()
Definition: plotter.cpp:47
virtual void Arc(const VECTOR2D &aStart, const VECTOR2D &aMid, const VECTOR2D &aEnd, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH)
Definition: plotter.cpp:149
bool m_plotMirror
Definition: plotter.h:656
virtual void FilledCircle(const VECTOR2I &pos, int diametre, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:661
virtual void polyArc(const VECTOR2D &aCentre, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aRadius, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH)
Generic fallback: arc rendered as a polyline.
Definition: plotter.cpp:180
void MoveTo(const VECTOR2I &pos)
Definition: plotter.h:244
void markerSlash(const VECTOR2I &pos, int radius)
Plot a / bar centered on the position.
Definition: plotter.cpp:342
void FinishTo(const VECTOR2I &pos)
Definition: plotter.h:254
virtual void BezierCurve(const VECTOR2I &aStart, const VECTOR2I &aControl1, const VECTOR2I &aControl2, const VECTOR2I &aEnd, int aTolerance, int aLineThickness=USE_DEFAULT_LINE_WIDTH)
Generic fallback: Cubic Bezier curve rendered as a polyline In KiCad the bezier curves have 4 control...
Definition: plotter.cpp:229
bool m_yaxisReversed
Definition: plotter.h:659
double m_iuPerDeviceUnit
Definition: plotter.h:653
VECTOR2I m_plotOffset
Definition: plotter.h:655
virtual VECTOR2D userToDeviceCoordinates(const VECTOR2I &aCoordinate)
Modify coordinates according to the orientation, scale factor, and offsets trace.
Definition: plotter.cpp:90
virtual ~PLOTTER()
Definition: plotter.cpp:66
VECTOR2I m_paperSize
Definition: plotter.h:677
virtual VECTOR2D userToDeviceSize(const VECTOR2I &size)
Modify size according to the plotter scale factors (VECTOR2I version, returns a VECTOR2D).
Definition: plotter.cpp:115
void sketchOval(const VECTOR2I &aPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, int aWidth)
Definition: plotter.cpp:500
char m_penState
Definition: plotter.h:668
void Marker(const VECTOR2I &position, int diametre, unsigned aShapeId)
Draw a pattern shape number aShapeId, to coord position.
Definition: plotter.cpp:363
void markerHBar(const VECTOR2I &pos, int radius)
Plot a - bar centered on the position.
Definition: plotter.cpp:335
int m_currentPenWidth
Definition: plotter.h:667
double m_plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plotter.h:645
void markerCircle(const VECTOR2I &pos, int radius)
Plot a circle centered on the position.
Definition: plotter.cpp:302
virtual void ThickArc(const EDA_SHAPE &aArcShape, OUTLINE_MODE aTraceMode, void *aData)
Definition: plotter.cpp:596
FILE * m_outputFile
Output file.
Definition: plotter.h:662
virtual void SetCurrentLineWidth(int width, void *aData=nullptr)=0
Set the line width for the next drawing.
void LineTo(const VECTOR2I &pos)
Definition: plotter.h:249
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=nullptr)=0
Draw a polygon ( filled or not ).
void PenFinish()
Definition: plotter.h:260
virtual void PlotText(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const TEXT_ATTRIBUTES &aAttributes, KIFONT::FONT *aFont=nullptr, const KIFONT::METRICS &aFontMetrics=KIFONT::METRICS::Default(), void *aData=nullptr)
Definition: plotter.cpp:752
void markerLozenge(const VECTOR2I &position, int radius)
Plot a lozenge centered on the position.
Definition: plotter.cpp:308
RENDER_SETTINGS * m_renderSettings
Definition: plotter.h:681
virtual void Text(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const EDA_ANGLE &aOrient, const VECTOR2I &aSize, enum GR_TEXT_H_ALIGN_T aH_justify, enum GR_TEXT_V_ALIGN_T aV_justify, int aPenWidth, bool aItalic, bool aBold, bool aMultilineAllowed, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, void *aData=nullptr)
Draw text with the plotter.
Definition: plotter.cpp:690
void markerBackSlash(const VECTOR2I &pos, int radius)
Plot a \ bar centered on the position.
Definition: plotter.cpp:349
virtual void FlashPadOval(const VECTOR2I &aPadPos, const VECTOR2I &aSize, const EDA_ANGLE &aPadOrient, OUTLINE_MODE aTraceMode, void *aData)=0
void segmentAsOval(const VECTOR2I &start, const VECTOR2I &end, int width, OUTLINE_MODE tracemode)
Convert a thick segment and plot it as an oval.
Definition: plotter.cpp:485
bool m_negativeMode
Definition: plotter.h:666
double m_IUsPerDecimil
Definition: plotter.h:651
void markerVBar(const VECTOR2I &pos, int radius)
Plot a | bar centered on the position.
Definition: plotter.cpp:356
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
void markerSquare(const VECTOR2I &position, int radius)
Plot a square centered on the position.
Definition: plotter.cpp:274
virtual int GetCurrentLineWidth() const
Definition: plotter.h:148
bool m_colorMode
Definition: plotter.h:665
double GetDashMarkLenIU(int aLineWidth) const
Definition: plotter.cpp:137
virtual void SetColor(const COLOR4D &color)=0
wxString m_filename
Definition: plotter.h:672
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsClosed() const override
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.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:278
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:405
FILL_T
Definition: eda_shape.h:55
static const bool FILLED
Definition: gr_basic.cpp:30
int GetPenSizeForBold(int aTextSize)
Definition: gr_text.cpp:40
OUTLINE_MODE
Definition: outline_mode.h:25
constexpr int delta
GR_TEXT_H_ALIGN_T
GR_TEXT_V_ALIGN_T
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:228
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition: trigo.cpp:520
int sign(T val)
Definition: util.h:171
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:121
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673
VECTOR2< double > VECTOR2D
Definition: vector2d.h:672