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 The 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
28#include <ranges>
30#include <macros.h>
31#include <string_utils.h>
33#include <geometry/shape_rect.h>
34#include <trigo.h>
35#include <fmt/core.h>
36
41static const double DXF_OBLIQUE_ANGLE = 15;
42
43// No support for linewidths in DXF
44#define DXF_LINE_WIDTH DO_NOT_SET_LINE_WIDTH
45
62static const struct
63{
64 const char *name;
65 int color;
67{
68 { "BLACK", 7 }, // In DXF, color 7 is *both* white and black!
69 { "GRAY1", 251 },
70 { "GRAY2", 8 },
71 { "GRAY3", 9 },
72 { "WHITE", 7 },
73 { "LYELLOW", 51 },
74 { "LORANGE", 41 },
75 { "BLUE1", 178 },
76 { "GREEN1", 98 },
77 { "CYAN1", 138 },
78 { "RED1", 18 },
79 { "MAGENTA1", 228 },
80 { "BROWN1", 58 },
81 { "ORANGE1", 34 },
82 { "BLUE2", 5 },
83 { "GREEN2", 3 },
84 { "CYAN2", 4 },
85 { "RED2", 1 },
86 { "MAGENTA2", 6 },
87 { "BROWN2", 54 },
88 { "ORANGE2", 42 },
89 { "BLUE3", 171 },
90 { "GREEN3", 91 },
91 { "CYAN3", 131 },
92 { "RED3", 11 },
93 { "MAGENTA3", 221 },
94 { "YELLOW3", 2 },
95 { "ORANGE3", 32 },
96 { "BLUE4", 5 },
97 { "GREEN4", 3 },
98 { "CYAN4", 4 },
99 { "RED4", 1 },
100 { "MAGENTA4", 6 },
101 { "YELLOW4", 2 },
102 { "ORANGE4", 40 }
104
105
106static const char* getDXFLineType( LINE_STYLE aType )
107{
108 switch( aType )
109 {
112 return "CONTINUOUS";
113 case LINE_STYLE::DASH:
114 return "DASHED";
115 case LINE_STYLE::DOT:
116 return "DOTTED";
118 return "DASHDOT";
120 return "DIVIDE";
121 default:
122 wxFAIL_MSG( "Unhandled LINE_STYLE" );
123 return "CONTINUOUS";
124 }
125}
126
127
128// A helper function to create a color name acceptable in DXF files
129// DXF files do not use a RGB definition
130static wxString getDXFColorName( const COLOR4D& aColor )
131{
132 EDA_COLOR_T color = COLOR4D::FindNearestLegacyColor( int( aColor.r * 255 ),
133 int( aColor.g * 255 ),
134 int( aColor.b * 255 ) );
135 wxString cname( dxf_layer[color].name );
136 return cname;
137}
138
139
141{
142 m_plotUnits = aUnit;
143
144 switch( aUnit )
145 {
146 case DXF_UNITS::MM:
147 m_unitScalingFactor = 0.00254;
149 break;
150
151 case DXF_UNITS::INCH:
152 default:
153 m_unitScalingFactor = 0.0001;
155 }
156}
157
158
159// convert aValue to a string, and remove trailing zeros
160// In DXF files coordinates need a high precision: at least 9 digits when given
161// in inches and 7 digits when in mm.
162// So we use 16 digits and remove trailing 0 (if any)
163static std::string formatCoord( double aValue )
164{
165 std::string buf;
166
167 buf = fmt::format( "{:.16f}", aValue );
168
169 // remove trailing zeros
170 while( !buf.empty() && buf[buf.size() - 1] == '0' )
171 {
172 buf.pop_back();
173 }
174
175 return buf;
176}
177
178
179void DXF_PLOTTER::SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil,
180 double aScale, bool aMirror )
181{
182 m_plotOffset = aOffset;
183 m_plotScale = aScale;
184
185 /* DXF paper is 'virtual' so there is no need of a paper size.
186 Also this way we can handle the aux origin which can be useful
187 (for example when aligning to a mechanical drawing) */
188 m_paperSize.x = 0;
189 m_paperSize.y = 0;
190
191 /* Like paper size DXF units are abstract too. Anyway there is a
192 * system variable (MEASUREMENT) which will be set to 0 to indicate
193 * english units */
194 m_IUsPerDecimil = aIusPerDecimil;
195 m_iuPerDeviceUnit = 1.0 / aIusPerDecimil; // Gives a DXF in decimils
196 m_iuPerDeviceUnit *= GetUnitScaling(); // Get the scaling factor for the current units
197
198 m_plotMirror = false; // No mirroring on DXF
200}
201
202
203bool DXF_PLOTTER::StartPlot( const wxString& aPageNumber )
204{
205 wxASSERT( m_outputFile );
206
207 // DXF HEADER - Boilerplate
208 // Defines the minimum for drawing i.e. the angle system and the
209 // 4 linetypes (CONTINUOUS, DOTDASH, DASHED and DOTTED)
210 fmt::print( m_outputFile,
211 " 0\n"
212 "SECTION\n"
213 " 2\n"
214 "HEADER\n"
215 " 9\n"
216 "$ANGBASE\n"
217 " 50\n"
218 "0.0\n"
219 " 9\n"
220 "$ANGDIR\n"
221 " 70\n"
222 "1\n"
223 " 9\n"
224 "$MEASUREMENT\n"
225 " 70\n"
226 "{}\n"
227 " 0\n"
228 "ENDSEC\n"
229 " 0\n"
230 "SECTION\n"
231 " 2\n"
232 "TABLES\n"
233 " 0\n"
234 "TABLE\n"
235 " 2\n"
236 "LTYPE\n"
237 " 70\n"
238 "4\n"
239 " 0\n"
240 "LTYPE\n"
241 " 5\n"
242 "40F\n"
243 " 2\n"
244 "CONTINUOUS\n"
245 " 70\n"
246 "0\n"
247 " 3\n"
248 "Solid line\n"
249 " 72\n"
250 "65\n"
251 " 73\n"
252 "0\n"
253 " 40\n"
254 "0.0\n"
255 " 0\n"
256 "LTYPE\n"
257 " 5\n"
258 "410\n"
259 " 2\n"
260 "DASHDOT\n"
261 " 70\n"
262 "0\n"
263 " 3\n"
264 "Dash Dot ____ _ ____ _\n"
265 " 72\n"
266 "65\n"
267 " 73\n"
268 "4\n"
269 " 40\n"
270 "2.0\n"
271 " 49\n"
272 "1.25\n"
273 " 49\n"
274 "-0.25\n"
275 " 49\n"
276 "0.25\n"
277 " 49\n"
278 "-0.25\n"
279 " 0\n"
280 "LTYPE\n"
281 " 5\n"
282 "411\n"
283 " 2\n"
284 "DASHED\n"
285 " 70\n"
286 "0\n"
287 " 3\n"
288 "Dashed __ __ __ __ __\n"
289 " 72\n"
290 "65\n"
291 " 73\n"
292 "2\n"
293 " 40\n"
294 "0.75\n"
295 " 49\n"
296 "0.5\n"
297 " 49\n"
298 "-0.25\n"
299 " 0\n"
300 "LTYPE\n"
301 " 5\n"
302 "43B\n"
303 " 2\n"
304 "DOTTED\n"
305 " 70\n"
306 "0\n"
307 " 3\n"
308 "Dotted . . . .\n"
309 " 72\n"
310 "65\n"
311 " 73\n"
312 "2\n"
313 " 40\n"
314 "0.2\n"
315 " 49\n"
316 "0.0\n"
317 " 49\n"
318 "-0.2\n"
319 " 0\n"
320 "ENDTAB\n",
322
323 // Text styles table
324 // Defines 4 text styles, one for each bold/italic combination
325 fmt::print( m_outputFile,
326 " 0\n"
327 "TABLE\n"
328 " 2\n"
329 "STYLE\n"
330 " 70\n"
331 "4\n" );
332
333 static const char *style_name[4] = {"KICAD", "KICADB", "KICADI", "KICADBI"};
334
335 for(int i = 0; i < 4; i++ )
336 {
337 fmt::print( m_outputFile,
338 " 0\n"
339 "STYLE\n"
340 " 2\n"
341 "{}\n" // Style name
342 " 70\n"
343 "0\n" // Standard flags
344 " 40\n"
345 "0\n" // Non-fixed height text
346 " 41\n"
347 "1\n" // Width factor (base)
348 " 42\n"
349 "1\n" // Last height (mandatory)
350 " 50\n"
351 "{:g}\n" // Oblique angle
352 " 71\n"
353 "0\n" // Generation flags (default)
354 " 3\n"
355 // The standard ISO font (when kicad is build with it
356 // the dxf text in acad matches *perfectly*)
357 "isocp.shx\n", // Font name (when not bigfont)
358 // Apply a 15 degree angle to italic text
359 style_name[i], i < 2 ? 0 : DXF_OBLIQUE_ANGLE );
360 }
361
362 EDA_COLOR_T numLayers = NBCOLORS;
363
364 // If printing in monochrome, only output the black layer
365 if( !GetColorMode() )
366 numLayers = static_cast<EDA_COLOR_T>( 1 );
367
368 // Layer table - one layer per color
369 fmt::print( m_outputFile,
370 " 0\n"
371 "ENDTAB\n"
372 " 0\n"
373 "TABLE\n"
374 " 2\n"
375 "LAYER\n"
376 " 70\n"
377 "{}\n", (int)numLayers );
378
379 /* The layer/colors palette. The acad/DXF palette is divided in 3 zones:
380
381 - The primary colors (1 - 9)
382 - An HSV zone (10-250, 5 values x 2 saturations x 10 hues
383 - Greys (251 - 255)
384 */
385
386 wxASSERT( numLayers <= NBCOLORS );
387
388 for( EDA_COLOR_T i = BLACK; i < numLayers; i = static_cast<EDA_COLOR_T>( int( i ) + 1 ) )
389 {
390 fmt::print( m_outputFile,
391 " 0\n"
392 "LAYER\n"
393 " 2\n"
394 "{}\n" // Layer name
395 " 70\n"
396 "0\n" // Standard flags
397 " 62\n"
398 "{}\n" // Color number
399 " 6\n"
400 "CONTINUOUS\n",// Linetype name
401 dxf_layer[i].name, dxf_layer[i].color );
402 }
403
404 // End of layer table, begin entities
405 fmt::print( m_outputFile,
406 " 0\n"
407 "ENDTAB\n"
408 " 0\n"
409 "ENDSEC\n"
410 " 0\n"
411 "SECTION\n"
412 " 2\n"
413 "ENTITIES\n" );
414
415 return true;
416}
417
418
420{
421 wxASSERT( m_outputFile );
422
423 // DXF FOOTER
424 fmt::print( m_outputFile,
425 " 0\n"
426 "ENDSEC\n"
427 " 0\n"
428 "EOF\n" );
429 fclose( m_outputFile );
430 m_outputFile = nullptr;
431
432 return true;
433}
434
435
437{
438 if( ( m_colorMode )
439 || ( color == COLOR4D::BLACK )
440 || ( color == COLOR4D::WHITE ) )
441 {
443 }
444 else
445 {
447 }
448}
449
450
451void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
452 int aCornerRadius )
453{
454 wxASSERT( m_outputFile );
455
456 if( aCornerRadius > 0 )
457 {
458 BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
459 box.Normalize();
460 SHAPE_RECT rect( box );
461 rect.SetRadius( aCornerRadius );
462 PlotPoly( rect.Outline(), fill, width, nullptr );
463 return;
464 }
465
466 if( p1 != p2 )
467 {
468 MoveTo( p1 );
469 LineTo( VECTOR2I( p1.x, p2.y ) );
470 LineTo( VECTOR2I( p2.x, p2.y ) );
471 LineTo( VECTOR2I( p2.x, p1.y ) );
472 FinishTo( VECTOR2I( p1.x, p1.y ) );
473 }
474 else
475 {
476 // Draw as a point
477 wxString cname = getDXFColorName( m_currentColor );
478 VECTOR2D point_dev = userToDeviceCoordinates( p1 );
479
480 fmt::print( m_outputFile, "0\nPOINT\n8\n{}\n10\n{}\n20\n{}\n",
481 TO_UTF8( cname ),
482 formatCoord( point_dev.x ),
483 formatCoord( point_dev.y ) );
484 }
485}
486
487
488void DXF_PLOTTER::Circle( const VECTOR2I& centre, int diameter, FILL_T fill, int width )
489{
490 wxASSERT( m_outputFile );
491 double radius = userToDeviceSize( diameter / 2 );
492 VECTOR2D centre_dev = userToDeviceCoordinates( centre );
493
494 wxString cname = getDXFColorName( m_currentColor );
495
496 if( radius > 0 )
497 {
498 if( fill == FILL_T::NO_FILL )
499 {
500 fmt::print( m_outputFile, "0\nCIRCLE\n8\n{}\n10\n{}\n20\n{}\n40\n{}\n",
501 TO_UTF8( cname ),
502 formatCoord( centre_dev.x ),
503 formatCoord( centre_dev.y ),
504 formatCoord( radius ) );
505 }
506 else if( fill == FILL_T::FILLED_SHAPE )
507 {
508 double r = radius * 0.5;
509 fmt::print( m_outputFile, "0\nPOLYLINE\n" );
510 fmt::print( m_outputFile, "8\n{}\n66\n1\n70\n1\n", TO_UTF8( cname ) );
511 fmt::print( m_outputFile, "40\n{}\n41\n{}\n",
513 formatCoord( radius ) );
514 fmt::print( m_outputFile, "0\nVERTEX\n8\n{}\n", TO_UTF8( cname ) );
515 fmt::print( m_outputFile, "10\n{}\n 20\n{}\n42\n1.0\n",
516 formatCoord( centre_dev.x-r ),
517 formatCoord( centre_dev.y ) );
518 fmt::print( m_outputFile, "0\nVERTEX\n8\n{}\n", TO_UTF8( cname ) );
519 fmt::print( m_outputFile, "10\n{}\n 20\n{}\n42\n1.0\n",
520 formatCoord( centre_dev.x+r ),
521 formatCoord( centre_dev.y ) );
522 fmt::print( m_outputFile, "0\nSEQEND\n" );
523 }
524 }
525 else
526 {
527 // Draw as a point
528 fmt::print( m_outputFile, "0\nPOINT\n8\n{}\n10\n{}\n20\n{}\n",
529 TO_UTF8( cname ),
530 formatCoord( centre_dev.x ),
531 formatCoord( centre_dev.y ) );
532 }
533}
534
535
536void DXF_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill, int aWidth,
537 void* aData )
538{
539 if( aCornerList.size() <= 1 )
540 return;
541
542 unsigned last = aCornerList.size() - 1;
543
544 // Plot outlines with lines (thickness = 0) to define the polygon
545 if( aWidth <= 0 || aFill == FILL_T::NO_FILL )
546 {
547 MoveTo( aCornerList[0] );
548
549 for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
550 LineTo( aCornerList[ii] );
551
552 // Close polygon if 'fill' requested
553 if( aFill != FILL_T::NO_FILL )
554 {
555 if( aCornerList[last] != aCornerList[0] )
556 LineTo( aCornerList[0] );
557 }
558
559 PenFinish();
560 return;
561 }
562
563 // The polygon outline has thickness, and is filled
564 // Build and plot the polygon which contains the initial
565 // polygon and its thick outline
566 SHAPE_POLY_SET bufferOutline;
567 SHAPE_POLY_SET bufferPolybase;
568
569 bufferPolybase.NewOutline();
570
571 // enter outline as polygon:
572 for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
573 {
574 TransformOvalToPolygon( bufferOutline, aCornerList[ ii - 1 ], aCornerList[ ii ],
576 }
577
578 // enter the initial polygon:
579 for( const VECTOR2I& corner : aCornerList )
580 bufferPolybase.Append( corner );
581
582 // Merge polygons to build the polygon which contains the initial
583 // polygon and its thick outline
584
585 // create the outline which contains thick outline:
586 bufferPolybase.BooleanAdd( bufferOutline );
587 bufferPolybase.Fracture();
588
589 if( bufferPolybase.OutlineCount() < 1 ) // should not happen
590 return;
591
592 const SHAPE_LINE_CHAIN& path = bufferPolybase.COutline( 0 );
593
594 if( path.PointCount() < 2 ) // should not happen
595 return;
596
597 // Now, output the final polygon to DXF file:
598 last = path.PointCount() - 1;
599 VECTOR2I point = path.CPoint( 0 );
600
601 VECTOR2I startPoint( point.x, point.y );
602 MoveTo( startPoint );
603
604 for( int ii = 1; ii < path.PointCount(); ii++ )
605 {
606 point = path.CPoint( ii );
607 LineTo( VECTOR2I( point.x, point.y ) );
608 }
609
610 // Close polygon, if needed
611 point = path.CPoint( last );
612 VECTOR2I endPoint( point.x, point.y );
613
614 if( endPoint != startPoint )
615 LineTo( startPoint );
616
617 PenFinish();
618}
619
620
621std::vector<VECTOR2I> arcPts( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
622 const EDA_ANGLE& aAngle, double aRadius )
623{
624 std::vector<VECTOR2I> pts;
625
626 /*
627 * Arcs are not so easily approximated by beziers (in the general case), so we approximate
628 * them in the old way
629 */
630 EDA_ANGLE startAngle = -aStartAngle;
631 EDA_ANGLE endAngle = startAngle - aAngle;
632 VECTOR2I start;
634 const EDA_ANGLE delta( 5, DEGREES_T ); // increment to draw circles
635
636 if( startAngle > endAngle )
637 std::swap( startAngle, endAngle );
638
639 // Usual trig arc plotting routine...
640 start.x = KiROUND( aCenter.x + aRadius * ( -startAngle ).Cos() );
641 start.y = KiROUND( aCenter.y + aRadius * ( -startAngle ).Sin() );
642 pts.emplace_back( start );
643
644 for( EDA_ANGLE ii = startAngle + delta; ii < endAngle; ii += delta )
645 {
646 end.x = KiROUND( aCenter.x + aRadius * ( -ii ).Cos() );
647 end.y = KiROUND( aCenter.y + aRadius * ( -ii ).Sin() );
648 pts.emplace_back( end );
649 }
650
651 end.x = KiROUND( aCenter.x + aRadius * ( -endAngle ).Cos() );
652 end.y = KiROUND( aCenter.y + aRadius * ( -endAngle ).Sin() );
653 pts.emplace_back( end );
654
655 return pts;
656}
657
658
659void DXF_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aLineChain, FILL_T aFill, int aWidth, void* aData )
660{
661 std::set<size_t> handledArcs;
662 std::vector<VECTOR2I> cornerList;
663
664 for( int ii = 0; ii < aLineChain.SegmentCount(); ++ii )
665 {
666 if( aLineChain.IsArcSegment( ii ) )
667 {
668 size_t arcIndex = aLineChain.ArcIndex( ii );
669
670 if( !handledArcs.contains( arcIndex ) )
671 {
672 handledArcs.insert( arcIndex );
673 const SHAPE_ARC& arc( aLineChain.Arc( arcIndex ) );
674 std::vector<VECTOR2I> pts = arcPts( arc.GetCenter(), arc.GetStartAngle(),
675 arc.GetCentralAngle(), arc.GetRadius() );
676
677 for( const VECTOR2I& pt : std::ranges::reverse_view( pts ) )
678 cornerList.emplace_back( pt );
679 }
680 }
681 else
682 {
683 const SEG& seg( aLineChain.Segment( ii ) );
684 cornerList.emplace_back( seg.A );
685 cornerList.emplace_back( seg.B );
686 }
687 }
688
689 if( aLineChain.IsClosed() && cornerList.front() != cornerList.back() )
690 cornerList.emplace_back( aLineChain.CPoint( 0 ) );
691
692 PlotPoly( cornerList, aFill, aWidth, aData );
693}
694
695
696void DXF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
697{
698 wxASSERT( m_outputFile );
699
700 if( plume == 'Z' )
701 {
702 return;
703 }
704
705 VECTOR2D pos_dev = userToDeviceCoordinates( pos );
706 VECTOR2D pen_lastpos_dev = userToDeviceCoordinates( m_penLastpos );
707
708 if( m_penLastpos != pos && plume == 'D' )
709 {
712
713 // DXF LINE
714 wxString cname = getDXFColorName( m_currentColor );
715 const char* lname = getDXFLineType( static_cast<LINE_STYLE>( m_currentLineType ) );
716 fmt::print( m_outputFile, "0\nLINE\n8\n{}\n6\n{}\n10\n{}\n20\n{}\n11\n{}\n21\n{}\n",
717 TO_UTF8( cname ),
718 lname,
719 formatCoord( pen_lastpos_dev.x ),
720 formatCoord( pen_lastpos_dev.y ),
721 formatCoord( pos_dev.x ),
722 formatCoord( pos_dev.y ) );
723 }
724
725 m_penLastpos = pos;
726}
727
728
729void DXF_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
730{
731 wxASSERT( aLineStyle >= LINE_STYLE::FIRST_TYPE
732 && aLineStyle <= LINE_STYLE::LAST_TYPE );
733
734 m_currentLineType = aLineStyle;
735}
736
737
738void DXF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
739 const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill, int aWidth )
740{
741 wxASSERT( m_outputFile );
742
743 if( aRadius <= 0 )
744 return;
745
746 EDA_ANGLE startAngle = -aStartAngle;
747 EDA_ANGLE endAngle = startAngle - aAngle;
748
749 // In DXF, arcs are drawn CCW.
750 // If startAngle > endAngle, it is CW. So transform it to CCW
751 if( endAngle < startAngle )
752 std::swap( startAngle, endAngle );
753
754 VECTOR2D centre_device = userToDeviceCoordinates( aCenter );
755 double radius_device = userToDeviceSize( aRadius );
756
757 // Emit a DXF ARC entity
758 wxString cname = getDXFColorName( m_currentColor );
759 fmt::print( m_outputFile,
760 "0\nARC\n8\n{}\n10\n{}\n20\n{}\n40\n{}\n50\n{:.8f}\n51\n{:.8f}\n",
761 TO_UTF8( cname ),
762 formatCoord( centre_device.x ),
763 formatCoord( centre_device.y ),
764 formatCoord( radius_device ),
765 startAngle.AsDegrees(),
766 endAngle.AsDegrees() );
767}
768
769
770void DXF_PLOTTER::ThickSegment( const VECTOR2I& aStart, const VECTOR2I& aEnd, int aWidth, void* aData )
771{
772 const PLOT_PARAMS* cfg = static_cast<const PLOT_PARAMS*>( aData );
773
774 if( cfg && cfg->GetDXFPlotMode() == SKETCH )
775 {
776 std::vector<VECTOR2I> cornerList;
777 SHAPE_POLY_SET outlineBuffer;
778 TransformOvalToPolygon( outlineBuffer, aStart, aEnd, aWidth, GetPlotterArcHighDef(),
779 ERROR_INSIDE );
780 const SHAPE_LINE_CHAIN& path = outlineBuffer.COutline( 0 );
781
782 cornerList.reserve( path.PointCount() );
783
784 for( int jj = 0; jj < path.PointCount(); jj++ )
785 cornerList.emplace_back( path.CPoint( jj ).x, path.CPoint( jj ).y );
786
787 // Ensure the polygon is closed
788 if( cornerList[0] != cornerList[cornerList.size() - 1] )
789 cornerList.push_back( cornerList[0] );
790
792 }
793 else
794 {
795 MoveTo( aStart );
796 FinishTo( aEnd );
797 }
798}
799
800
801void DXF_PLOTTER::ThickArc( const VECTOR2D& centre, const EDA_ANGLE& aStartAngle,
802 const EDA_ANGLE& aAngle, double aRadius, int aWidth, void* aData )
803{
804 const PLOT_PARAMS* cfg = static_cast<const PLOT_PARAMS*>( aData );
805
806 if( cfg && cfg->GetDXFPlotMode() == SKETCH )
807 {
808 Arc( centre, aStartAngle, aAngle, aRadius - aWidth/2, FILL_T::NO_FILL, DXF_LINE_WIDTH );
809 Arc( centre, aStartAngle, aAngle, aRadius + aWidth/2, FILL_T::NO_FILL, DXF_LINE_WIDTH );
810 }
811 else
812 {
813 Arc( centre, aStartAngle, aAngle, aRadius, FILL_T::NO_FILL, DXF_LINE_WIDTH );
814 }
815}
816
817
818void DXF_PLOTTER::ThickRect( const VECTOR2I& p1, const VECTOR2I& p2, int width, void* aData )
819{
820 const PLOT_PARAMS* cfg = static_cast<const PLOT_PARAMS*>( aData );
821
822 if( cfg && cfg->GetDXFPlotMode() == SKETCH )
823 {
824 VECTOR2I offsetp1( p1.x - width/2, p1.y - width/2 );
825 VECTOR2I offsetp2( p2.x + width/2, p2.y + width/2 );
826 Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
827
828 offsetp1.x += width;
829 offsetp1.y += width;
830 offsetp2.x -= width;
831 offsetp2.y -= width;
832 Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
833 }
834 else
835 {
836 Rect( p1, p2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
837 }
838}
839
840
841void DXF_PLOTTER::ThickCircle( const VECTOR2I& pos, int diametre, int width, void* aData )
842{
843 const PLOT_PARAMS* cfg = static_cast<const PLOT_PARAMS*>( aData );
844
845 if( cfg && cfg->GetDXFPlotMode() == SKETCH )
846 {
847 Circle( pos, diametre - width, FILL_T::NO_FILL, DXF_LINE_WIDTH );
848 Circle( pos, diametre + width, FILL_T::NO_FILL, DXF_LINE_WIDTH );
849 }
850 else
851 {
852 Circle( pos, diametre, FILL_T::NO_FILL, DXF_LINE_WIDTH );
853 }
854}
855
856
857void DXF_PLOTTER::FilledCircle( const VECTOR2I& pos, int diametre, void* aData )
858{
859 const PLOT_PARAMS* cfg = static_cast<const PLOT_PARAMS*>( aData );
860
861 if( cfg && cfg->GetDXFPlotMode() == SKETCH )
862 Circle( pos, diametre, FILL_T::NO_FILL, DXF_LINE_WIDTH );
863 else
864 Circle( pos, diametre, FILL_T::FILLED_SHAPE, 0 );
865}
866
867
868void DXF_PLOTTER::ThickPoly( const SHAPE_POLY_SET& aPoly, int aWidth, void* aData )
869{
870 const PLOT_PARAMS* cfg = static_cast<const PLOT_PARAMS*>( aData );
871
872 if( cfg && cfg->GetDXFPlotMode() == SKETCH )
873 {
874 SHAPE_POLY_SET outline = aPoly.CloneDropTriangulation();
877
878 outline = aPoly.CloneDropTriangulation();
881 }
882 else
883 {
884 PLOTTER::PlotPoly( aPoly.COutline( 0 ), FILL_T::NO_FILL, aWidth, aData );
885 }
886}
887
888
889void DXF_PLOTTER::FlashPadOval( const VECTOR2I& aPos, const VECTOR2I& aSize,
890 const EDA_ANGLE& aOrient, void* aData )
891{
892 wxASSERT( m_outputFile );
893
894 VECTOR2I size( aSize );
895 EDA_ANGLE orient( aOrient );
896
897 /* The chip is reduced to an oval tablet with size.y > size.x
898 * (Oval vertical orientation 0) */
899 if( size.x > size.y )
900 {
901 std::swap( size.x, size.y );
902 orient += ANGLE_90;
903 }
904
905 ThickOval( aPos, size, orient, DXF_LINE_WIDTH, aData );
906}
907
908
909void DXF_PLOTTER::FlashPadCircle( const VECTOR2I& pos, int diametre, void* aData )
910{
911 wxASSERT( m_outputFile );
912 Circle( pos, diametre, FILL_T::NO_FILL, DXF_LINE_WIDTH );
913}
914
915
916void DXF_PLOTTER::FlashPadRect( const VECTOR2I& aPos, const VECTOR2I& aPadSize,
917 const EDA_ANGLE& aOrient, void* aData )
918{
919 wxASSERT( m_outputFile );
920
921 VECTOR2I size, start, end;
922
923 size.x = aPadSize.x / 2;
924 size.y = aPadSize.y / 2;
925
926 if( size.x < 0 )
927 size.x = 0;
928
929 if( size.y < 0 )
930 size.y = 0;
931
932 // If a dimension is zero, the trace is reduced to 1 line
933 if( size.x == 0 )
934 {
935 start = VECTOR2I( aPos.x, aPos.y - size.y );
936 end = VECTOR2I( aPos.x, aPos.y + size.y );
937 RotatePoint( start, aPos, aOrient );
938 RotatePoint( end, aPos, aOrient );
939 MoveTo( start );
940 FinishTo( end );
941 return;
942 }
943
944 if( size.y == 0 )
945 {
946 start = VECTOR2I( aPos.x - size.x, aPos.y );
947 end = VECTOR2I( aPos.x + size.x, aPos.y );
948 RotatePoint( start, aPos, aOrient );
949 RotatePoint( end, aPos, aOrient );
950 MoveTo( start );
951 FinishTo( end );
952 return;
953 }
954
955 start = VECTOR2I( aPos.x - size.x, aPos.y - size.y );
956 RotatePoint( start, aPos, aOrient );
957 MoveTo( start );
958
959 end = VECTOR2I( aPos.x - size.x, aPos.y + size.y );
960 RotatePoint( end, aPos, aOrient );
961 LineTo( end );
962
963 end = VECTOR2I( aPos.x + size.x, aPos.y + size.y );
964 RotatePoint( end, aPos, aOrient );
965 LineTo( end );
966
967 end = VECTOR2I( aPos.x + size.x, aPos.y - size.y );
968 RotatePoint( end, aPos, aOrient );
969 LineTo( end );
970
971 FinishTo( start );
972}
973
974
975void DXF_PLOTTER::FlashPadRoundRect( const VECTOR2I& aPadPos, const VECTOR2I& aSize,
976 int aCornerRadius, const EDA_ANGLE& aOrient, void* aData )
977{
978 SHAPE_POLY_SET outline;
979 TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient, aCornerRadius, 0.0, 0,
981
982 // TransformRoundRectToPolygon creates only one convex polygon
983 SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
984
985 MoveTo( VECTOR2I( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
986
987 for( int ii = 1; ii < poly.PointCount(); ++ii )
988 LineTo( VECTOR2I( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
989
990 FinishTo( VECTOR2I( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
991}
992
993
994void DXF_PLOTTER::FlashPadCustom( const VECTOR2I& aPadPos, const VECTOR2I& aSize,
995 const EDA_ANGLE& aOrient, SHAPE_POLY_SET* aPolygons,
996 void* aData )
997{
998 for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt )
999 {
1000 SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt );
1001
1002 MoveTo( VECTOR2I( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
1003
1004 for( int ii = 1; ii < poly.PointCount(); ++ii )
1005 LineTo( VECTOR2I( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
1006
1007 FinishTo( VECTOR2I( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
1008 }
1009}
1010
1011
1012void DXF_PLOTTER::FlashPadTrapez( const VECTOR2I& aPadPos, const VECTOR2I* aCorners,
1013 const EDA_ANGLE& aPadOrient, void* aData )
1014{
1015 wxASSERT( m_outputFile );
1016 VECTOR2I coord[4]; /* coord actual corners of a trapezoidal trace */
1017
1018 for( int ii = 0; ii < 4; ii++ )
1019 {
1020 coord[ii] = aCorners[ii];
1021 RotatePoint( coord[ii], aPadOrient );
1022 coord[ii] += aPadPos;
1023 }
1024
1025 // Plot edge:
1026 MoveTo( coord[0] );
1027 LineTo( coord[1] );
1028 LineTo( coord[2] );
1029 LineTo( coord[3] );
1030 FinishTo( coord[0] );
1031}
1032
1033
1034void DXF_PLOTTER::FlashRegularPolygon( const VECTOR2I& aShapePos, int aRadius, int aCornerCount,
1035 const EDA_ANGLE& aOrient, void* aData )
1036{
1037 // Do nothing
1038 wxASSERT( 0 );
1039}
1040
1041
1049bool containsNonAsciiChars( const wxString& string )
1050{
1051 for( unsigned i = 0; i < string.length(); i++ )
1052 {
1053 wchar_t ch = string[i];
1054
1055 if( ch > 255 )
1056 return true;
1057 }
1058 return false;
1059}
1060
1061
1062void DXF_PLOTTER::Text( const VECTOR2I& aPos,
1063 const COLOR4D& aColor,
1064 const wxString& aText,
1065 const EDA_ANGLE& aOrient,
1066 const VECTOR2I& aSize,
1067 enum GR_TEXT_H_ALIGN_T aH_justify,
1068 enum GR_TEXT_V_ALIGN_T aV_justify,
1069 int aWidth,
1070 bool aItalic,
1071 bool aBold,
1072 bool aMultilineAllowed,
1073 KIFONT::FONT* aFont,
1074 const KIFONT::METRICS& aFontMetrics,
1075 void* aData )
1076{
1077 // Fix me: see how to use DXF text mode for multiline texts
1078 if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
1079 aMultilineAllowed = false; // the text has only one line.
1080
1081 bool processSuperSub = aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) );
1082
1083 if( m_textAsLines || containsNonAsciiChars( aText ) || aMultilineAllowed || processSuperSub )
1084 {
1085 // output text as graphics.
1086 // Perhaps multiline texts could be handled as DXF text entity
1087 // but I do not want spend time about this (JPC)
1088 PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify, aWidth, aItalic,
1089 aBold, aMultilineAllowed, aFont, aFontMetrics, aData );
1090 }
1091 else
1092 {
1093 TEXT_ATTRIBUTES attrs;
1094 attrs.m_Halign = aH_justify;
1095 attrs.m_Valign =aV_justify;
1096 attrs.m_StrokeWidth = aWidth;
1097 attrs.m_Angle = aOrient;
1098 attrs.m_Italic = aItalic;
1099 attrs.m_Bold = aBold;
1100 attrs.m_Mirrored = aSize.x < 0;
1101 attrs.m_Multiline = false;
1102 plotOneLineOfText( aPos, aColor, aText, attrs );
1103 }
1104}
1105
1106
1108 const COLOR4D& aColor,
1109 const wxString& aText,
1110 const TEXT_ATTRIBUTES& aAttributes,
1111 KIFONT::FONT* aFont,
1112 const KIFONT::METRICS& aFontMetrics,
1113 void* aData )
1114{
1115 TEXT_ATTRIBUTES attrs = aAttributes;
1116
1117 // Fix me: see how to use DXF text mode for multiline texts
1118 if( attrs.m_Multiline && !aText.Contains( wxT( "\n" ) ) )
1119 attrs.m_Multiline = false; // the text has only one line.
1120
1121 bool processSuperSub = aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) );
1122
1123 if( m_textAsLines || containsNonAsciiChars( aText ) || attrs.m_Multiline || processSuperSub )
1124 {
1125 // output text as graphics.
1126 // Perhaps multiline texts could be handled as DXF text entity
1127 // but I do not want spend time about that (JPC)
1128 PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aFontMetrics, aData );
1129 }
1130 else
1131 {
1132 plotOneLineOfText( aPos, aColor, aText, attrs );
1133 }
1134}
1135
1136
1137void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor,
1138 const wxString& aText, const TEXT_ATTRIBUTES& aAttributes )
1139{
1140 /* Emit text as a text entity. This loses formatting and shape but it's
1141 more useful as a CAD object */
1142 VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
1143 SetColor( aColor );
1144 wxString cname = getDXFColorName( m_currentColor );
1145 VECTOR2D size_dev = userToDeviceSize( aAttributes.m_Size );
1146 int h_code = 0, v_code = 0;
1147
1148 switch( aAttributes.m_Halign )
1149 {
1150 case GR_TEXT_H_ALIGN_LEFT: h_code = 0; break;
1151 case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
1152 case GR_TEXT_H_ALIGN_RIGHT: h_code = 2; break;
1153 case GR_TEXT_H_ALIGN_INDETERMINATE: wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) ); break;
1154 }
1155
1156 switch( aAttributes.m_Valign )
1157 {
1158 case GR_TEXT_V_ALIGN_TOP: v_code = 3; break;
1159 case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
1160 case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
1161 case GR_TEXT_V_ALIGN_INDETERMINATE: wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) ); break;
1162 }
1163
1164 std::string textStyle = "KICAD";
1165 if( aAttributes.m_Bold )
1166 {
1167 if( aAttributes.m_Italic )
1168 textStyle = "KICADBI";
1169 else
1170 textStyle = "KICADB";
1171 }
1172 else if( aAttributes.m_Italic )
1173 textStyle = "KICADI";
1174
1175 // Position, size, rotation and alignment
1176 // The two alignment point usages is somewhat idiot (see the DXF ref)
1177 // Anyway since we don't use the fit/aligned options, they're the same
1178 fmt::print( m_outputFile,
1179 " 0\n"
1180 "TEXT\n"
1181 " 7\n"
1182 "{}\n" // Text style
1183 " 8\n"
1184 "{}\n" // Layer name
1185 " 10\n"
1186 "{}\n" // First point X
1187 " 11\n"
1188 "{}\n" // Second point X
1189 " 20\n"
1190 "{}\n" // First point Y
1191 " 21\n"
1192 "{}\n" // Second point Y
1193 " 40\n"
1194 "{}\n" // Text height
1195 " 41\n"
1196 "{}\n" // Width factor
1197 " 50\n"
1198 "{:.8f}\n" // Rotation
1199 " 51\n"
1200 "{:.8f}\n" // Oblique angle
1201 " 71\n"
1202 "{}\n" // Mirror flags
1203 " 72\n"
1204 "{}\n" // H alignment
1205 " 73\n"
1206 "{}\n", // V alignment
1207 textStyle,
1208 TO_UTF8( cname ),
1209 formatCoord( origin_dev.x ),
1210 formatCoord( origin_dev.x ),
1211 formatCoord( origin_dev.y ),
1212 formatCoord( origin_dev.y ),
1213 formatCoord( size_dev.y ),
1214 formatCoord( fabs( size_dev.x / size_dev.y ) ),
1215 aAttributes.m_Angle.AsDegrees(),
1216 aAttributes.m_Italic ? DXF_OBLIQUE_ANGLE : 0,
1217 aAttributes.m_Mirrored ? 2 : 0, // X mirror flag
1218 h_code, v_code );
1219
1220 /* There are two issue in emitting the text:
1221 - Our overline character (~) must be converted to the appropriate
1222 control sequence %%O or %%o
1223 - Text encoding in DXF is more or less unspecified since depends on
1224 the DXF declared version, the acad version reading it *and* some
1225 system variables to be put in the header handled only by newer acads
1226 Also before R15 unicode simply is not supported (you need to use
1227 bigfonts which are a massive PITA). Common denominator solution:
1228 use Latin1 (and however someone could choke on it, anyway). Sorry
1229 for the extended latin people. If somewant want to try fixing this
1230 recent version seems to use UTF-8 (and not UCS2 like the rest of
1231 Windows)
1232
1233 XXX Actually there is a *third* issue: older DXF formats are limited
1234 to 255 bytes records (it was later raised to 2048); since I'm lazy
1235 and text so long is not probable I just don't implement this rule.
1236 If someone is interested in fixing this, you have to emit the first
1237 partial lines with group code 3 (max 250 bytes each) and then finish
1238 with a group code 1 (less than 250 bytes). The DXF refs explains it
1239 in no more details...
1240 */
1241
1242 int braceNesting = 0;
1243 int overbarDepth = -1;
1244
1245 fmt::print( m_outputFile, " 1\n" );
1246
1247 for( unsigned int i = 0; i < aText.length(); i++ )
1248 {
1249 /* Here I do a bad thing: writing the output one byte at a time!
1250 but today I'm lazy and I have no idea on how to coerce a Unicode
1251 wxString to spit out latin1 encoded text ...
1252
1253 At least stdio is *supposed* to do output buffering, so there is
1254 hope is not too slow */
1255 wchar_t ch = aText[i];
1256
1257 if( ch > 255 )
1258 {
1259 // I can't encode this...
1260 putc( '?', m_outputFile );
1261 }
1262 else
1263 {
1264 if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
1265 {
1266 fmt::print( m_outputFile, "%%o" );
1267 overbarDepth = braceNesting;
1268
1269 // Skip the '{'
1270 i++;
1271 continue;
1272 }
1273 else if( aText[i] == '{' )
1274 {
1275 braceNesting++;
1276 }
1277 else if( aText[i] == '}' )
1278 {
1279 if( braceNesting > 0 )
1280 braceNesting--;
1281
1282 if( braceNesting == overbarDepth )
1283 {
1284 fmt::print( m_outputFile, "%%O" );
1285 overbarDepth = -1;
1286 continue;
1287 }
1288 }
1289
1290 putc( ch, m_outputFile );
1291 }
1292 }
1293
1294 fmt::print( m_outputFile, "\n" );
1295}
int color
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....
static const struct @110355335012326036072316124131344246226335322120 dxf_layer[NBCOLORS]
The layer/colors palette.
static std::string formatCoord(double aValue)
bool containsNonAsciiChars(const wxString &string)
Check if a given string contains non-ASCII characters.
std::vector< VECTOR2I > arcPts(const VECTOR2D &aCenter, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aRadius)
static const char * getDXFLineType(LINE_STYLE aType)
const char * name
#define DXF_LINE_WIDTH
@ ERROR_INSIDE
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
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
static const COLOR4D WHITE
Definition color4d.h:401
static const COLOR4D BLACK
Definition color4d.h:402
void plotOneLineOfText(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const TEXT_ATTRIBUTES &aAttrs)
DXF_UNITS m_plotUnits
virtual void PlotText(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const TEXT_ATTRIBUTES &aAttributes, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, void *aData=nullptr) override
bool m_textAsLines
virtual void FlashPadCustom(const VECTOR2I &aPadPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, SHAPE_POLY_SET *aPolygons, void *aData) override
virtual void ThickCircle(const VECTOR2I &pos, int diametre, int width, void *aData) override
void SetUnits(DXF_UNITS aUnit)
Set the units to use for plotting the DXF file.
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the scale/position for the DXF plot.
virtual void ThickArc(const VECTOR2D &aCentre, const EDA_ANGLE &aStAngle, const EDA_ANGLE &aAngle, double aRadius, int aWidth, void *aData) override
virtual void Arc(const VECTOR2D &aCenter, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aRadius, FILL_T aFill, int aWidth) override
double GetUnitScaling() const
Get the scale factor to apply to convert the device units to be in the currently set units.
virtual void FlashPadOval(const VECTOR2I &aPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, void *aData) override
DXF oval pad: always done in sketch mode.
virtual void FlashPadRect(const VECTOR2I &aPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, void *aData) override
DXF rectangular pad: always done in sketch mode.
virtual void ThickRect(const VECTOR2I &p1, const VECTOR2I &p2, int width, void *aData) override
virtual void FlashPadRoundRect(const VECTOR2I &aPadPos, const VECTOR2I &aSize, int aCornerRadius, const EDA_ANGLE &aOrient, void *aData) override
virtual void ThickPoly(const SHAPE_POLY_SET &aPoly, int aWidth, void *aData) 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.
virtual void FlashPadTrapez(const VECTOR2I &aPadPos, const VECTOR2I *aCorners, const EDA_ANGLE &aPadOrient, void *aData) override
DXF trapezoidal pad: only sketch mode is supported.
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width) override
DXF circle: full functionality; it even does 'fills' drawing a circle with a dual-arc polyline wide a...
virtual void FlashPadCircle(const VECTOR2I &pos, int diametre, 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...
virtual void FilledCircle(const VECTOR2I &pos, int diametre, void *aData) override
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth, 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
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width, int aCornerRadius=0) override
DXF rectangle: fill not supported.
virtual bool EndPlot() override
virtual void FlashRegularPolygon(const VECTOR2I &aShapePos, int aDiameter, int aCornerCount, const EDA_ANGLE &aOrient, void *aData) override
Flash a regular polygon.
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, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, void *aData=nullptr) override
Draw text with the plotter.
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData) override
double m_unitScalingFactor
virtual void SetDash(int aLineWidth, LINE_STYLE aLineStyle) override
COLOR4D m_currentColor
LINE_STYLE m_currentLineType
double AsDegrees() const
Definition eda_angle.h:116
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:131
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
double r
Red component.
Definition color4d.h:392
double g
Green component.
Definition color4d.h:393
double b
Blue component.
Definition color4d.h:394
bool m_plotMirror
Definition plotter.h:654
void MoveTo(const VECTOR2I &pos)
Definition plotter.h:262
virtual void ThickOval(const VECTOR2I &aPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, int aWidth, void *aData)
Definition plotter.cpp:486
void FinishTo(const VECTOR2I &pos)
Definition plotter.h:272
double m_iuPerDeviceUnit
Definition plotter.h:651
VECTOR2I m_plotOffset
Definition plotter.h:653
VECTOR2I m_penLastpos
Definition plotter.h:667
virtual VECTOR2D userToDeviceCoordinates(const VECTOR2I &aCoordinate)
Modify coordinates according to the orientation, scale factor, and offsets trace.
Definition plotter.cpp:92
VECTOR2I m_paperSize
Definition plotter.h:675
virtual VECTOR2D userToDeviceSize(const VECTOR2I &size)
Modify size according to the plotter scale factors (VECTOR2I version, returns a VECTOR2D).
Definition plotter.cpp:117
int GetPlotterArcHighDef() const
Definition plotter.h:228
double m_plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition plotter.h:643
bool GetColorMode() const
Definition plotter.h:149
FILE * m_outputFile
Output file.
Definition plotter.h:660
void LineTo(const VECTOR2I &pos)
Definition plotter.h:267
void PenFinish()
Definition plotter.h:278
virtual void PlotText(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const TEXT_ATTRIBUTES &aAttributes, KIFONT::FONT *aFont=nullptr, const KIFONT::METRICS &aFontMetrics=KIFONT::METRICS::Default(), void *aData=nullptr)
Definition plotter.cpp:695
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth, void *aData)=0
Draw a polygon ( filled or not ).
virtual void Text(const VECTOR2I &aPos, const COLOR4D &aColor, const wxString &aText, const EDA_ANGLE &aOrient, const VECTOR2I &aSize, enum GR_TEXT_H_ALIGN_T aH_justify, enum GR_TEXT_V_ALIGN_T aV_justify, int aPenWidth, bool aItalic, bool aBold, bool aMultilineAllowed, KIFONT::FONT *aFont, const KIFONT::METRICS &aFontMetrics, void *aData=nullptr)
Draw text with the plotter.
Definition plotter.cpp:625
double m_IUsPerDecimil
Definition plotter.h:649
bool m_colorMode
Definition plotter.h:663
virtual DXF_OUTLINE_MODE GetDXFPlotMode() const
Definition plotter.h:109
Definition seg.h:42
VECTOR2I A
Definition seg.h:49
VECTOR2I B
Definition seg.h:50
EDA_ANGLE GetCentralAngle() const
Get the "central angle" of the arc - this is the angle at the point of the "pie slice".
double GetRadius() const
EDA_ANGLE GetStartAngle() const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
bool IsArcSegment(size_t aSegment) const
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
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.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET CloneDropTriangulation() const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const SHAPE_LINE_CHAIN Outline() const
void SetRadius(int aRadius)
Definition shape_rect.h:206
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
EDA_COLOR_T
Legacy color enumeration.
Definition color4d.h:42
@ NBCOLORS
Number of colors.
Definition color4d.h:79
@ BLACK
Definition color4d.h:44
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.
@ ROUND_ALL_CORNERS
All angles are rounded.
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
@ DEGREES_T
Definition eda_angle.h:31
FILL_T
Definition eda_shape.h:56
@ NO_FILL
Definition eda_shape.h:57
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
This file contains miscellaneous commonly used macros and functions.
DXF_UNITS
Definition plotter.h:52
@ SKETCH
Definition plotter.h:81
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
LINE_STYLE
Dashed line types.
int radius
VECTOR2I end
int delta
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_H_ALIGN_INDETERMINATE
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_INDETERMINATE
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694