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