KiCad PCB EDA Suite
DXF_plotter.cpp
Go to the documentation of this file.
1
5/*
6 * This program source code file is part of KiCad, a free EDA CAD application.
7 *
8 * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, you may find one here:
22 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23 * or you may search the http://www.gnu.org website for the version 2 license,
24 * or you may write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 */
27
29#include <macros.h>
30#include <string_utils.h>
32#include <trigo.h>
33
38static const double DXF_OBLIQUE_ANGLE = 15;
39
40/* The layer/colors palette. The acad/DXF palette is divided in 3 zones:
41
42 - The primary colors (1 - 9)
43 - An HSV zone (10-250, 5 values x 2 saturations x 10 hues
44 - Greys (251 - 255)
45
46 There is *no* black... the white does it on paper, usually, and
47 anyway it depends on the plotter configuration, since DXF colors
48 are meant to be logical only (they represent *both* line color and
49 width); later version with plot styles only complicate the matter!
50
51 As usual, brown and magenta/purple are difficult to place since
52 they are actually variations of other colors.
53 */
54static const struct
55{
56 const char *name;
57 int color;
59{
60 { "BLACK", 7 }, // In DXF, color 7 is *both* white and black!
61 { "GRAY1", 251 },
62 { "GRAY2", 8 },
63 { "GRAY3", 9 },
64 { "WHITE", 7 },
65 { "LYELLOW", 51 },
66 { "LORANGE", 41 },
67 { "BLUE1", 178 },
68 { "GREEN1", 98 },
69 { "CYAN1", 138 },
70 { "RED1", 18 },
71 { "MAGENTA1", 228 },
72 { "BROWN1", 58 },
73 { "ORANGE1", 34 },
74 { "BLUE2", 5 },
75 { "GREEN2", 3 },
76 { "CYAN2", 4 },
77 { "RED2", 1 },
78 { "MAGENTA2", 6 },
79 { "BROWN2", 54 },
80 { "ORANGE2", 42 },
81 { "BLUE3", 171 },
82 { "GREEN3", 91 },
83 { "CYAN3", 131 },
84 { "RED3", 11 },
85 { "MAGENTA3", 221 },
86 { "YELLOW3", 2 },
87 { "ORANGE3", 32 },
88 { "BLUE4", 5 },
89 { "GREEN4", 3 },
90 { "CYAN4", 4 },
91 { "RED4", 1 },
92 { "MAGENTA4", 6 },
93 { "YELLOW4", 2 },
94 { "ORANGE4", 40 }
95};
96
97
98static const char* getDXFLineType( PLOT_DASH_TYPE aType )
99{
100 switch( aType )
101 {
104 return "CONTINUOUS";
106 return "DASHED";
108 return "DOTTED";
110 return "DASHDOT";
111 default:
112 wxFAIL_MSG( "Unhandled PLOT_DASH_TYPE" );
113 return "CONTINUOUS";
114 }
115}
116
117
118// A helper function to create a color name acceptable in DXF files
119// DXF files do not use a RGB definition
120static wxString getDXFColorName( const COLOR4D& aColor )
121{
122 EDA_COLOR_T color = COLOR4D::FindNearestLegacyColor( int( aColor.r * 255 ),
123 int( aColor.g * 255 ),
124 int( aColor.b * 255 ) );
125 wxString cname( dxf_layer[color].name );
126 return cname;
127}
128
129
131{
132 m_plotUnits = aUnit;
133
134 switch( aUnit )
135 {
137 m_unitScalingFactor = 0.00254;
139 break;
140
142 default:
143 m_unitScalingFactor = 0.0001;
145 }
146}
147
148
149void DXF_PLOTTER::SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil,
150 double aScale, bool aMirror )
151{
152 m_plotOffset = aOffset;
153 m_plotScale = aScale;
154
155 /* DXF paper is 'virtual' so there is no need of a paper size.
156 Also this way we can handle the aux origin which can be useful
157 (for example when aligning to a mechanical drawing) */
158 m_paperSize.x = 0;
159 m_paperSize.y = 0;
160
161 /* Like paper size DXF units are abstract too. Anyway there is a
162 * system variable (MEASUREMENT) which will be set to 0 to indicate
163 * english units */
164 m_IUsPerDecimil = aIusPerDecimil;
165 m_iuPerDeviceUnit = 1.0 / aIusPerDecimil; // Gives a DXF in decimils
166 m_iuPerDeviceUnit *= GetUnitScaling(); // Get the scaling factor for the current units
167
168 m_plotMirror = false; // No mirroring on DXF
170}
171
172
173bool DXF_PLOTTER::StartPlot( const wxString& aPageNumber )
174{
175 wxASSERT( m_outputFile );
176
177 // DXF HEADER - Boilerplate
178 // Defines the minimum for drawing i.e. the angle system and the
179 // 4 linetypes (CONTINUOUS, DOTDASH, DASHED and DOTTED)
180 fprintf( m_outputFile,
181 " 0\n"
182 "SECTION\n"
183 " 2\n"
184 "HEADER\n"
185 " 9\n"
186 "$ANGBASE\n"
187 " 50\n"
188 "0.0\n"
189 " 9\n"
190 "$ANGDIR\n"
191 " 70\n"
192 "1\n"
193 " 9\n"
194 "$MEASUREMENT\n"
195 " 70\n"
196 "%u\n"
197 " 0\n"
198 "ENDSEC\n"
199 " 0\n"
200 "SECTION\n"
201 " 2\n"
202 "TABLES\n"
203 " 0\n"
204 "TABLE\n"
205 " 2\n"
206 "LTYPE\n"
207 " 70\n"
208 "4\n"
209 " 0\n"
210 "LTYPE\n"
211 " 5\n"
212 "40F\n"
213 " 2\n"
214 "CONTINUOUS\n"
215 " 70\n"
216 "0\n"
217 " 3\n"
218 "Solid line\n"
219 " 72\n"
220 "65\n"
221 " 73\n"
222 "0\n"
223 " 40\n"
224 "0.0\n"
225 " 0\n"
226 "LTYPE\n"
227 " 5\n"
228 "410\n"
229 " 2\n"
230 "DASHDOT\n"
231 " 70\n"
232 "0\n"
233 " 3\n"
234 "Dash Dot ____ _ ____ _\n"
235 " 72\n"
236 "65\n"
237 " 73\n"
238 "4\n"
239 " 40\n"
240 "2.0\n"
241 " 49\n"
242 "1.25\n"
243 " 49\n"
244 "-0.25\n"
245 " 49\n"
246 "0.25\n"
247 " 49\n"
248 "-0.25\n"
249 " 0\n"
250 "LTYPE\n"
251 " 5\n"
252 "411\n"
253 " 2\n"
254 "DASHED\n"
255 " 70\n"
256 "0\n"
257 " 3\n"
258 "Dashed __ __ __ __ __\n"
259 " 72\n"
260 "65\n"
261 " 73\n"
262 "2\n"
263 " 40\n"
264 "0.75\n"
265 " 49\n"
266 "0.5\n"
267 " 49\n"
268 "-0.25\n"
269 " 0\n"
270 "LTYPE\n"
271 " 5\n"
272 "43B\n"
273 " 2\n"
274 "DOTTED\n"
275 " 70\n"
276 "0\n"
277 " 3\n"
278 "Dotted . . . .\n"
279 " 72\n"
280 "65\n"
281 " 73\n"
282 "2\n"
283 " 40\n"
284 "0.2\n"
285 " 49\n"
286 "0.0\n"
287 " 49\n"
288 "-0.2\n"
289 " 0\n"
290 "ENDTAB\n",
292
293 // Text styles table
294 // Defines 4 text styles, one for each bold/italic combination
295 fputs( " 0\n"
296 "TABLE\n"
297 " 2\n"
298 "STYLE\n"
299 " 70\n"
300 "4\n", m_outputFile );
301
302 static const char *style_name[4] = {"KICAD", "KICADB", "KICADI", "KICADBI"};
303 for(int i = 0; i < 4; i++ )
304 {
305 fprintf( m_outputFile,
306 " 0\n"
307 "STYLE\n"
308 " 2\n"
309 "%s\n" // Style name
310 " 70\n"
311 "0\n" // Standard flags
312 " 40\n"
313 "0\n" // Non-fixed height text
314 " 41\n"
315 "1\n" // Width factor (base)
316 " 42\n"
317 "1\n" // Last height (mandatory)
318 " 50\n"
319 "%g\n" // Oblique angle
320 " 71\n"
321 "0\n" // Generation flags (default)
322 " 3\n"
323 // The standard ISO font (when kicad is build with it
324 // the dxf text in acad matches *perfectly*)
325 "isocp.shx\n", // Font name (when not bigfont)
326 // Apply a 15 degree angle to italic text
327 style_name[i], i < 2 ? 0 : DXF_OBLIQUE_ANGLE );
328 }
329
330 EDA_COLOR_T numLayers = NBCOLORS;
331
332 // If printing in monochrome, only output the black layer
333 if( !GetColorMode() )
334 numLayers = static_cast<EDA_COLOR_T>( 1 );
335
336 // Layer table - one layer per color
337 fprintf( m_outputFile,
338 " 0\n"
339 "ENDTAB\n"
340 " 0\n"
341 "TABLE\n"
342 " 2\n"
343 "LAYER\n"
344 " 70\n"
345 "%d\n", numLayers );
346
347 /* The layer/colors palette. The acad/DXF palette is divided in 3 zones:
348
349 - The primary colors (1 - 9)
350 - An HSV zone (10-250, 5 values x 2 saturations x 10 hues
351 - Greys (251 - 255)
352 */
353
354 wxASSERT( numLayers <= NBCOLORS );
355
356 for( EDA_COLOR_T i = BLACK; i < numLayers; i = static_cast<EDA_COLOR_T>( int( i ) + 1 ) )
357 {
358 fprintf( m_outputFile,
359 " 0\n"
360 "LAYER\n"
361 " 2\n"
362 "%s\n" // Layer name
363 " 70\n"
364 "0\n" // Standard flags
365 " 62\n"
366 "%d\n" // Color number
367 " 6\n"
368 "CONTINUOUS\n",// Linetype name
369 dxf_layer[i].name, dxf_layer[i].color );
370 }
371
372 // End of layer table, begin entities
373 fputs( " 0\n"
374 "ENDTAB\n"
375 " 0\n"
376 "ENDSEC\n"
377 " 0\n"
378 "SECTION\n"
379 " 2\n"
380 "ENTITIES\n", m_outputFile );
381
382 return true;
383}
384
385
387{
388 wxASSERT( m_outputFile );
389
390 // DXF FOOTER
391 fputs( " 0\n"
392 "ENDSEC\n"
393 " 0\n"
394 "EOF\n", m_outputFile );
395 fclose( m_outputFile );
396 m_outputFile = nullptr;
397
398 return true;
399}
400
401
403{
404 if( ( m_colorMode )
405 || ( color == COLOR4D::BLACK )
406 || ( color == COLOR4D::WHITE ) )
407 {
409 }
410 else
411 {
413 }
414}
415
416
417void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
418{
419 wxASSERT( m_outputFile );
420 MoveTo( p1 );
421 LineTo( VECTOR2I( p1.x, p2.y ) );
422 LineTo( VECTOR2I( p2.x, p2.y ) );
423 LineTo( VECTOR2I( p2.x, p1.y ) );
424 FinishTo( VECTOR2I( p1.x, p1.y ) );
425}
426
427
428void DXF_PLOTTER::Circle( const VECTOR2I& centre, int diameter, FILL_T fill, int width )
429{
430 wxASSERT( m_outputFile );
431 double radius = userToDeviceSize( diameter / 2 );
432 VECTOR2D centre_dev = userToDeviceCoordinates( centre );
433
434 if( radius > 0 )
435 {
436 wxString cname = getDXFColorName( m_currentColor );
437
438 if( fill == FILL_T::NO_FILL )
439 {
440 fprintf( m_outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n",
441 TO_UTF8( cname ),
442 centre_dev.x, centre_dev.y, radius );
443 }
444 else if( fill == FILL_T::FILLED_SHAPE )
445 {
446 double r = radius*0.5;
447 fprintf( m_outputFile, "0\nPOLYLINE\n" );
448 fprintf( m_outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname ) );
449 fprintf( m_outputFile, "40\n%g\n41\n%g\n", radius, radius);
450 fprintf( m_outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ) );
451 fprintf( m_outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
452 centre_dev.x-r, centre_dev.y );
453 fprintf( m_outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ) );
454 fprintf( m_outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
455 centre_dev.x+r, centre_dev.y );
456 fprintf( m_outputFile, "0\nSEQEND\n");
457 }
458 }
459}
460
461
462void DXF_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill, int aWidth,
463 void* aData )
464{
465 if( aCornerList.size() <= 1 )
466 return;
467
468 unsigned last = aCornerList.size() - 1;
469
470 // Plot outlines with lines (thickness = 0) to define the polygon
471 if( aWidth <= 0 )
472 {
473 MoveTo( aCornerList[0] );
474
475 for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
476 LineTo( aCornerList[ii] );
477
478 // Close polygon if 'fill' requested
479 if( aFill != FILL_T::NO_FILL )
480 {
481 if( aCornerList[last] != aCornerList[0] )
482 LineTo( aCornerList[0] );
483 }
484
485 PenFinish();
486
487 return;
488 }
489
490 // if the polygon outline has thickness, and is not filled
491 // (i.e. is a polyline) plot outlines with thick segments
492 if( aWidth > 0 && aFill == FILL_T::NO_FILL )
493 {
494 MoveTo( aCornerList[0] );
495
496 for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
497 ThickSegment( aCornerList[ii-1], aCornerList[ii], aWidth, FILLED, nullptr );
498
499 return;
500 }
501
502 // The polygon outline has thickness, and is filled
503 // Build and plot the polygon which contains the initial
504 // polygon and its thick outline
505 SHAPE_POLY_SET bufferOutline;
506 SHAPE_POLY_SET bufferPolybase;
507
508 bufferPolybase.NewOutline();
509
510 // enter outline as polygon:
511 for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
512 {
513 TransformOvalToPolygon( bufferOutline, aCornerList[ ii - 1 ], aCornerList[ ii ],
515 }
516
517 // enter the initial polygon:
518 for( unsigned ii = 0; ii < aCornerList.size(); ii++ )
519 {
520 bufferPolybase.Append( aCornerList[ii] );
521 }
522
523 // Merge polygons to build the polygon which contains the initial
524 // polygon and its thick outline
525
526 // create the outline which contains thick outline:
527 bufferPolybase.BooleanAdd( bufferOutline, SHAPE_POLY_SET::PM_FAST );
528 bufferPolybase.Fracture( SHAPE_POLY_SET::PM_FAST );
529
530 if( bufferPolybase.OutlineCount() < 1 ) // should not happen
531 return;
532
533 const SHAPE_LINE_CHAIN& path = bufferPolybase.COutline( 0 );
534
535 if( path.PointCount() < 2 ) // should not happen
536 return;
537
538 // Now, output the final polygon to DXF file:
539 last = path.PointCount() - 1;
540 VECTOR2I point = path.CPoint( 0 );
541
542 VECTOR2I startPoint( point.x, point.y );
543 MoveTo( startPoint );
544
545 for( int ii = 1; ii < path.PointCount(); ii++ )
546 {
547 point = path.CPoint( ii );
548 LineTo( VECTOR2I( point.x, point.y ) );
549 }
550
551 // Close polygon, if needed
552 point = path.CPoint( last );
553 VECTOR2I endPoint( point.x, point.y );
554
555 if( endPoint != startPoint )
556 LineTo( startPoint );
557
558 PenFinish();
559}
560
561
562void DXF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
563{
564 wxASSERT( m_outputFile );
565
566 if( plume == 'Z' )
567 {
568 return;
569 }
570
571 VECTOR2D pos_dev = userToDeviceCoordinates( pos );
572 VECTOR2D pen_lastpos_dev = userToDeviceCoordinates( m_penLastpos );
573
574 if( m_penLastpos != pos && plume == 'D' )
575 {
578 // DXF LINE
579 wxString cname = getDXFColorName( m_currentColor );
580 const char* lname = getDXFLineType( static_cast<PLOT_DASH_TYPE>( m_currentLineType ) );
581 fprintf( m_outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n",
582 TO_UTF8( cname ), lname,
583 pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y );
584 }
585
586 m_penLastpos = pos;
587}
588
589
590void DXF_PLOTTER::SetDash( int aLineWidth, PLOT_DASH_TYPE aLineStyle )
591{
592 wxASSERT( aLineStyle >= PLOT_DASH_TYPE::FIRST_TYPE
593 && aLineStyle <= PLOT_DASH_TYPE::LAST_TYPE );
594
595 m_currentLineType = aLineStyle;
596}
597
598
599void DXF_PLOTTER::ThickSegment( const VECTOR2I& aStart, const VECTOR2I& aEnd, int aWidth,
600 OUTLINE_MODE aPlotMode, void* aData )
601{
602 if( aPlotMode == SKETCH )
603 {
604 std::vector<VECTOR2I> cornerList;
605 SHAPE_POLY_SET outlineBuffer;
606 TransformOvalToPolygon( outlineBuffer, aStart, aEnd, aWidth, GetPlotterArcHighDef(),
607 ERROR_INSIDE );
608 const SHAPE_LINE_CHAIN& path = outlineBuffer.COutline( 0 );
609
610 cornerList.reserve( path.PointCount() );
611
612 for( int jj = 0; jj < path.PointCount(); jj++ )
613 cornerList.emplace_back( path.CPoint( jj ).x, path.CPoint( jj ).y );
614
615 // Ensure the polygon is closed
616 if( cornerList[0] != cornerList[cornerList.size() - 1] )
617 cornerList.push_back( cornerList[0] );
618
619 PlotPoly( cornerList, FILL_T::NO_FILL );
620 }
621 else
622 {
623 MoveTo( aStart );
624 FinishTo( aEnd );
625 }
626}
627
628
629void DXF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
630 const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
631{
632 wxASSERT( m_outputFile );
633
634 if( aRadius <= 0 )
635 return;
636
637 EDA_ANGLE startAngle( aStartAngle );
638 EDA_ANGLE endAngle( aEndAngle );
639
640 // In DXF, arcs are drawn CCW.
641 // If startAngle > endAngle, it is CW. So transform it to CCW
642 if( startAngle > endAngle )
643 std::swap( startAngle, endAngle );
644
645 VECTOR2D centre_device = userToDeviceCoordinates( aCenter );
646 double radius_device = userToDeviceSize( aRadius );
647
648 // Emit a DXF ARC entity
649 wxString cname = getDXFColorName( m_currentColor );
650 fprintf( m_outputFile,
651 "0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n",
652 TO_UTF8( cname ),
653 centre_device.x, centre_device.y, radius_device,
654 startAngle.AsDegrees(), endAngle.AsDegrees() );
655}
656
657
658void DXF_PLOTTER::FlashPadOval( const VECTOR2I& aPos, const VECTOR2I& aSize,
659 const EDA_ANGLE& aOrient, OUTLINE_MODE aTraceMode, void* aData )
660{
661 wxASSERT( m_outputFile );
662
663 VECTOR2I size( aSize );
664 EDA_ANGLE orient( aOrient );
665
666 /* The chip is reduced to an oval tablet with size.y > size.x
667 * (Oval vertical orientation 0) */
668 if( size.x > size.y )
669 {
670 std::swap( size.x, size.y );
671 orient += ANGLE_90;
672 }
673
674 sketchOval( aPos, size, orient, -1 );
675}
676
677
678void DXF_PLOTTER::FlashPadCircle( const VECTOR2I& pos, int diametre,
679 OUTLINE_MODE trace_mode, void* aData )
680{
681 wxASSERT( m_outputFile );
682 Circle( pos, diametre, FILL_T::NO_FILL );
683}
684
685
686void DXF_PLOTTER::FlashPadRect( const VECTOR2I& aPos, const VECTOR2I& aPadSize,
687 const EDA_ANGLE& aOrient, OUTLINE_MODE aTraceMode, void* aData )
688{
689 wxASSERT( m_outputFile );
690
691 VECTOR2I size, start, end;
692
693 size.x = aPadSize.x / 2;
694 size.y = aPadSize.y / 2;
695
696 if( size.x < 0 )
697 size.x = 0;
698
699 if( size.y < 0 )
700 size.y = 0;
701
702 // If a dimension is zero, the trace is reduced to 1 line
703 if( size.x == 0 )
704 {
705 start = VECTOR2I( aPos.x, aPos.y - size.y );
706 end = VECTOR2I( aPos.x, aPos.y + size.y );
707 RotatePoint( start, aPos, aOrient );
708 RotatePoint( end, aPos, aOrient );
709 MoveTo( start );
710 FinishTo( end );
711 return;
712 }
713
714 if( size.y == 0 )
715 {
716 start = VECTOR2I( aPos.x - size.x, aPos.y );
717 end = VECTOR2I( aPos.x + size.x, aPos.y );
718 RotatePoint( start, aPos, aOrient );
719 RotatePoint( end, aPos, aOrient );
720 MoveTo( start );
721 FinishTo( end );
722 return;
723 }
724
725 start = VECTOR2I( aPos.x - size.x, aPos.y - size.y );
726 RotatePoint( start, aPos, aOrient );
727 MoveTo( start );
728
729 end = VECTOR2I( aPos.x - size.x, aPos.y + size.y );
730 RotatePoint( end, aPos, aOrient );
731 LineTo( end );
732
733 end = VECTOR2I( aPos.x + size.x, aPos.y + size.y );
734 RotatePoint( end, aPos, aOrient );
735 LineTo( end );
736
737 end = VECTOR2I( aPos.x + size.x, aPos.y - size.y );
738 RotatePoint( end, aPos, aOrient );
739 LineTo( end );
740
741 FinishTo( start );
742}
743
744
745void DXF_PLOTTER::FlashPadRoundRect( const VECTOR2I& aPadPos, const VECTOR2I& aSize,
746 int aCornerRadius, const EDA_ANGLE& aOrient,
747 OUTLINE_MODE aTraceMode, void* aData )
748{
749 SHAPE_POLY_SET outline;
750 TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient, aCornerRadius, 0.0, 0,
752
753 // TransformRoundRectToPolygon creates only one convex polygon
754 SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
755
756 MoveTo( VECTOR2I( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
757
758 for( int ii = 1; ii < poly.PointCount(); ++ii )
759 LineTo( VECTOR2I( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
760
761 FinishTo( VECTOR2I( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
762}
763
764void DXF_PLOTTER::FlashPadCustom( const VECTOR2I& aPadPos, const VECTOR2I& aSize,
765 const EDA_ANGLE& aOrient, SHAPE_POLY_SET* aPolygons,
766 OUTLINE_MODE aTraceMode, void* aData )
767{
768 for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt )
769 {
770 SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt );
771
772 MoveTo( VECTOR2I( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
773
774 for( int ii = 1; ii < poly.PointCount(); ++ii )
775 LineTo( VECTOR2I( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
776
777 FinishTo( VECTOR2I( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
778 }
779}
780
781
782void DXF_PLOTTER::FlashPadTrapez( const VECTOR2I& aPadPos, const VECTOR2I* aCorners,
783 const EDA_ANGLE& aPadOrient, OUTLINE_MODE aTraceMode,
784 void* aData )
785{
786 wxASSERT( m_outputFile );
787 VECTOR2I coord[4]; /* coord actual corners of a trapezoidal trace */
788
789 for( int ii = 0; ii < 4; ii++ )
790 {
791 coord[ii] = aCorners[ii];
792 RotatePoint( coord[ii], aPadOrient );
793 coord[ii] += aPadPos;
794 }
795
796 // Plot edge:
797 MoveTo( coord[0] );
798 LineTo( coord[1] );
799 LineTo( coord[2] );
800 LineTo( coord[3] );
801 FinishTo( coord[0] );
802}
803
804
805void DXF_PLOTTER::FlashRegularPolygon( const VECTOR2I& aShapePos, int aRadius, int aCornerCount,
806 const EDA_ANGLE& aOrient, OUTLINE_MODE aTraceMode,
807 void* aData )
808{
809 // Do nothing
810 wxASSERT( 0 );
811}
812
813
821bool containsNonAsciiChars( const wxString& string )
822{
823 for( unsigned i = 0; i < string.length(); i++ )
824 {
825 wchar_t ch = string[i];
826
827 if( ch > 255 )
828 return true;
829 }
830 return false;
831}
832
833
834void DXF_PLOTTER::Text( const VECTOR2I& aPos,
835 const COLOR4D& aColor,
836 const wxString& aText,
837 const EDA_ANGLE& aOrient,
838 const VECTOR2I& aSize,
839 enum GR_TEXT_H_ALIGN_T aH_justify,
840 enum GR_TEXT_V_ALIGN_T aV_justify,
841 int aWidth,
842 bool aItalic,
843 bool aBold,
844 bool aMultilineAllowed,
845 KIFONT::FONT* aFont,
846 void* aData )
847{
848 // Fix me: see how to use DXF text mode for multiline texts
849 if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
850 aMultilineAllowed = false; // the text has only one line.
851
852 bool processSuperSub = aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) );
853
854 if( m_textAsLines || containsNonAsciiChars( aText ) || aMultilineAllowed || processSuperSub )
855 {
856 // output text as graphics.
857 // Perhaps multiline texts could be handled as DXF text entity
858 // but I do not want spend time about this (JPC)
859 PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify, aWidth, aItalic,
860 aBold, aMultilineAllowed, aFont, aData );
861 }
862 else
863 {
864 /* Emit text as a text entity. This loses formatting and shape but it's
865 more useful as a CAD object */
866 VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
867 SetColor( aColor );
868 wxString cname = getDXFColorName( m_currentColor );
869 VECTOR2D size_dev = userToDeviceSize( aSize );
870 int h_code = 0, v_code = 0;
871
872 switch( aH_justify )
873 {
874 case GR_TEXT_H_ALIGN_LEFT: h_code = 0; break;
875 case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
876 case GR_TEXT_H_ALIGN_RIGHT: h_code = 2; break;
877 }
878
879 switch( aV_justify )
880 {
881 case GR_TEXT_V_ALIGN_TOP: v_code = 3; break;
882 case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
883 case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
884 }
885
886 // Position, size, rotation and alignment
887 // The two alignment point usages is somewhat idiot (see the DXF ref)
888 // Anyway since we don't use the fit/aligned options, they're the same
889 fprintf( m_outputFile,
890 " 0\n"
891 "TEXT\n"
892 " 7\n"
893 "%s\n" // Text style
894 " 8\n"
895 "%s\n" // Layer name
896 " 10\n"
897 "%g\n" // First point X
898 " 11\n"
899 "%g\n" // Second point X
900 " 20\n"
901 "%g\n" // First point Y
902 " 21\n"
903 "%g\n" // Second point Y
904 " 40\n"
905 "%g\n" // Text height
906 " 41\n"
907 "%g\n" // Width factor
908 " 50\n"
909 "%g\n" // Rotation
910 " 51\n"
911 "%g\n" // Oblique angle
912 " 71\n"
913 "%d\n" // Mirror flags
914 " 72\n"
915 "%d\n" // H alignment
916 " 73\n"
917 "%d\n", // V alignment
918 aBold ? (aItalic ? "KICADBI" : "KICADB") : (aItalic ? "KICADI" : "KICAD"),
919 TO_UTF8( cname ),
920 origin_dev.x, origin_dev.x,
921 origin_dev.y, origin_dev.y,
922 size_dev.y, fabs( size_dev.x / size_dev.y ),
923 aOrient.AsDegrees(),
924 aItalic ? DXF_OBLIQUE_ANGLE : 0,
925 size_dev.x < 0 ? 2 : 0, // X mirror flag
926 h_code, v_code );
927
928 /* There are two issue in emitting the text:
929 - Our overline character (~) must be converted to the appropriate
930 control sequence %%O or %%o
931 - Text encoding in DXF is more or less unspecified since depends on
932 the DXF declared version, the acad version reading it *and* some
933 system variables to be put in the header handled only by newer acads
934 Also before R15 unicode simply is not supported (you need to use
935 bigfonts which are a massive PITA). Common denominator solution:
936 use Latin1 (and however someone could choke on it, anyway). Sorry
937 for the extended latin people. If somewant want to try fixing this
938 recent version seems to use UTF-8 (and not UCS2 like the rest of
939 Windows)
940
941 XXX Actually there is a *third* issue: older DXF formats are limited
942 to 255 bytes records (it was later raised to 2048); since I'm lazy
943 and text so long is not probable I just don't implement this rule.
944 If someone is interested in fixing this, you have to emit the first
945 partial lines with group code 3 (max 250 bytes each) and then finish
946 with a group code 1 (less than 250 bytes). The DXF refs explains it
947 in no more details...
948 */
949
950 int braceNesting = 0;
951 int overbarDepth = -1;
952
953 fputs( " 1\n", m_outputFile );
954
955 for( unsigned int i = 0; i < aText.length(); i++ )
956 {
957 /* Here I do a bad thing: writing the output one byte at a time!
958 but today I'm lazy and I have no idea on how to coerce a Unicode
959 wxString to spit out latin1 encoded text ...
960
961 At least stdio is *supposed* to do output buffering, so there is
962 hope is not too slow */
963 wchar_t ch = aText[i];
964
965 if( ch > 255 )
966 {
967 // I can't encode this...
968 putc( '?', m_outputFile );
969 }
970 else
971 {
972 if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
973 {
974 fputs( "%%o", m_outputFile );
975 overbarDepth = braceNesting;
976
977 // Skip the '{'
978 i++;
979 continue;
980 }
981 else if( aText[i] == '{' )
982 {
983 braceNesting++;
984 }
985 else if( aText[i] == '}' )
986 {
987 if( braceNesting > 0 )
988 braceNesting--;
989
990 if( braceNesting == overbarDepth )
991 {
992 fputs( "%%O", m_outputFile );
993 overbarDepth = -1;
994 continue;
995 }
996 }
997
998 putc( ch, m_outputFile );
999 }
1000 }
1001
1002 putc( '\n', m_outputFile );
1003 }
1004}
1005
int color
Definition: DXF_plotter.cpp:57
static wxString getDXFColorName(const COLOR4D &aColor)
static const double DXF_OBLIQUE_ANGLE
Oblique angle for DXF native text (I don't remember if 15 degrees is the ISO value....
Definition: DXF_plotter.cpp:38
static const char * getDXFLineType(PLOT_DASH_TYPE aType)
Definition: DXF_plotter.cpp:98
bool containsNonAsciiChars(const wxString &string)
Check if a given string contains non-ASCII characters.
static const struct @8 dxf_layer[NBCOLORS]
const char * name
Definition: DXF_plotter.cpp:56
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, OUTLINE_MODE tracemode, void *aData) override
DXF_UNITS m_plotUnits
Definition: plotter_dxf.h:217
virtual void FlashPadCircle(const VECTOR2I &pos, int diametre, OUTLINE_MODE trace_mode, void *aData) override
DXF round pad: always done in sketch mode; it could be filled but it isn't pretty if other kinds of p...
bool m_textAsLines
Definition: plotter_dxf.h:213
virtual void FlashPadRect(const VECTOR2I &aPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, OUTLINE_MODE aTraceMode, void *aData) override
DXF rectangular pad: always done in sketch mode.
virtual void Arc(const VECTOR2I &aCenter, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aEndAngle, int aRadius, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH) override
Generic fallback: arc rendered as a polyline.
virtual void FlashPadCustom(const VECTOR2I &aPadPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, SHAPE_POLY_SET *aPolygons, OUTLINE_MODE aTraceMode, void *aData) override
void SetUnits(DXF_UNITS aUnit)
Set the units to use for plotting the DXF file.
virtual void FlashPadTrapez(const VECTOR2I &aPadPos, const VECTOR2I *aCorners, const EDA_ANGLE &aPadOrient, OUTLINE_MODE aTraceMode, void *aData) override
DXF trapezoidal pad: only sketch mode is supported.
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the scale/position for the DXF plot.
double GetUnitScaling() const
Get the scale factor to apply to convert the device units to be in the currently set units.
Definition: plotter_dxf.h:193
virtual void FlashRegularPolygon(const VECTOR2I &aShapePos, int aDiameter, int aCornerCount, const EDA_ANGLE &aOrient, OUTLINE_MODE aTraceMode, void *aData) override
Flash a regular polygon.
virtual void FlashPadOval(const VECTOR2I &aPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, OUTLINE_MODE aTraceMode, void *aData) override
DXF oval pad: always done in sketch mode.
virtual void FlashPadRoundRect(const VECTOR2I &aPadPos, const VECTOR2I &aSize, int aCornerRadius, const EDA_ANGLE &aOrient, OUTLINE_MODE aTraceMode, void *aData) override
PLOT_DASH_TYPE m_currentLineType
Definition: plotter_dxf.h:215
virtual void SetDash(int aLineWidth, PLOT_DASH_TYPE aLineStyle) override
virtual bool StartPlot(const wxString &aPageNumber) override
Open the DXF plot with a skeleton header.
unsigned int GetMeasurementDirective() const
Get the correct value for the $MEASUREMENT field given the current units.
Definition: plotter_dxf.h:203
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
DXF circle: full functionality; it even does 'fills' drawing a circle with a dual-arc polyline wide a...
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=nullptr) override
DXF polygon: doesn't fill it but at least it close the filled ones DXF does not know thick outline.
unsigned int m_measurementDirective
Definition: plotter_dxf.h:219
virtual bool EndPlot() override
virtual void PenTo(const VECTOR2I &pos, char plume) override
Moveto/lineto primitive, moves the 'pen' to the specified direction.
virtual void SetColor(const COLOR4D &color) override
The DXF exporter handles 'colors' as layers...
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 aWidth, bool aItalic, bool aBold, bool aMultilineAllowed=false, KIFONT::FONT *aFont=nullptr, void *aData=nullptr) override
Draw text with the plotter.
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
DXF rectangle: fill not supported.
double m_unitScalingFactor
Definition: plotter_dxf.h:218
COLOR4D m_currentColor
Definition: plotter_dxf.h:214
double AsDegrees() const
Definition: eda_angle.h:149
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:105
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
double r
Red component.
Definition: color4d.h:384
double g
Green component.
Definition: color4d.h:385
double b
Blue component.
Definition: color4d.h:386
bool m_plotMirror
Definition: plotter.h:627
void MoveTo(const VECTOR2I &pos)
Definition: plotter.h:247
void FinishTo(const VECTOR2I &pos)
Definition: plotter.h:257
double m_iuPerDeviceUnit
Definition: plotter.h:624
VECTOR2I m_plotOffset
Definition: plotter.h:626
VECTOR2I m_penLastpos
Definition: plotter.h:640
virtual VECTOR2D userToDeviceCoordinates(const VECTOR2I &aCoordinate)
Modify coordinates according to the orientation, scale factor, and offsets trace.
Definition: plotter.cpp:90
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:714
VECTOR2I m_paperSize
Definition: plotter.h:646
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
double m_plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plotter.h:616
bool GetColorMode() const
Definition: plotter.h:138
FILE * m_outputFile
Output file.
Definition: plotter.h:633
void LineTo(const VECTOR2I &pos)
Definition: plotter.h:252
void PenFinish()
Definition: plotter.h:263
double m_IUsPerDecimil
Definition: plotter.h:622
bool m_colorMode
Definition: plotter.h:636
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.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
SHAPE_LINE_CHAIN & Outline(int aIndex)
int NewOutline()
Creates a new hole in a given outline.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
EDA_COLOR_T
Legacy color enumeration.
Definition: color4d.h:42
@ WHITE
Definition: color4d.h:48
@ NBCOLORS
Number of colors.
Definition: color4d.h:79
@ BLACK
Definition: color4d.h:44
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, 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.
void TransformOvalToPolygon(SHAPE_POLY_SET &aCornerBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:414
FILL_T
Definition: eda_shape.h:54
@ FILLED_SHAPE
E_SERIE r
Definition: eserie.cpp:41
@ ERROR_INSIDE
This file contains miscellaneous commonly used macros and functions.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
OUTLINE_MODE
Definition: outline_mode.h:25
@ SKETCH
Definition: outline_mode.h:26
@ FILLED
Definition: outline_mode.h:27
DXF_UNITS
Definition: plotter.h:58
Plotting engine (DXF)
PLOT_DASH_TYPE
Dashed line types.
Definition: stroke_params.h:48
GR_TEXT_H_ALIGN_T
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
GR_TEXT_V_ALIGN_T
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618