KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 {
136 case DXF_UNITS::MILLIMETERS:
137 m_unitScalingFactor = 0.00254;
139 break;
140
141 case DXF_UNITS::INCHES:
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
169 m_currentColor = COLOR4D::BLACK;
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 {
412 m_currentColor = COLOR4D::BLACK;
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 {
576 wxASSERT( m_currentLineType >= PLOT_DASH_TYPE::FIRST_TYPE
577 && m_currentLineType <= PLOT_DASH_TYPE::LAST_TYPE );
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 TEXT_ATTRIBUTES attrs;
865 attrs.m_Halign = aH_justify;
866 attrs.m_Valign =aV_justify;
867 attrs.m_StrokeWidth = aWidth;
868 attrs.m_Angle = aOrient;
869 attrs.m_Italic = aItalic;
870 attrs.m_Bold = aBold;
871 attrs.m_Mirrored = aSize.x < 0;
872 attrs.m_Multiline = false;
873 plotOneLineOfText( aPos, aColor, aText, attrs );
874 }
875}
876
877
878void DXF_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
879 const wxString& aText,
880 const TEXT_ATTRIBUTES& aAttributes,
881 KIFONT::FONT* aFont,
882 void* aData )
883{
884 TEXT_ATTRIBUTES attrs = aAttributes;
885 // Fix me: see how to use DXF text mode for multiline texts
886 if( attrs.m_Multiline && !aText.Contains( wxT( "\n" ) ) )
887 attrs.m_Multiline = false; // the text has only one line.
888
889 bool processSuperSub = aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) );
890
891 if( m_textAsLines || containsNonAsciiChars( aText ) || attrs.m_Multiline || processSuperSub )
892 {
893 // output text as graphics.
894 // Perhaps multiline texts could be handled as DXF text entity
895 // but I do not want spend time about that (JPC)
896 PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
897 }
898 else
899 plotOneLineOfText( aPos, aColor, aText, attrs );
900}
901
902void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor,
903 const wxString& aText,
904 const TEXT_ATTRIBUTES& aAttributes )
905{
906 /* Emit text as a text entity. This loses formatting and shape but it's
907 more useful as a CAD object */
908 VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
909 SetColor( aColor );
910 wxString cname = getDXFColorName( m_currentColor );
911 VECTOR2D size_dev = userToDeviceSize( aAttributes.m_Size );
912 int h_code = 0, v_code = 0;
913
914 switch( aAttributes.m_Halign )
915 {
916 case GR_TEXT_H_ALIGN_LEFT: h_code = 0; break;
917 case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
918 case GR_TEXT_H_ALIGN_RIGHT: h_code = 2; break;
919 }
920
921 switch( aAttributes.m_Valign )
922 {
923 case GR_TEXT_V_ALIGN_TOP: v_code = 3; break;
924 case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
925 case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
926 }
927
928 // Position, size, rotation and alignment
929 // The two alignment point usages is somewhat idiot (see the DXF ref)
930 // Anyway since we don't use the fit/aligned options, they're the same
931 fprintf( m_outputFile,
932 " 0\n"
933 "TEXT\n"
934 " 7\n"
935 "%s\n" // Text style
936 " 8\n"
937 "%s\n" // Layer name
938 " 10\n"
939 "%g\n" // First point X
940 " 11\n"
941 "%g\n" // Second point X
942 " 20\n"
943 "%g\n" // First point Y
944 " 21\n"
945 "%g\n" // Second point Y
946 " 40\n"
947 "%g\n" // Text height
948 " 41\n"
949 "%g\n" // Width factor
950 " 50\n"
951 "%g\n" // Rotation
952 " 51\n"
953 "%g\n" // Oblique angle
954 " 71\n"
955 "%d\n" // Mirror flags
956 " 72\n"
957 "%d\n" // H alignment
958 " 73\n"
959 "%d\n", // V alignment
960 aAttributes.m_Bold ?
961 (aAttributes.m_Italic ? "KICADBI" : "KICADB")
962 : (aAttributes.m_Italic ? "KICADI" : "KICAD"), TO_UTF8( cname ),
963 origin_dev.x, origin_dev.x,
964 origin_dev.y, origin_dev.y,
965 size_dev.y, fabs( size_dev.x / size_dev.y ),
966 aAttributes.m_Angle.AsDegrees(),
967 aAttributes.m_Italic ? DXF_OBLIQUE_ANGLE : 0,
968 aAttributes.m_Mirrored ? 2 : 0, // X mirror flag
969 h_code, v_code );
970
971 /* There are two issue in emitting the text:
972 - Our overline character (~) must be converted to the appropriate
973 control sequence %%O or %%o
974 - Text encoding in DXF is more or less unspecified since depends on
975 the DXF declared version, the acad version reading it *and* some
976 system variables to be put in the header handled only by newer acads
977 Also before R15 unicode simply is not supported (you need to use
978 bigfonts which are a massive PITA). Common denominator solution:
979 use Latin1 (and however someone could choke on it, anyway). Sorry
980 for the extended latin people. If somewant want to try fixing this
981 recent version seems to use UTF-8 (and not UCS2 like the rest of
982 Windows)
983
984 XXX Actually there is a *third* issue: older DXF formats are limited
985 to 255 bytes records (it was later raised to 2048); since I'm lazy
986 and text so long is not probable I just don't implement this rule.
987 If someone is interested in fixing this, you have to emit the first
988 partial lines with group code 3 (max 250 bytes each) and then finish
989 with a group code 1 (less than 250 bytes). The DXF refs explains it
990 in no more details...
991 */
992
993 int braceNesting = 0;
994 int overbarDepth = -1;
995
996 fputs( " 1\n", m_outputFile );
997
998 for( unsigned int i = 0; i < aText.length(); i++ )
999 {
1000 /* Here I do a bad thing: writing the output one byte at a time!
1001 but today I'm lazy and I have no idea on how to coerce a Unicode
1002 wxString to spit out latin1 encoded text ...
1003
1004 At least stdio is *supposed* to do output buffering, so there is
1005 hope is not too slow */
1006 wchar_t ch = aText[i];
1007
1008 if( ch > 255 )
1009 {
1010 // I can't encode this...
1011 putc( '?', m_outputFile );
1012 }
1013 else
1014 {
1015 if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
1016 {
1017 fputs( "%%o", m_outputFile );
1018 overbarDepth = braceNesting;
1019
1020 // Skip the '{'
1021 i++;
1022 continue;
1023 }
1024 else if( aText[i] == '{' )
1025 {
1026 braceNesting++;
1027 }
1028 else if( aText[i] == '}' )
1029 {
1030 if( braceNesting > 0 )
1031 braceNesting--;
1032
1033 if( braceNesting == overbarDepth )
1034 {
1035 fputs( "%%O", m_outputFile );
1036 overbarDepth = -1;
1037 continue;
1038 }
1039 }
1040
1041 putc( ch, m_outputFile );
1042 }
1043 }
1044
1045 putc( '\n', m_outputFile );
1046}
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:226
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:222
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:198
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:224
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:208
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:228
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 PlotText(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const TEXT_ATTRIBUTES &aAttributes, KIFONT::FONT *aFont, void *aData=nullptr) override
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.
void plotOneLineOfText(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const TEXT_ATTRIBUTES &aAttributes)
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:227
COLOR4D m_currentColor
Definition: plotter_dxf.h:223
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:103
double r
Red component.
Definition: color4d.h:375
double g
Green component.
Definition: color4d.h:376
static EDA_COLOR_T FindNearestLegacyColor(int aR, int aG, int aB)
Returns a legacy color ID that is closest to the given 8-bit RGB values.
Definition: color4d.cpp:540
double b
Blue component.
Definition: color4d.h:377
bool m_plotMirror
Definition: plotter.h:647
void MoveTo(const VECTOR2I &pos)
Definition: plotter.h:247
void FinishTo(const VECTOR2I &pos)
Definition: plotter.h:257
double m_iuPerDeviceUnit
Definition: plotter.h:644
VECTOR2I m_plotOffset
Definition: plotter.h:646
VECTOR2I m_penLastpos
Definition: plotter.h:660
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: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
double m_plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plotter.h:636
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
bool GetColorMode() const
Definition: plotter.h:138
FILE * m_outputFile
Output file.
Definition: plotter.h:653
void LineTo(const VECTOR2I &pos)
Definition: plotter.h:252
void PenFinish()
Definition: plotter.h:263
double m_IUsPerDecimil
Definition: plotter.h:642
bool m_colorMode
Definition: plotter.h:656
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 set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
EDA_COLOR_T
Legacy color enumeration.
Definition: color4d.h:41
@ NBCOLORS
Number of colors.
Definition: color4d.h:78
@ BLACK
Definition: color4d.h:43
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aInflate, int aError, ERROR_LOC aErrorLoc)
Convert a rectangle with rounded corners and/or chamfered corners to a polygon.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, 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:431
FILL_T
Definition: eda_shape.h:54
@ ERROR_INSIDE
static const bool FILLED
Definition: gr_basic.cpp:30
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
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:588