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