KiCad PCB EDA Suite
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
149void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR2I& aEnd,
150 FILL_T aFill, int aWidth, int aMaxError )
151{
152 EDA_ANGLE startAngle( aStart - aCenter );
153 EDA_ANGLE endAngle( aEnd - aCenter );
154 int radius = ( aStart - aCenter ).EuclideanNorm();
155
156 if( startAngle > endAngle )
157 {
158 if( endAngle < ANGLE_0 )
159 endAngle.Normalize();
160 else
161 startAngle = startAngle.Normalize() - ANGLE_360;
162 }
163
164 // In old Kicad code, calls to Arc() using angles calls this function after
165 // swapping angles and negate them (to compensate the inverted Y axis).
166 // So to be compatible with Arc() calls with angles, do the same thing
167 std::swap( startAngle, endAngle );
168 startAngle = -startAngle;
169 endAngle = -endAngle;
170
171 Arc( aCenter, startAngle, endAngle, radius, aFill, aWidth );
172}
173
174
175void PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
176 const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
177{
178 EDA_ANGLE startAngle( aStartAngle );
179 EDA_ANGLE endAngle( aEndAngle );
180 const EDA_ANGLE delta( 5.0, DEGREES_T ); // increment to draw arc
181 VECTOR2I start, end;
182 const int sign = -1;
183
184 if( startAngle > endAngle )
185 std::swap( startAngle, endAngle );
186
187 SetCurrentLineWidth( aWidth );
188
189 start.x = aCenter.x + KiROUND( aRadius * startAngle.Cos() );
190 start.y = aCenter.y + sign*KiROUND( aRadius * startAngle.Sin() );
191
192 if( aFill != FILL_T::NO_FILL )
193 {
194 MoveTo( aCenter );
195 LineTo( start );
196 }
197 else
198 {
199 MoveTo( start );
200 }
201
202 for( EDA_ANGLE ii = startAngle + delta; ii < endAngle; ii += delta )
203 {
204 end.x = aCenter.x + KiROUND( aRadius * ii.Cos() );
205 end.y = aCenter.y + sign*KiROUND( aRadius * ii.Sin() );
206 LineTo( end );
207 }
208
209 end.x = aCenter.x + KiROUND( aRadius * endAngle.Cos() );
210 end.y = aCenter.y + sign*KiROUND( aRadius * endAngle.Sin() );
211
212 if( aFill != FILL_T::NO_FILL )
213 {
214 LineTo( end );
215 FinishTo( aCenter );
216 }
217 else
218 {
219 FinishTo( end );
220 }
221}
222
223
224void PLOTTER::BezierCurve( const VECTOR2I& aStart, const VECTOR2I& aControl1,
225 const VECTOR2I& aControl2, const VECTOR2I& aEnd,
226 int aTolerance, int aLineThickness )
227{
228 // Generic fallback: Quadratic Bezier curve plotted as a polyline
229 int minSegLen = aLineThickness; // The segment min length to approximate a bezier curve
230
231 std::vector<VECTOR2I> ctrlPoints;
232 ctrlPoints.reserve( 4 );
233
234 ctrlPoints.push_back( aStart );
235 ctrlPoints.push_back( aControl1 );
236 ctrlPoints.push_back( aControl2 );
237 ctrlPoints.push_back( aEnd );
238
239 BEZIER_POLY bezier_converter( ctrlPoints );
240
241 std::vector<VECTOR2I> approxPoints;
242 bezier_converter.GetPoly( approxPoints, minSegLen );
243
244 SetCurrentLineWidth( aLineThickness );
245 MoveTo( aStart );
246
247 for( unsigned ii = 1; ii < approxPoints.size()-1; ii++ )
248 LineTo( approxPoints[ii] );
249
250 FinishTo( aEnd );
251}
252
253
254void PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aScaleFactor )
255{
256 VECTOR2I size( aImage.GetWidth() * aScaleFactor, aImage.GetHeight() * aScaleFactor );
257
258 VECTOR2I start = aPos;
259 start.x -= size.x / 2;
260 start.y -= size.y / 2;
261
262 VECTOR2I end = start;
263 end.x += size.x;
264 end.y += size.y;
265
266 Rect( start, end, FILL_T::NO_FILL );
267}
268
269
270void PLOTTER::markerSquare( const VECTOR2I& position, int radius )
271{
272 double r = KiROUND( radius / 1.4142 );
273 std::vector<VECTOR2I> corner_list;
274 VECTOR2I corner;
275
276 corner_list.reserve( 4 );
277
278 corner.x = position.x + r;
279 corner.y = position.y + r;
280 corner_list.push_back( corner );
281 corner.x = position.x + r;
282 corner.y = position.y - r;
283 corner_list.push_back( corner );
284 corner.x = position.x - r;
285 corner.y = position.y - r;
286 corner_list.push_back( corner );
287 corner.x = position.x - r;
288 corner.y = position.y + r;
289 corner_list.push_back( corner );
290 corner.x = position.x + r;
291 corner.y = position.y + r;
292 corner_list.push_back( corner );
293
295}
296
297
298void PLOTTER::markerCircle( const VECTOR2I& position, int radius )
299{
300 Circle( position, radius * 2, FILL_T::NO_FILL, GetCurrentLineWidth() );
301}
302
303
304void PLOTTER::markerLozenge( const VECTOR2I& position, int radius )
305{
306 std::vector<VECTOR2I> corner_list;
307 VECTOR2I corner;
308
309 corner_list.reserve( 4 );
310
311 corner.x = position.x;
312 corner.y = position.y + radius;
313 corner_list.push_back( corner );
314 corner.x = position.x + radius;
315 corner.y = position.y,
316 corner_list.push_back( corner );
317 corner.x = position.x;
318 corner.y = position.y - radius;
319 corner_list.push_back( corner );
320 corner.x = position.x - radius;
321 corner.y = position.y;
322 corner_list.push_back( corner );
323 corner.x = position.x;
324 corner.y = position.y + radius;
325 corner_list.push_back( corner );
326
328}
329
330
331void PLOTTER::markerHBar( const VECTOR2I& pos, int radius )
332{
333 MoveTo( VECTOR2I( pos.x - radius, pos.y ) );
334 FinishTo( VECTOR2I( pos.x + radius, pos.y ) );
335}
336
337
338void PLOTTER::markerSlash( const VECTOR2I& pos, int radius )
339{
340 MoveTo( VECTOR2I( pos.x - radius, pos.y - radius ) );
341 FinishTo( VECTOR2I( pos.x + radius, pos.y + radius ) );
342}
343
344
345void PLOTTER::markerBackSlash( const VECTOR2I& pos, int radius )
346{
347 MoveTo( VECTOR2I( pos.x + radius, pos.y - radius ) );
348 FinishTo( VECTOR2I( pos.x - radius, pos.y + radius ) );
349}
350
351
352void PLOTTER::markerVBar( const VECTOR2I& pos, int radius )
353{
354 MoveTo( VECTOR2I( pos.x, pos.y - radius ) );
355 FinishTo( VECTOR2I( pos.x, pos.y + radius ) );
356}
357
358
359void PLOTTER::Marker( const VECTOR2I& position, int diametre, unsigned aShapeId )
360{
361 int radius = diametre / 2;
362
363 /* Marker are composed by a series of 'parts' superimposed; not every
364 combination make sense, obviously. Since they are used in order I
365 tried to keep the uglier/more complex constructions at the end.
366 Also I avoided the |/ |\ -/ -\ construction because they're *very*
367 ugly... if needed they could be added anyway... I'd like to see
368 a board with more than 58 drilling/slotting tools!
369 If Visual C++ supported the 0b literals they would be optimally
370 and easily encoded as an integer array. We have to do with octal */
371 static const unsigned char marker_patterns[MARKER_COUNT] = {
372
373 // Bit order: O Square Lozenge - | \ /
374 // First choice: simple shapes
375 0003, // X
376 0100, // O
377 0014, // +
378 0040, // Sq
379 0020, // Lz
380
381 // Two simple shapes
382 0103, // X O
383 0017, // X +
384 0043, // X Sq
385 0023, // X Lz
386 0114, // O +
387 0140, // O Sq
388 0120, // O Lz
389 0054, // + Sq
390 0034, // + Lz
391 0060, // Sq Lz
392
393 // Three simple shapes
394 0117, // X O +
395 0143, // X O Sq
396 0123, // X O Lz
397 0057, // X + Sq
398 0037, // X + Lz
399 0063, // X Sq Lz
400 0154, // O + Sq
401 0134, // O + Lz
402 0074, // + Sq Lz
403
404 // Four simple shapes
405 0174, // O Sq Lz +
406 0163, // X O Sq Lz
407 0157, // X O Sq +
408 0137, // X O Lz +
409 0077, // X Sq Lz +
410
411 // This draws *everything *
412 0177, // X O Sq Lz +
413
414 // Here we use the single bars... so the cross is forbidden
415 0110, // O -
416 0104, // O |
417 0101, // O /
418 0050, // Sq -
419 0044, // Sq |
420 0041, // Sq /
421 0030, // Lz -
422 0024, // Lz |
423 0021, // Lz /
424 0150, // O Sq -
425 0144, // O Sq |
426 0141, // O Sq /
427 0130, // O Lz -
428 0124, // O Lz |
429 0121, // O Lz /
430 0070, // Sq Lz -
431 0064, // Sq Lz |
432 0061, // Sq Lz /
433 0170, // O Sq Lz -
434 0164, // O Sq Lz |
435 0161, // O Sq Lz /
436
437 // Last resort: the backlash component (easy to confound)
438 0102, // \ O
439 0042, // \ Sq
440 0022, // \ Lz
441 0142, // \ O Sq
442 0122, // \ O Lz
443 0062, // \ Sq Lz
444 0162 // \ O Sq Lz
445 };
446
447 if( aShapeId >= MARKER_COUNT )
448 {
449 // Fallback shape
450 markerCircle( position, radius );
451 }
452 else
453 {
454 // Decode the pattern and draw the corresponding parts
455 unsigned char pat = marker_patterns[aShapeId];
456
457 if( pat & 0001 )
458 markerSlash( position, radius );
459
460 if( pat & 0002 )
461 markerBackSlash( position, radius );
462
463 if( pat & 0004 )
464 markerVBar( position, radius );
465
466 if( pat & 0010 )
467 markerHBar( position, radius );
468
469 if( pat & 0020 )
470 markerLozenge( position, radius );
471
472 if( pat & 0040 )
473 markerSquare( position, radius );
474
475 if( pat & 0100 )
476 markerCircle( position, radius );
477 }
478}
479
480
481void PLOTTER::segmentAsOval( const VECTOR2I& start, const VECTOR2I& end, int aWidth,
482 OUTLINE_MODE aTraceMode )
483{
484 VECTOR2I center( ( start.x + end.x ) / 2, ( start.y + end.y ) / 2 );
485 VECTOR2I size( end.x - start.x, end.y - start.y );
486 EDA_ANGLE orient( size );
487 orient = -orient; // this is due to our Y axis orientation
488
489 size.x = KiROUND( EuclideanNorm( size ) ) + aWidth;
490 size.y = aWidth;
491
492 FlashPadOval( center, size, orient, aTraceMode, nullptr );
493}
494
495
496void PLOTTER::sketchOval( const VECTOR2I& aPos, const VECTOR2I& aSize, const EDA_ANGLE& aOrient,
497 int aWidth )
498{
499 SetCurrentLineWidth( aWidth );
500
501 EDA_ANGLE orient( aOrient );
502 VECTOR2I size( aSize );
503
504 if( size.x > size.y )
505 {
506 std::swap( size.x, size.y );
507 orient += ANGLE_90;
508 }
509
510 int deltaxy = size.y - size.x; /* distance between centers of the oval */
511 int radius = size.x / 2;
512
513 // Build a vertical oval shape giving the start and end points of arcs and edges,
514 // and the middle point of arcs
515 std::vector<VECTOR2I> corners;
516 corners.reserve( 6 );
517 // Shape is (x = corner and arc ends, c = arc centre)
518 // xcx
519 //
520 // xcx
521 int half_height = deltaxy / 2;
522 corners.emplace_back( -radius, -half_height );
523 corners.emplace_back( -radius, half_height );
524 corners.emplace_back( 0, half_height );
525 corners.emplace_back( radius, half_height );
526 corners.emplace_back( radius, -half_height );
527 corners.emplace_back( 0, -half_height );
528
529 // Rotate and move to the actual position
530 for( size_t ii = 0; ii < corners.size(); ii++ )
531 {
532 RotatePoint( corners[ii], orient );
533 corners[ii] += aPos;
534 }
535
536 // Gen shape:
537 MoveTo( corners[0] );
538 FinishTo( corners[1] );
539
540 Arc( corners[2], orient + ANGLE_180, orient + ANGLE_360, radius, FILL_T::NO_FILL );
541
542 MoveTo( corners[3] );
543 FinishTo( corners[4] );
544
545 Arc( corners[5], orient, orient + ANGLE_180, radius, FILL_T::NO_FILL );
546}
547
548
549void PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end, int width,
550 OUTLINE_MODE tracemode, void* aData )
551{
552 if( tracemode == FILLED )
553 {
554 if( start == end )
555 {
556 Circle( start, width, FILL_T::FILLED_SHAPE, 0 );
557 }
558 else
559 {
560 SetCurrentLineWidth( width );
561 MoveTo( start );
562 FinishTo( end );
563 }
564 }
565 else
566 {
568 segmentAsOval( start, end, width, tracemode );
569 }
570}
571
572
573void PLOTTER::ThickArc( const VECTOR2I& centre, const EDA_ANGLE& aStartAngle,
574 const EDA_ANGLE& aEndAngle, int aRadius, int aWidth,
575 OUTLINE_MODE aTraceMode, void* aData )
576{
577 if( aTraceMode == FILLED )
578 {
579 Arc( centre, aStartAngle, aEndAngle, aRadius, FILL_T::NO_FILL, aWidth );
580 }
581 else
582 {
584 Arc( centre, aStartAngle, aEndAngle, aRadius - ( aWidth - m_currentPenWidth ) / 2,
585 FILL_T::NO_FILL, -1 );
586 Arc( centre, aStartAngle, aEndAngle, aRadius + ( aWidth - m_currentPenWidth ) / 2,
587 FILL_T::NO_FILL, -1 );
588 }
589}
590
591
592void PLOTTER::ThickArc( const VECTOR2I& aCentre, const VECTOR2I& aStart,
593 const VECTOR2I& aEnd, int aWidth,
594 OUTLINE_MODE aTraceMode, void* aData )
595{
596 if( aTraceMode == FILLED )
597 {
598 Arc( aCentre, aStart, aEnd, FILL_T::NO_FILL, aWidth, GetPlotterArcHighDef() );
599 }
600 else
601 {
603 int radius = ( aStart - aCentre ).EuclideanNorm();
604
605 int new_radius = radius - ( aWidth - m_currentPenWidth ) / 2;
606 VECTOR2I start = ( aStart - aCentre ).Resize( new_radius ) + aCentre;
607 VECTOR2I end = ( aEnd - aCentre ).Resize( new_radius ) + aCentre;
608
609 Arc( aCentre, start, end, FILL_T::NO_FILL, -1, GetPlotterArcHighDef() );
610
611 new_radius = radius + ( aWidth - m_currentPenWidth ) / 2;
612 start = ( aStart - aCentre ).Resize( new_radius ) + aCentre;
613 end = ( aEnd - aCentre ).Resize( new_radius ) + aCentre;
614
615 Arc( aCentre, start, end, FILL_T::NO_FILL, -1, GetPlotterArcHighDef() );
616 }
617}
618
619
620void PLOTTER::ThickArc( const EDA_SHAPE& aArcShape,
621 OUTLINE_MODE aTraceMode, void* aData )
622{
623 ThickArc( aArcShape.getCenter(),aArcShape.GetStart(), aArcShape.GetEnd(),
624 aArcShape.GetWidth(), aTraceMode, aData );
625}
626
627
628void PLOTTER::ThickRect( const VECTOR2I& p1, const VECTOR2I& p2, int width,
629 OUTLINE_MODE tracemode, void* aData )
630{
631 if( tracemode == FILLED )
632 {
633 Rect( p1, p2, FILL_T::NO_FILL, width );
634 }
635 else
636 {
638 VECTOR2I offsetp1( p1.x - ( width - m_currentPenWidth ) / 2,
639 p1.y - (width - m_currentPenWidth) / 2 );
640 VECTOR2I offsetp2( p2.x + ( width - m_currentPenWidth ) / 2,
641 p2.y + (width - m_currentPenWidth) / 2 );
642 Rect( offsetp1, offsetp2, FILL_T::NO_FILL, -1 );
643 offsetp1.x += ( width - m_currentPenWidth );
644 offsetp1.y += ( width - m_currentPenWidth );
645 offsetp2.x -= ( width - m_currentPenWidth );
646 offsetp2.y -= ( width - m_currentPenWidth );
647 Rect( offsetp1, offsetp2, FILL_T::NO_FILL, -1 );
648 }
649}
650
651
652void PLOTTER::ThickCircle( const VECTOR2I& pos, int diametre, int width, OUTLINE_MODE tracemode,
653 void* aData )
654{
655 if( tracemode == FILLED )
656 {
657 Circle( pos, diametre, FILL_T::NO_FILL, width );
658 }
659 else
660 {
662 Circle( pos, diametre - width + m_currentPenWidth, FILL_T::NO_FILL, -1 );
663 Circle( pos, diametre + width - m_currentPenWidth, FILL_T::NO_FILL, -1 );
664 }
665}
666
667
668void PLOTTER::FilledCircle( const VECTOR2I& pos, int diametre, OUTLINE_MODE tracemode, void* aData )
669{
670 if( tracemode == FILLED )
671 {
672 Circle( pos, diametre, FILL_T::FILLED_SHAPE, 0 );
673 }
674 else
675 {
677 Circle( pos, diametre, FILL_T::NO_FILL, -1 );
678 }
679}
680
681
682void PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int aWidth, void* aData )
683{
684 std::vector<VECTOR2I> cornerList;
685 cornerList.reserve( aCornerList.PointCount() );
686
687 for( int ii = 0; ii < aCornerList.PointCount(); ii++ )
688 cornerList.emplace_back( aCornerList.CPoint( ii ) );
689
690 if( aCornerList.IsClosed() && cornerList.front() != cornerList.back() )
691 cornerList.emplace_back( aCornerList.CPoint( 0 ) );
692
693 PlotPoly( cornerList, aFill, aWidth, aData );
694}
695
696
697void PLOTTER::Text( const VECTOR2I& aPos,
698 const COLOR4D& aColor,
699 const wxString& aText,
700 const EDA_ANGLE& aOrient,
701 const VECTOR2I& aSize,
702 enum GR_TEXT_H_ALIGN_T aH_justify,
703 enum GR_TEXT_V_ALIGN_T aV_justify,
704 int aPenWidth,
705 bool aItalic,
706 bool aBold,
707 bool aMultilineAllowed,
708 KIFONT::FONT* aFont,
709 void* aData )
710{
712
713 SetColor( aColor );
714 SetCurrentLineWidth( aPenWidth, aData );
715
716 if( aPenWidth == 0 && aBold ) // Use default values if aPenWidth == 0
717 aPenWidth = GetPenSizeForBold( std::min( aSize.x, aSize.y ) );
718
719 if( aPenWidth < 0 )
720 aPenWidth = -aPenWidth;
721
722 CALLBACK_GAL callback_gal( empty_opts,
723 // Stroke callback
724 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
725 {
726 MoveTo( aPt1 );
727 LineTo( aPt2 );
728 PenFinish();
729 },
730 // Polygon callback
731 [&]( const SHAPE_LINE_CHAIN& aPoly )
732 {
733 PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, aData );
734 } );
735
736 TEXT_ATTRIBUTES attributes;
737 attributes.m_Angle = aOrient;
738 attributes.m_StrokeWidth = aPenWidth;
739 attributes.m_Italic = aItalic;
740 attributes.m_Bold = aBold;
741 attributes.m_Halign = aH_justify;
742 attributes.m_Valign = aV_justify;
743 attributes.m_Size = aSize;
744
745 // if Size.x is < 0, the text is mirrored (we have no other param to know a text is mirrored)
746 if( attributes.m_Size.x < 0 )
747 {
748 attributes.m_Size.x = -attributes.m_Size.x;
749 attributes.m_Mirrored = true;
750 }
751
752 if( !aFont )
753 aFont = KIFONT::FONT::GetFont();
754
755 aFont->Draw( &callback_gal, aText, aPos, attributes );
756}
757
758void PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
759 const wxString& aText,
760 const TEXT_ATTRIBUTES& aAttributes,
761 KIFONT::FONT* aFont,
762 void* aData )
763{
765
766 TEXT_ATTRIBUTES attributes = aAttributes;
767 int penWidth = attributes.m_StrokeWidth;
768
769 SetColor( aColor );
770 SetCurrentLineWidth( penWidth, aData );
771
772 if( penWidth == 0 && attributes.m_Bold ) // Use default values if aPenWidth == 0
773 penWidth = GetPenSizeForBold( std::min( attributes.m_Size.x, attributes.m_Size.y ) );
774
775 if( penWidth < 0 )
776 penWidth = -penWidth;
777
778 attributes.m_StrokeWidth = penWidth;
779
780 CALLBACK_GAL callback_gal( empty_opts,
781 // Stroke callback
782 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
783 {
784 MoveTo( aPt1 );
785 LineTo( aPt2 );
786 PenFinish();
787 },
788 // Polygon callback
789 [&]( const SHAPE_LINE_CHAIN& aPoly )
790 {
791 PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, aData );
792 } );
793
794 if( !aFont )
795 aFont = KIFONT::FONT::GetFont();
796
797 aFont->Draw( &callback_gal, aText, aPos, attributes );
798}
Bezier curves to polygon converter.
Definition: bezier_curves.h:38
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMinSegLen=0, int aMaxSegCount=32)
Convert a Bezier curve to a polygon.
EDA_ANGLE Normalize()
Definition: eda_angle.h:249
double Sin() const
Definition: eda_angle.h:206
double Cos() const
Definition: eda_angle.h:221
VECTOR2I getCenter() const
Definition: eda_shape.cpp:444
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:145
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:120
int GetWidth() const
Definition: eda_shape.h:109
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:105
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false)
Definition: font.cpp:138
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttrs) const
Draw a string.
Definition: font.cpp:232
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:102
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:549
virtual void PlotImage(const wxImage &aImage, const VECTOR2I &aPos, double aScaleFactor)
Only PostScript plotters can plot bitmaps.
Definition: plotter.cpp:254
virtual void ThickRect(const VECTOR2I &p1, const VECTOR2I &p2, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:628
virtual void ThickCircle(const VECTOR2I &pos, int diametre, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:652
static const unsigned MARKER_COUNT
Draw a marker (used for the drill map).
Definition: plotter.h:486
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:649
PLOTTER()
Definition: plotter.cpp:47
bool m_plotMirror
Definition: plotter.h:647
virtual void FilledCircle(const VECTOR2I &pos, int diametre, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:668
void MoveTo(const VECTOR2I &pos)
Definition: plotter.h:247
virtual void Arc(const VECTOR2I &aCenter, const VECTOR2I &aStart, const VECTOR2I &aEnd, FILL_T aFill, int aWidth, int aMaxError)
Generic fallback: arc rendered as a polyline.
Definition: plotter.cpp:149
void markerSlash(const VECTOR2I &pos, int radius)
Plot a / bar centered on the position.
Definition: plotter.cpp:338
void FinishTo(const VECTOR2I &pos)
Definition: plotter.h:257
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:224
bool m_yaxisReversed
Definition: plotter.h:650
double m_iuPerDeviceUnit
Definition: plotter.h:644
VECTOR2I m_plotOffset
Definition: plotter.h:646
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
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, void *aData=nullptr)
Draw text with the plotter.
Definition: plotter.cpp:697
VECTOR2I m_paperSize
Definition: plotter.h:666
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:496
int GetPlotterArcHighDef() const
Definition: plotter.h:213
char m_penState
Definition: plotter.h:659
void Marker(const VECTOR2I &position, int diametre, unsigned aShapeId)
Draw a pattern shape number aShapeId, to coord position.
Definition: plotter.cpp:359
void markerHBar(const VECTOR2I &pos, int radius)
Plot a - bar centered on the position.
Definition: plotter.cpp:331
int m_currentPenWidth
Definition: plotter.h:658
double m_plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plotter.h:636
void markerCircle(const VECTOR2I &pos, int radius)
Plot a circle centered on the position.
Definition: plotter.cpp:298
virtual void PlotText(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const TEXT_ATTRIBUTES &aAttributes, KIFONT::FONT *aFont, void *aData=nullptr)
Definition: plotter.cpp:758
FILE * m_outputFile
Output file.
Definition: plotter.h:653
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:252
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:263
void markerLozenge(const VECTOR2I &position, int radius)
Plot a lozenge centered on the position.
Definition: plotter.cpp:304
RENDER_SETTINGS * m_renderSettings
Definition: plotter.h:670
void markerBackSlash(const VECTOR2I &pos, int radius)
Plot a \ bar centered on the position.
Definition: plotter.cpp:345
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:481
bool m_negativeMode
Definition: plotter.h:657
double m_IUsPerDecimil
Definition: plotter.h:642
void markerVBar(const VECTOR2I &pos, int radius)
Plot a | bar centered on the position.
Definition: plotter.cpp:352
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
virtual void ThickArc(const VECTOR2I &aCentre, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, OUTLINE_MODE aTraceMode, void *aData)
Definition: plotter.cpp:592
void markerSquare(const VECTOR2I &position, int radius)
Plot a square centered on the position.
Definition: plotter.cpp:270
virtual int GetCurrentLineWidth() const
Definition: plotter.h:153
bool m_colorMode
Definition: plotter.h:656
double GetDashMarkLenIU(int aLineWidth) const
Definition: plotter.cpp:137
virtual void SetColor(const COLOR4D &color)=0
wxString m_filename
Definition: plotter.h:663
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.
static constexpr EDA_ANGLE & ANGLE_180
Definition: eda_angle.h:433
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_360
Definition: eda_angle.h:435
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:431
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:429
FILL_T
Definition: eda_shape.h:54
@ FILLED_SHAPE
int GetPenSizeForBold(int aTextSize)
Definition: gr_text.cpp:40
OUTLINE_MODE
Definition: outline_mode.h:25
@ FILLED
Definition: outline_mode.h:27
Plot settings, and plotting engines (PostScript, Gerber, HPGL and DXF)
constexpr int delta
GR_TEXT_H_ALIGN_T
GR_TEXT_V_ALIGN_T
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
int sign(T val)
Definition: util.h:124
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:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:589
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590