KiCad PCB EDA Suite
gerber_draw_item.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 1992-2017 <Jean-Pierre Charras>
5 * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <base_units.h>
26#include <trigo.h>
27#include <bitmaps.h>
28#include <eda_text.h>
29#include <gerbview_frame.h>
31#include <gerber_draw_item.h>
32#include <gerber_file_image.h>
34#include <string_utils.h>
35#include <geometry/shape_arc.h>
36#include <math/util.h> // for KiROUND
37#include <widgets/msgpanel.h>
38
39#include <wx/msgdlg.h>
40
43{
44 m_GerberImageFile = aGerberImageFile;
46 m_Flashed = false;
47 m_DCode = 0;
48 m_UnitsMetric = false;
49 m_LayerNegative = false;
50 m_swapAxis = false;
51 m_mirrorA = false;
52 m_mirrorB = false;
53 m_drawScale.x = m_drawScale.y = 1.0;
54 m_lyrRotation = 0;
55
58}
59
60
62{
63}
64
65
67{
68 m_netAttributes = aNetAttributes;
69
72 {
73 m_GerberImageFile->m_ComponentsList.insert( std::make_pair( m_netAttributes.m_Cmpref, 0 ) );
74 }
75
77 m_GerberImageFile->m_NetnamesList.insert( std::make_pair( m_netAttributes.m_Netname, 0 ) );
78}
79
80
82{
83 // Return the layer this item is on, or 0 if the m_GerberImageFile is null.
85}
86
87
88bool GERBER_DRAW_ITEM::GetTextD_CodePrms( int& aSize, VECTOR2I& aPos, EDA_ANGLE& aOrientation )
89{
90 // calculate the best size and orientation of the D_Code text
91
92 if( m_DCode <= 0 )
93 return false; // No D_Code for this item
94
95 if( m_Flashed || m_Shape == GBR_ARC )
96 aPos = m_Start;
97 else // it is a line:
98 aPos = ( m_Start + m_End) / 2;
99
100 aPos = GetABPosition( aPos );
101
102 int size; // the best size for the text
103
104 if( GetDcodeDescr() )
105 size = GetDcodeDescr()->GetShapeDim( this );
106 else
107 size = std::min( m_Size.x, m_Size.y );
108
109 aOrientation = ANGLE_HORIZONTAL;
110
111 if( m_Flashed )
112 {
113 // A reasonable size for text is min_dim/3 because most of time this text has 3 chars.
114 aSize = size / 3;
115 }
116 else // this item is a line
117 {
120
121 aOrientation = angle.Normalize90();
122
123 // A reasonable size for text is size/2 because text needs margin below and above it.
124 // a margin = size/4 seems good, expecting the line len is large enough to show 3 chars,
125 // that is the case most of time.
126 aSize = size / 2;
127 }
128
129 return true;
130}
131
132
134{
135 /* Note: RS274Xrevd_e is obscure about the order of transforms:
136 * For instance: Rotation must be made after or before mirroring ?
137 * Note: if something is changed here, GetYXPosition must reflect changes
138 */
139 VECTOR2I abPos = aXYPosition + m_GerberImageFile->m_ImageJustifyOffset;
140
141 if( m_swapAxis )
142 std::swap( abPos.x, abPos.y );
143
145 abPos.x = KiROUND( abPos.x * m_drawScale.x );
146 abPos.y = KiROUND( abPos.y * m_drawScale.y );
148
149 if( !rotation.IsZero() )
150 RotatePoint( abPos, -rotation );
151
152 // Negate A axis if mirrored
153 if( m_mirrorA )
154 abPos.x = -abPos.x;
155
156 // abPos.y must be negated when no mirror, because draw axis is top to bottom
157 if( !m_mirrorB )
158 abPos.y = -abPos.y;
159
160 return abPos;
161}
162
163
165{
166 // do the inverse transform made by GetABPosition
167 VECTOR2I xyPos = aABPosition;
168
169 if( m_mirrorA )
170 xyPos.x = -xyPos.x;
171
172 if( !m_mirrorB )
173 xyPos.y = -xyPos.y;
174
176
177 if( !rotation.IsZero() )
178 RotatePoint( xyPos, rotation );
179
180 xyPos.x = KiROUND( xyPos.x / m_drawScale.x );
181 xyPos.y = KiROUND( xyPos.y / m_drawScale.y );
183
184 if( m_swapAxis )
185 std::swap( xyPos.x, xyPos.y );
186
188}
189
190
192{
194 m_swapAxis = m_GerberImageFile->m_SwapAxis; // false if A = X, B = Y;
195
196 // true if A =Y, B = Y
197 m_mirrorA = m_GerberImageFile->m_MirrorA; // true: mirror / axe A
198 m_mirrorB = m_GerberImageFile->m_MirrorB; // true: mirror / axe B
199 m_drawScale = m_GerberImageFile->m_Scale; // A and B scaling factor
200 m_layerOffset = m_GerberImageFile->m_Offset; // Offset from OF command
201
202 // Rotation from RO command:
205}
206
207
209{
210 switch( m_Shape )
211 {
212 case GBR_SEGMENT: return _( "Line" );
213 case GBR_ARC: return _( "Arc" );
214 case GBR_CIRCLE: return _( "Circle" );
215 case GBR_SPOT_OVAL: return wxT( "spot_oval" );
216 case GBR_SPOT_CIRCLE: return wxT( "spot_circle" );
217 case GBR_SPOT_RECT: return wxT( "spot_rect" );
218 case GBR_SPOT_POLY: return wxT( "spot_poly" );
219 case GBR_POLYGON: return wxT( "polygon" );
220
221 case GBR_SPOT_MACRO:
222 {
223 wxString name = wxT( "apt_macro" );
224 D_CODE* dcode = GetDcodeDescr();
225
226 if( dcode && dcode->GetMacro() )
227 name << wxT(" ") << dcode->GetMacro()->name;
228
229 return name;
230 }
231
232 default: return wxT( "??" );
233 }
234}
235
236
238{
239 if( ( m_DCode < FIRST_DCODE ) || ( m_DCode > LAST_DCODE ) )
240 return nullptr;
241
242 if( m_GerberImageFile == nullptr )
243 return nullptr;
244
246}
247
248
250{
251 // return a rectangle which is (pos,dim) in nature. therefore the +1
252 BOX2I bbox( m_Start, VECTOR2I( 1, 1 ) );
253 D_CODE* code = GetDcodeDescr();
254
255 // TODO(JE) GERBER_DRAW_ITEM maybe should actually be a number of subclasses.
256 // Until/unless that is changed, we need to do different things depending on
257 // what is actually being represented by this GERBER_DRAW_ITEM.
258
259 switch( m_Shape )
260 {
261 case GBR_POLYGON:
262 {
263 BOX2I bb = m_Polygon.BBox();
264 bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
265 bbox.SetOrigin( bb.GetOrigin() );
266 break;
267 }
268
269 case GBR_CIRCLE:
270 {
271 double radius = GetLineLength( m_Start, m_End );
272 bbox.Inflate( radius, radius );
273 break;
274 }
275
276 case GBR_ARC:
277 {
278 EDA_ANGLE angle( atan2( double( m_End.y - m_ArcCentre.y ),
279 double( m_End.x - m_ArcCentre.x ) )
280 - atan2( double( m_Start.y - m_ArcCentre.y ),
281 double( m_Start.x - m_ArcCentre.x ) ),
282 RADIANS_T );
283
284 if( m_End == m_Start ) // Arc with the end point = start point is expected to be a circle.
286 else
287 angle.Normalize();
288
290 bbox = arc.BBox( m_Size.x / 2 ); // m_Size.x is the line thickness
291 break;
292 }
293
294 case GBR_SPOT_CIRCLE:
295 {
296 if( code )
297 {
298 int radius = code->m_Size.x >> 1;
299 bbox.Inflate( radius, radius );
300 }
301
302 break;
303 }
304
305 case GBR_SPOT_RECT:
306 {
307 if( code )
308 bbox.Inflate( code->m_Size.x / 2, code->m_Size.y / 2 );
309
310 break;
311 }
312
313 case GBR_SPOT_OVAL:
314 {
315 if( code )
316 bbox.Inflate( code->m_Size.x /2, code->m_Size.y / 2 );
317
318 break;
319 }
320
321 case GBR_SPOT_POLY:
322 {
323 if( code )
324 {
325 if( code->m_Polygon.OutlineCount() == 0 )
326 code->ConvertShapeToPolygon( this );
327
328 bbox.Inflate( code->m_Polygon.BBox().GetWidth() / 2,
329 code->m_Polygon.BBox().GetHeight() / 2 );
330 }
331
332 break;
333 }
334 case GBR_SPOT_MACRO:
335 {
336 if( code )
337 {
338 // Update the shape drawings and the bounding box coordinates:
339 code->GetMacro()->GetApertureMacroShape( this, m_Start );
340
341 // now the bounding box is valid:
342 bbox = code->GetMacro()->GetBoundingBox();
343 }
344
345 break;
346 }
347
348 case GBR_SEGMENT:
349 {
350 if( code && code->m_Shape == APT_RECT )
351 {
352 if( m_Polygon.OutlineCount() == 0 )
353 {
354 // We cannot initialize m_Polygon, because we are in a const function.
355 // So use a temporary polygon
356 SHAPE_POLY_SET poly_shape;
357 ConvertSegmentToPolygon( &poly_shape );
358 bbox = poly_shape.BBox();
359 }
360
361 else
362 {
363 bbox = m_Polygon.BBox();
364 }
365 }
366 else
367 {
368 int radius = ( m_Size.x + 1 ) / 2;
369
370 int ymax = std::max( m_Start.y, m_End.y ) + radius;
371 int xmax = std::max( m_Start.x, m_End.x ) + radius;
372
373 int ymin = std::min( m_Start.y, m_End.y ) - radius;
374 int xmin = std::min( m_Start.x, m_End.x ) - radius;
375
376 bbox = BOX2I( VECTOR2I( xmin, ymin ), VECTOR2I( xmax - xmin + 1, ymax - ymin + 1 ) );
377 }
378
379 break;
380 }
381 default:
382 wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
383 break;
384 }
385
386 // calculate the corners coordinates in current Gerber axis orientations
387 VECTOR2I org = GetABPosition( bbox.GetOrigin() );
388 VECTOR2I end = GetABPosition( bbox.GetEnd() );
389
390 // Set the corners position:
391 bbox.SetOrigin( org );
392 bbox.SetEnd( end );
393 bbox.Normalize();
394
395 return bbox;
396}
397
398
399void GERBER_DRAW_ITEM::MoveXY( const VECTOR2I& aMoveVector )
400{
401 m_Start += aMoveVector;
402 m_End += aMoveVector;
403 m_ArcCentre += aMoveVector;
404
405 m_Polygon.Move( aMoveVector );
406}
407
408
410{
412
413 // if isClear is true, this item has negative shape
414 return isClear;
415}
416
417
418void GERBER_DRAW_ITEM::Print( wxDC* aDC, const VECTOR2I& aOffset, GBR_DISPLAY_OPTIONS* aOptions )
419{
420 // used when a D_CODE is not found. default D_CODE to draw a flashed item
421 static D_CODE dummyD_CODE( 0 );
422 bool isFilled;
423 int radius;
424 int halfPenWidth;
425 static bool show_err;
426 D_CODE* d_codeDescr = GetDcodeDescr();
427
428 if( d_codeDescr == nullptr )
429 d_codeDescr = &dummyD_CODE;
430
432
433 /* isDark is true if flash is positive and should use a drawing
434 * color other than the background color, else use the background color
435 * when drawing so that an erasure happens.
436 */
438
439 if( !isDark )
440 {
441 // draw in background color ("negative" color)
442 color = aOptions->m_NegativeDrawColor;
443 }
444
445 isFilled = aOptions->m_DisplayLinesFill;
446
447 switch( m_Shape )
448 {
449 case GBR_POLYGON:
450 isFilled = aOptions->m_DisplayPolygonsFill;
451
452 if( !isDark )
453 isFilled = true;
454
455 PrintGerberPoly( aDC, color, aOffset, isFilled );
456 break;
457
458 case GBR_CIRCLE:
459 radius = KiROUND( GetLineLength( m_Start, m_End ) );
460
461 halfPenWidth = m_Size.x >> 1;
462
463 if( !isFilled )
464 {
465 // draw the border of the pen's path using two circles, each as narrow as possible
466 GRCircle( aDC, GetABPosition( m_Start ), radius - halfPenWidth, 0, color );
467 GRCircle( aDC, GetABPosition( m_Start ), radius + halfPenWidth, 0, color );
468 }
469 else // Filled mode
470 {
471 GRCircle( aDC, GetABPosition( m_Start ), radius, m_Size.x, color );
472 }
473
474 break;
475
476 case GBR_ARC:
477 // Currently, arcs plotted with a rectangular aperture are not supported.
478 // a round pen only is expected.
479 if( !isFilled )
480 {
483 }
484 else
485 {
488 }
489
490 break;
491
492 case GBR_SPOT_CIRCLE:
493 case GBR_SPOT_RECT:
494 case GBR_SPOT_OVAL:
495 case GBR_SPOT_POLY:
496 case GBR_SPOT_MACRO:
497 isFilled = aOptions->m_DisplayFlashedItemsFill;
498 d_codeDescr->DrawFlashedShape( this, aDC, color, m_Start, isFilled );
499 break;
500
501 case GBR_SEGMENT:
502 /* Plot a line from m_Start to m_End.
503 * Usually, a round pen is used, but some Gerber files use a rectangular pen
504 * In fact, any aperture can be used to plot a line.
505 * currently: only a square pen is handled (I believe using a polygon gives a strange plot).
506 */
507 if( d_codeDescr->m_Shape == APT_RECT )
508 {
509 if( m_Polygon.OutlineCount() == 0 )
511
512 PrintGerberPoly( aDC, color, aOffset, isFilled );
513 }
514 else if( !isFilled )
515 {
517 }
518 else
519 {
521 color );
522 }
523
524 break;
525
526 default:
527 if( !show_err )
528 {
529 wxMessageBox( wxT( "Trace_Segment() type error" ) );
530 show_err = true;
531 }
532
533 break;
534 }
535}
536
537
539{
540 aPolygon->RemoveAllContours();
541 aPolygon->NewOutline();
542
543 VECTOR2I start = m_Start;
544 VECTOR2I end = m_End;
545
546 // make calculations more easy if ensure start.x < end.x
547 // (only 2 quadrants to consider)
548 if( start.x > end.x )
549 std::swap( start, end );
550
551 // calculate values relative to start point:
552 VECTOR2I delta = end - start;
553
554 // calculate corners for the first quadrant only (delta.x and delta.y > 0 )
555 // currently, delta.x already is > 0.
556 // make delta.y > 0
557 bool change = delta.y < 0;
558
559 if( change )
560 delta.y = -delta.y;
561
562 // Now create the full polygon.
563 // Due to previous changes, the shape is always something like
564 // 3 4
565 // 2 5
566 // 1 6
567 VECTOR2I corner;
568 corner.x -= m_Size.x/2;
569 corner.y -= m_Size.y/2;
570 VECTOR2I close = corner;
571 aPolygon->Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
572 corner.y += m_Size.y;
573 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
574
575 if( delta.x || delta.y )
576 {
577 corner += delta;
578 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
579 }
580
581 corner.x += m_Size.x;
582 aPolygon->Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
583 corner.y -= m_Size.y;
584 aPolygon->Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
585
586 if( delta.x || delta.y )
587 {
588 corner -= delta;
589 aPolygon->Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
590 }
591
592 aPolygon->Append( VECTOR2I( close ) ); // close the shape
593
594 // Create final polygon:
595 if( change )
596 aPolygon->Mirror( false, true );
597
598 aPolygon->Move( VECTOR2I( start ) );
599}
600
601
603{
605}
606
607
608void GERBER_DRAW_ITEM::PrintGerberPoly( wxDC* aDC, const COLOR4D& aColor, const VECTOR2I& aOffset,
609 bool aFilledShape )
610{
611 std::vector<VECTOR2I> points;
613 int pointCount = poly.PointCount() - 1;
614
615 points.reserve( pointCount );
616
617 for( int ii = 0; ii < pointCount; ii++ )
618 {
619 VECTOR2I p( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
620 points[ii] = p + aOffset;
621 points[ii] = GetABPosition( points[ii] );
622 }
623
624 GRClosedPoly( aDC, pointCount, &points[0], aFilledShape, aColor );
625}
626
627
628void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
629{
630 wxString msg;
631 wxString text;
632
633 msg = ShowGBRShape();
634 aList.emplace_back( _( "Type" ), msg );
635
636 // Display D_Code value with its attributes for items using a DCode:
637 if( m_Shape == GBR_POLYGON ) // Has no DCode, but can have an attribute
638 {
639 msg = _( "Attribute" );
640
641 if( m_AperFunction.IsEmpty() )
642 text = _( "No attribute" );
643 else
645 }
646 else
647 {
648 msg.Printf( _( "D Code %d" ), m_DCode );
649 D_CODE* apertDescr = GetDcodeDescr();
650
651 if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
652 text = _( "No attribute" );
653 else
654 text = apertDescr->m_AperFunction;
655 }
656
657 aList.emplace_back( msg, text );
658
659 // Display graphic layer name
661 aList.emplace_back( _( "Graphic Layer" ), msg );
662
663 // Display item position
668
669 if( m_Flashed )
670 {
671 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
672 aList.emplace_back( _( "Position" ), msg );
673 }
674 else
675 {
676 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
677 aList.emplace_back( _( "Start" ), msg );
678
679 msg.Printf( wxT( "(%.4f, %.4f)" ), xEnd, yEnd );
680 aList.emplace_back( _( "End" ), msg );
681 }
682
683 // Display item rotation
684 // The full rotation is Image rotation + m_lyrRotation
685 // but m_lyrRotation is specific to this object
686 // so we display only this parameter
687 msg.Printf( wxT( "%f" ), m_lyrRotation );
688 aList.emplace_back( _( "Rotation" ), msg );
689
690 // Display item polarity (item specific)
691 msg = m_LayerNegative ? _("Clear") : _("Dark");
692 aList.emplace_back( _( "Polarity" ), msg );
693
694 // Display mirroring (item specific)
695 msg.Printf( wxT( "A:%s B:%s" ), m_mirrorA ? _( "Yes" ) : _( "No" ),
696 m_mirrorB ? _( "Yes" ) : _( "No" ) );
697 aList.emplace_back( _( "Mirror" ), msg );
698
699 // Display AB axis swap (item specific)
700 msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
701 aList.emplace_back( _( "AB axis" ), msg );
702
703 // Display net info, if exists
705 return;
706
707 // Build full net info:
708 wxString net_msg;
709 wxString cmp_pad_msg;
710
712 {
713 net_msg = _( "Net:" );
714 net_msg << wxS( " " );
715
716 if( m_netAttributes.m_Netname.IsEmpty() )
717 net_msg << wxT( "<no net>" );
718 else
720 }
721
723 {
725 {
726 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s" ),
729 }
730 else
731 {
732 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s Fct %s" ),
736 }
737 }
738
740 {
741 cmp_pad_msg = _( "Cmp:" );
742 cmp_pad_msg << wxS( " " ) << m_netAttributes.m_Cmpref;
743 }
744
745 aList.emplace_back( net_msg, cmp_pad_msg );
746}
747
748
750{
751 if( m_Flashed )
752 return BITMAPS::pad;
753
754 switch( m_Shape )
755 {
756 case GBR_SEGMENT:
757 case GBR_ARC:
758 case GBR_CIRCLE:
759 return BITMAPS::add_line;
760
761 case GBR_SPOT_OVAL:
762 case GBR_SPOT_CIRCLE:
763 case GBR_SPOT_RECT:
764 case GBR_SPOT_POLY:
765 case GBR_SPOT_MACRO:
766 // should be handles by m_Flashed == true
767 return BITMAPS::pad;
768
769 case GBR_POLYGON:
771 }
772
773 return BITMAPS::info;
774}
775
776
777bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
778{
779 // In case the item has a very tiny width defined, allow it to be selected
780 const int MIN_HIT_TEST_RADIUS = gerbIUScale.mmToIU( 0.01 );
781
782 // calculate aRefPos in XY Gerber axis:
783 VECTOR2I ref_pos = GetXYPosition( aRefPos );
784
785 SHAPE_POLY_SET poly;
786
787 switch( m_Shape )
788 {
789 case GBR_POLYGON:
790 poly = m_Polygon;
791 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
792
793 case GBR_SPOT_POLY:
794 poly = GetDcodeDescr()->m_Polygon;
795 poly.Move( VECTOR2I( m_Start ) );
796 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
797
798 case GBR_SPOT_RECT:
799 return GetBoundingBox().Contains( aRefPos );
800
801 case GBR_SPOT_OVAL:
802 {
803 BOX2I bbox = GetBoundingBox();
804
805 if( ! bbox.Contains( aRefPos ) )
806 return false;
807
808 // This is similar to a segment with thickness = min( m_Size.x, m_Size.y )
809 int radius = std::min( m_Size.x, m_Size.y )/2;
810 VECTOR2I start, end;
811
812 if( m_Size.x > m_Size.y ) // Horizontal oval
813 {
814 int len = m_Size.y - m_Size.x;
815 start.x = -len/2;
816 end.x = len/2;
817 }
818 else // Vertical oval
819 {
820 int len = m_Size.x - m_Size.y;
821 start.y = -len/2;
822 end.y = len/2;
823 }
824
825 start += bbox.Centre();
826 end += bbox.Centre();
827
828 if( radius < MIN_HIT_TEST_RADIUS )
829 radius = MIN_HIT_TEST_RADIUS;
830
831 return TestSegmentHit( aRefPos, start, end, radius );
832 }
833
834 case GBR_ARC:
835 {
836 double radius = GetLineLength( m_Start, m_ArcCentre );
837 VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
838
839 int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x );
840
841 // Are we close enough to the radius?
842 bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
843
844 if( radius_hit )
845 {
846 // Now check that we are within the arc angle
847
850 EDA_ANGLE start_angle( start );
851 EDA_ANGLE end_angle( end );
852
853 start_angle.Normalize();
854 end_angle.Normalize();
855
856 if( m_Start == m_End )
857 {
858 start_angle = ANGLE_0;
859 end_angle = ANGLE_360;
860 }
861 else if( end_angle < start_angle )
862 {
863 end_angle += ANGLE_360;
864 }
865
866 EDA_ANGLE test_angle( test_radius );
867 test_angle.Normalize();
868
869 return ( test_angle > start_angle && test_angle < end_angle );
870 }
871
872 return false;
873 }
874
875 case GBR_SPOT_MACRO:
876 // Aperture macro polygons are already in absolute coordinates
877 auto p = GetDcodeDescr()->GetMacro()->GetApertureMacroShape( this, m_Start );
878 return p->Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
879 }
880
881 // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
882 int radius = std::min( m_Size.x, m_Size.y ) >> 1;
883
884 if( radius < MIN_HIT_TEST_RADIUS )
885 radius = MIN_HIT_TEST_RADIUS;
886
887 if( m_Flashed )
888 return HitTestPoints( m_Start, ref_pos, radius );
889 else
890 return TestSegmentHit( ref_pos, m_Start, m_End, radius );
891}
892
893
894bool GERBER_DRAW_ITEM::HitTest( const BOX2I& aRefArea, bool aContained, int aAccuracy ) const
895{
897
898 if( aRefArea.Contains( pos ) )
899 return true;
900
901 pos = GetABPosition( m_End );
902
903 if( aRefArea.Contains( pos ) )
904 return true;
905
906 return false;
907}
908
909
910#if defined(DEBUG)
911
912void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
913{
914 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
915 " shape=\"" << m_Shape << '"' <<
916 " addr=\"" << std::hex << this << std::dec << '"' <<
917 " layer=\"" << GetLayer() << '"' <<
918 " size=\"" << m_Size << '"' <<
919 " flags=\"" << m_flags << '"' <<
920 " status=\"" << GetStatus() << '"' <<
921 "<start" << m_Start << "/>" <<
922 "<end" << m_End << "/>";
923
924 os << "</" << GetClass().Lower().mb_str() << ">\n";
925}
926
927#endif
928
929
930void GERBER_DRAW_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
931{
932 aCount = 2;
933
934 aLayers[0] = GERBER_DRAW_LAYER( GetLayer() );
935 aLayers[1] = GERBER_DCODE_LAYER( aLayers[0] );
936}
937
938
940{
941 return GetBoundingBox();
942}
943
944
945double GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
946{
947 // DCodes will be shown only if zoom is appropriate:
948 // Returns the level of detail of the item.
949 // A level of detail (LOD) is the minimal VIEW scale that
950 // is sufficient for an item to be shown on a given layer.
951 if( IsDCodeLayer( aLayer ) )
952 {
953 int size = 0;
954
955 switch( m_Shape )
956 {
957 case GBR_SPOT_MACRO:
959 break;
960
961 case GBR_ARC:
963 break;
964
965 default:
966 size = m_Size.x;
967 }
968
969 // the level of details is chosen experimentally, to show
970 // only a readable text:
971 double level = (double) gerbIUScale.mmToIU( 3 );
972 return level / ( size + 1 );
973 }
974
975 // Other layers are shown without any conditions
976 return 0.0;
977}
978
979
981 const std::vector<KICAD_T>& aScanTypes )
982{
983 for( KICAD_T scanType : aScanTypes )
984 {
985 if( scanType == Type() )
986 {
987 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
989 }
990 }
991
993}
994
995
997{
998 wxString layerName = GERBER_FILE_IMAGE_LIST::GetImagesList().GetDisplayName( GetLayer(), true );
999
1000 return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
1001 ShowGBRShape(),
1002 m_DCode,
1003 GetLayer() + 1,
1004 layerName );
1005}
int color
Definition: DXF_plotter.cpp:57
const char * name
Definition: DXF_plotter.cpp:56
constexpr EDA_IU_SCALE gerbIUScale
Definition: base_units.h:108
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
@ add_graphical_polygon
BOX2< VECTOR2I > BOX2I
Definition: box2.h:847
void SetOrigin(const Vec &pos)
Definition: box2.h:202
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:119
const Vec & GetOrigin() const
Definition: box2.h:183
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
const Vec GetEnd() const
Definition: box2.h:185
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
Vec Centre() const
Definition: box2.h:70
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:255
A gerber DCODE (also called Aperture) definition.
Definition: dcode.h:80
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:124
void DrawFlashedShape(const GERBER_DRAW_ITEM *aParent, wxDC *aDC, const COLOR4D &aColor, const VECTOR2I &aShapePos, bool aFilledShape)
Draw the dcode shape for flashed items.
Definition: dcode.cpp:147
wxString m_AperFunction
the aperture attribute (created by a TA.AperFunction command).
Definition: dcode.h:201
int GetShapeDim(GERBER_DRAW_ITEM *aParent)
Calculate a value that can be used to evaluate the size of text when displaying the D-Code of an item...
Definition: dcode.cpp:115
APERTURE_T m_Shape
shape ( Line, rectangle, circle , oval .. )
Definition: dcode.h:190
SHAPE_POLY_SET m_Polygon
Definition: dcode.h:204
wxSize m_Size
Horizontal and vertical dimensions.
Definition: dcode.h:189
void ConvertShapeToPolygon(const GERBER_DRAW_ITEM *aParent)
Convert a shape to an equivalent polygon.
Definition: dcode.cpp:294
EDA_ANGLE Normalize()
Definition: eda_angle.h:249
bool IsZero() const
Definition: eda_angle.h:169
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:500
EDA_ITEM_FLAGS GetStatus() const
Definition: eda_item.h:139
const wxString & GetValue() const
bool m_DisplayFlashedItemsFill
Option to draw flashed items (filled/sketch)
COLOR4D m_NegativeDrawColor
The color used to draw negative objects, usually the background color, but not always,...
bool m_DisplayPolygonsFill
Option to draw polygons (filled/sketch)
bool m_DisplayLinesFill
Option to draw line items (filled/sketch)
Information which can be added in a gerber file as attribute of an object.
int m_NetAttribType
the type of net info (used to define the gerber string to create)
wxString m_Cmpref
the component reference parent of the data
@ GBR_NETINFO_NET
print info associated to a net (TO.N attribute)
@ GBR_NETINFO_UNSPECIFIED
idle command (no command)
@ GBR_NETINFO_CMP
print info associated to a component (TO.C attribute)
@ GBR_NETINFO_PAD
print info associated to a flashed pad (TO.P attribute)
GBR_DATA_FIELD m_PadPinFunction
for a pad: the pin function (defined in schematic)
GBR_DATA_FIELD m_Padname
for a flashed pad: the pad name ((TO.P attribute)
wxString m_Netname
for items associated to a net: the netname
virtual wxString GetSelectMenuText(UNITS_PROVIDER *aUnitsProvider) const override
Return a pointer to an image to be used in menus.
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
bool GetTextD_CodePrms(int &aSize, VECTOR2I &aPos, EDA_ANGLE &aOrientation)
Return the best size and orientation to display the D_Code on screen.
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
D_CODE * GetDcodeDescr() const
Return the GetDcodeDescr of this object, or NULL.
void SetLayerParameters()
Initialize parameters from Image and Layer parameters found in the gerber file: m_UnitsMetric,...
SHAPE_POLY_SET m_Polygon
wxString ShowGBRShape() const
bool HasNegativeItems()
Optimize screen refresh (when no items are in background color refresh can be faster).
VECTOR2I GetABPosition(const VECTOR2I &aXYPosition) const
Return the image position of aPosition for this object.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
VECTOR2I GetXYPosition(const VECTOR2I &aABPosition) const
Return the image position of aPosition for this object.
void MoveXY(const VECTOR2I &aMoveVector)
Move this object.
int GetLayer() const
Return the layer this item is on.
void ConvertSegmentToPolygon()
Convert a line to an equivalent polygon.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
GERBER_DRAW_ITEM(GERBER_FILE_IMAGE *aGerberparams)
GERBER_FILE_IMAGE * m_GerberImageFile
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
wxString GetClass() const override
void PrintGerberPoly(wxDC *aDC, const COLOR4D &aColor, const VECTOR2I &aOffset, bool aFilledShape)
Print the polygon stored in m_PolyCorners.
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &aScanTypes) override
Return the text to display to be used in the selection clarification context menu when multiple items...
void SetNetAttributes(const GBR_NETLIST_METADATA &aNetAttributes)
virtual const BOX2I ViewBBox() const override
bool HitTest(const VECTOR2I &aRefPos, int aAccuracy=0) const override
Test if the given wxPoint is within the bounds of this object.
GBR_NETLIST_METADATA m_netAttributes
the string given by a TO attribute set in aperture (dcode).
void Print(wxDC *aDC, const VECTOR2I &aOffset, GBR_DISPLAY_OPTIONS *aOptions)
static GERBER_FILE_IMAGE_LIST & GetImagesList()
const wxString GetDisplayName(int aIdx, bool aNameOnly=false, bool aFullName=false)
Get the display name for the layer at aIdx.
Hold the image data and parameters for one gerber file and layer parameters.
bool m_SwapAxis
false if A = X and B = Y (default); true if A = Y, B = X
double m_LocalRotation
Local rotation added to m_ImageRotation.
VECTOR2I m_Offset
Coord Offset, from OF command.
bool m_ImageNegative
true = Negative image
COLOR4D GetPositiveDrawColor() const
std::map< wxString, int > m_ComponentsList
bool m_MirrorB
true: mirror / axis B (Y)
D_CODE * GetDCODE(int aDCODE) const
Return a pointer to the D_CODE within this GERBER for the given aDCODE.
int m_ImageRotation
Image rotation (0, 90, 180, 270 only) in degrees.
VECTOR2I m_ImageOffset
Coord Offset, from IO command.
std::map< wxString, int > m_NetnamesList
int m_GraphicLayer
Graphic layer Number.
bool m_GerbMetric
false = Inches, true = metric
bool m_MirrorA
true: mirror / axis A (X)
VECTOR2I m_Scale
scale (X and Y) of layer.
VECTOR2I m_ImageJustifyOffset
Image Justify Offset on XY axis (default = 0,0)
GERBER_LAYER & GetLayerParams()
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Definition: shape_arc.cpp:355
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.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
SHAPE_LINE_CHAIN & Outline(int aIndex)
int NewOutline()
Creates a new hole in a given outline.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void Move(const VECTOR2I &aVector) override
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
EDA_UNITS GetUserUnits() const
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
@ APT_RECT
Definition: dcode.h:50
#define FIRST_DCODE
Definition: dcode.h:69
#define LAST_DCODE
Definition: dcode.h:70
#define _(s)
static constexpr EDA_ANGLE & ANGLE_HORIZONTAL
Definition: eda_angle.h:408
@ RADIANS_T
Definition: eda_angle.h:32
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_360
Definition: eda_angle.h:418
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:412
INSPECT_RESULT
Definition: eda_item.h:42
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h:78
@ GBR_SPOT_OVAL
@ GBR_SEGMENT
@ GBR_SPOT_POLY
@ GBR_SPOT_RECT
@ GBR_CIRCLE
@ GBR_POLYGON
@ GBR_SPOT_CIRCLE
@ GBR_ARC
@ GBR_SPOT_MACRO
void GRCSegm(wxDC *DC, const VECTOR2I &A, const VECTOR2I &B, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:192
void GRCircle(wxDC *aDC, const VECTOR2I &aPos, int aRadius, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:348
void GRFilledSegment(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:269
void GRClosedPoly(wxDC *DC, int n, const VECTOR2I *Points, bool Fill, const COLOR4D &Color)
Draw a closed polyline and fill it if Fill, in object space.
Definition: gr_basic.cpp:342
void GRArc(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:369
#define GERBER_DCODE_LAYER(x)
Definition: layer_ids.h:425
bool IsDCodeLayer(int aLayer)
Definition: layer_ids.h:1001
#define GERBER_DRAW_LAYER(x)
Definition: layer_ids.h:423
Message panel definition file.
double ToUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Function To_User_Unit convert aValue in internal units to the appropriate user units defined by aUnit...
Definition: eda_units.cpp:194
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
wxString UnescapeString(const wxString &aSource)
wxString name
The name of the aperture macro.
Definition: am_primitive.h:231
BOX2I GetBoundingBox() const
Return the bounding box of the shape.
Definition: am_primitive.h:226
SHAPE_POLY_SET * GetApertureMacroShape(const GERBER_DRAW_ITEM *aParent, const VECTOR2I &aShapePos)
Calculate the primitive shape for flashed items.
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
constexpr int delta
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
bool HitTestPoints(const VECTOR2I &pointA, const VECTOR2I &pointB, double threshold)
Test, if two points are near each other.
Definition: trigo.h:159
double GetLineLength(const VECTOR2I &aPointA, const VECTOR2I &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:188
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ GERBER_DRAW_ITEM_T
Definition: typeinfo.h:214
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:617
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618