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-2023 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_ShapeType == 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_ShapeType )
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()->m_AmName;
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_ShapeType )
260 {
261 case GBR_POLYGON:
262 {
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_MACRO:
322 case GBR_SPOT_POLY:
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_SEGMENT:
335 {
336 if( code && code->m_ApertType == APT_RECT )
337 {
338 if( m_ShapeAsPolygon.OutlineCount() == 0 )
339 {
340 // We cannot initialize m_ShapeAsPolygon, because we are in a const function.
341 // So use a temporary polygon
342 SHAPE_POLY_SET poly_shape;
343 ConvertSegmentToPolygon( &poly_shape );
344 bbox = poly_shape.BBox();
345 }
346
347 else
348 {
349 bbox = m_ShapeAsPolygon.BBox();
350 }
351 }
352 else
353 {
354 int radius = ( m_Size.x + 1 ) / 2;
355
356 int ymax = std::max( m_Start.y, m_End.y ) + radius;
357 int xmax = std::max( m_Start.x, m_End.x ) + radius;
358
359 int ymin = std::min( m_Start.y, m_End.y ) - radius;
360 int xmin = std::min( m_Start.x, m_End.x ) - radius;
361
362 bbox = BOX2I( VECTOR2I( xmin, ymin ), VECTOR2I( xmax - xmin + 1, ymax - ymin + 1 ) );
363 }
364
365 break;
366 }
367 default:
368 wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
369 break;
370 }
371
372 // calculate the corners coordinates in current Gerber axis orientations
373 VECTOR2I org = GetABPosition( bbox.GetOrigin() );
374 VECTOR2I end = GetABPosition( bbox.GetEnd() );
375
376 // Set the corners position:
377 bbox.SetOrigin( org );
378 bbox.SetEnd( end );
379 bbox.Normalize();
380
381 return bbox;
382}
383
384
385void GERBER_DRAW_ITEM::MoveXY( const VECTOR2I& aMoveVector )
386{
387 m_Start += aMoveVector;
388 m_End += aMoveVector;
389 m_ArcCentre += aMoveVector;
390
391 m_ShapeAsPolygon.Move( aMoveVector );
392}
393
394
396{
398
399 // if isClear is true, this item has negative shape
400 return isClear;
401}
402
403
404void GERBER_DRAW_ITEM::Print( wxDC* aDC, const VECTOR2I& aOffset, GBR_DISPLAY_OPTIONS* aOptions )
405{
406 // used when a D_CODE is not found. default D_CODE to draw a flashed item
407 static D_CODE dummyD_CODE( 0 );
408 bool isFilled;
409 int radius;
410 int halfPenWidth;
411 static bool show_err;
412 D_CODE* d_codeDescr = GetDcodeDescr();
413
414 if( d_codeDescr == nullptr )
415 d_codeDescr = &dummyD_CODE;
416
418
419 /* isDark is true if flash is positive and should use a drawing
420 * color other than the background color, else use the background color
421 * when drawing so that an erasure happens.
422 */
424
425 if( !isDark )
426 {
427 // draw in background color ("negative" color)
428 color = aOptions->m_NegativeDrawColor;
429 }
430
431 isFilled = aOptions->m_DisplayLinesFill;
432
433 switch( m_ShapeType )
434 {
435 case GBR_POLYGON:
436 isFilled = aOptions->m_DisplayPolygonsFill;
437
438 if( !isDark )
439 isFilled = true;
440
441 PrintGerberPoly( aDC, color, aOffset, isFilled );
442 break;
443
444 case GBR_CIRCLE:
445 radius = KiROUND( GetLineLength( m_Start, m_End ) );
446
447 halfPenWidth = m_Size.x >> 1;
448
449 if( !isFilled )
450 {
451 // draw the border of the pen's path using two circles, each as narrow as possible
452 GRCircle( aDC, GetABPosition( m_Start ), radius - halfPenWidth, 0, color );
453 GRCircle( aDC, GetABPosition( m_Start ), radius + halfPenWidth, 0, color );
454 }
455 else // Filled mode
456 {
457 GRCircle( aDC, GetABPosition( m_Start ), radius, m_Size.x, color );
458 }
459
460 break;
461
462 case GBR_ARC:
463 // Currently, arcs plotted with a rectangular aperture are not supported.
464 // a round pen only is expected.
465 if( !isFilled )
466 {
469 }
470 else
471 {
474 }
475
476 break;
477
478 case GBR_SPOT_CIRCLE:
479 case GBR_SPOT_RECT:
480 case GBR_SPOT_OVAL:
481 case GBR_SPOT_POLY:
482 case GBR_SPOT_MACRO:
483 isFilled = aOptions->m_DisplayFlashedItemsFill;
484 d_codeDescr->DrawFlashedShape( this, aDC, color, m_Start, isFilled );
485 break;
486
487 case GBR_SEGMENT:
488 /* Plot a line from m_Start to m_End.
489 * Usually, a round pen is used, but some Gerber files use a rectangular pen
490 * In fact, any aperture can be used to plot a line.
491 * currently: only a square pen is handled (I believe using a polygon gives a strange plot).
492 */
493 if( d_codeDescr->m_ApertType == APT_RECT )
494 {
495 if( m_ShapeAsPolygon.OutlineCount() == 0 )
497
498 PrintGerberPoly( aDC, color, aOffset, isFilled );
499 }
500 else if( !isFilled )
501 {
503 }
504 else
505 {
507 color );
508 }
509
510 break;
511
512 default:
513 if( !show_err )
514 {
515 wxMessageBox( wxT( "Trace_Segment() type error" ) );
516 show_err = true;
517 }
518
519 break;
520 }
521}
522
523
525{
526 aPolygon->RemoveAllContours();
527 aPolygon->NewOutline();
528
529 VECTOR2I start = m_Start;
530 VECTOR2I end = m_End;
531
532 // make calculations more easy if ensure start.x < end.x
533 // (only 2 quadrants to consider)
534 if( start.x > end.x )
535 std::swap( start, end );
536
537 // calculate values relative to start point:
538 VECTOR2I delta = end - start;
539
540 // calculate corners for the first quadrant only (delta.x and delta.y > 0 )
541 // currently, delta.x already is > 0.
542 // make delta.y > 0
543 bool change = delta.y < 0;
544
545 if( change )
546 delta.y = -delta.y;
547
548 // Now create the full polygon.
549 // Due to previous changes, the shape is always something like
550 // 3 4
551 // 2 5
552 // 1 6
553 VECTOR2I corner;
554 corner.x -= m_Size.x/2;
555 corner.y -= m_Size.y/2;
556 VECTOR2I close = corner;
557 aPolygon->Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
558 corner.y += m_Size.y;
559 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
560
561 if( delta.x || delta.y )
562 {
563 corner += delta;
564 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
565 }
566
567 corner.x += m_Size.x;
568 aPolygon->Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
569 corner.y -= m_Size.y;
570 aPolygon->Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
571
572 if( delta.x || delta.y )
573 {
574 corner -= delta;
575 aPolygon->Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
576 }
577
578 aPolygon->Append( VECTOR2I( close ) ); // close the shape
579
580 // Create final polygon:
581 if( change )
582 aPolygon->Mirror( false, true );
583
584 aPolygon->Move( VECTOR2I( start ) );
585}
586
587
589{
591}
592
593
594void GERBER_DRAW_ITEM::PrintGerberPoly( wxDC* aDC, const COLOR4D& aColor, const VECTOR2I& aOffset,
595 bool aFilledShape )
596{
597 std::vector<VECTOR2I> points;
599 int pointCount = poly.PointCount() - 1;
600
601 points.reserve( pointCount );
602
603 for( int ii = 0; ii < pointCount; ii++ )
604 {
605 VECTOR2I p( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
606 points[ii] = p + aOffset;
607 points[ii] = GetABPosition( points[ii] );
608 }
609
610 GRClosedPoly( aDC, pointCount, &points[0], aFilledShape, aColor );
611}
612
613
614void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
615{
616 wxString msg;
617 wxString text;
618
619 msg = ShowGBRShape();
620 aList.emplace_back( _( "Type" ), msg );
621
622 // Display D_Code value with its attributes for items using a DCode:
623 if( m_ShapeType == GBR_POLYGON ) // Has no DCode, but can have an attribute
624 {
625 msg = _( "Attribute" );
626
627 if( m_AperFunction.IsEmpty() )
628 text = _( "No attribute" );
629 else
631 }
632 else
633 {
634 msg.Printf( _( "D Code %d" ), m_DCode );
635 D_CODE* apertDescr = GetDcodeDescr();
636
637 if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
638 text = _( "No attribute" );
639 else
640 text = apertDescr->m_AperFunction;
641 }
642
643 aList.emplace_back( msg, text );
644
645 // Display graphic layer name
647 aList.emplace_back( _( "Graphic Layer" ), msg );
648
649 // Display item position
654
655 if( m_Flashed )
656 {
657 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
658 aList.emplace_back( _( "Position" ), msg );
659 }
660 else
661 {
662 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
663 aList.emplace_back( _( "Start" ), msg );
664
665 msg.Printf( wxT( "(%.4f, %.4f)" ), xEnd, yEnd );
666 aList.emplace_back( _( "End" ), msg );
667 }
668
669 // Display item rotation
670 // The full rotation is Image rotation + m_lyrRotation
671 // but m_lyrRotation is specific to this object
672 // so we display only this parameter
673 msg.Printf( wxT( "%f" ), m_lyrRotation );
674 aList.emplace_back( _( "Rotation" ), msg );
675
676 // Display item polarity (item specific)
677 msg = m_LayerNegative ? _("Clear") : _("Dark");
678 aList.emplace_back( _( "Polarity" ), msg );
679
680 // Display mirroring (item specific)
681 msg.Printf( wxT( "A:%s B:%s" ), m_mirrorA ? _( "Yes" ) : _( "No" ),
682 m_mirrorB ? _( "Yes" ) : _( "No" ) );
683 aList.emplace_back( _( "Mirror" ), msg );
684
685 // Display AB axis swap (item specific)
686 msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
687 aList.emplace_back( _( "AB axis" ), msg );
688
689 // Display net info, if exists
691 return;
692
693 // Build full net info:
694 wxString net_msg;
695 wxString cmp_pad_msg;
696
698 {
699 net_msg = _( "Net:" );
700 net_msg << wxS( " " );
701
702 if( m_netAttributes.m_Netname.IsEmpty() )
703 net_msg << _( "<no net>" );
704 else
706 }
707
709 {
711 {
712 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s" ),
715 }
716 else
717 {
718 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s Fct %s" ),
722 }
723 }
724
726 {
727 cmp_pad_msg = _( "Cmp:" );
728 cmp_pad_msg << wxS( " " ) << m_netAttributes.m_Cmpref;
729 }
730
731 aList.emplace_back( net_msg, cmp_pad_msg );
732}
733
734
736{
737 if( m_Flashed )
738 return BITMAPS::pad;
739
740 switch( m_ShapeType )
741 {
742 case GBR_SEGMENT:
743 case GBR_ARC:
744 case GBR_CIRCLE:
745 return BITMAPS::add_line;
746
747 case GBR_SPOT_OVAL:
748 case GBR_SPOT_CIRCLE:
749 case GBR_SPOT_RECT:
750 case GBR_SPOT_POLY:
751 case GBR_SPOT_MACRO:
752 // should be handles by m_Flashed == true
753 return BITMAPS::pad;
754
755 case GBR_POLYGON:
757 }
758
759 return BITMAPS::info;
760}
761
762
763bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
764{
765 // In case the item has a very tiny width defined, allow it to be selected
766 const int MIN_HIT_TEST_RADIUS = gerbIUScale.mmToIU( 0.01 );
767
768 // calculate aRefPos in XY Gerber axis:
769 VECTOR2I ref_pos = GetXYPosition( aRefPos );
770
771 SHAPE_POLY_SET poly;
772
773 switch( m_ShapeType )
774 {
775 case GBR_POLYGON:
776 poly = m_ShapeAsPolygon;
777 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
778
779 case GBR_SPOT_POLY:
780 poly = GetDcodeDescr()->m_Polygon;
781 poly.Move( VECTOR2I( m_Start ) );
782 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
783
784 case GBR_SPOT_RECT:
785 return GetBoundingBox().Contains( aRefPos );
786
787 case GBR_SPOT_OVAL:
788 {
789 BOX2I bbox = GetBoundingBox();
790
791 if( ! bbox.Contains( aRefPos ) )
792 return false;
793
794 // This is similar to a segment with thickness = min( m_Size.x, m_Size.y )
795 int radius = std::min( m_Size.x, m_Size.y )/2;
796 VECTOR2I start, end;
797
798 if( m_Size.x > m_Size.y ) // Horizontal oval
799 {
800 int len = m_Size.y - m_Size.x;
801 start.x = -len/2;
802 end.x = len/2;
803 }
804 else // Vertical oval
805 {
806 int len = m_Size.x - m_Size.y;
807 start.y = -len/2;
808 end.y = len/2;
809 }
810
811 start += bbox.Centre();
812 end += bbox.Centre();
813
814 if( radius < MIN_HIT_TEST_RADIUS )
815 radius = MIN_HIT_TEST_RADIUS;
816
817 return TestSegmentHit( aRefPos, start, end, radius );
818 }
819
820 case GBR_ARC:
821 {
822 double radius = GetLineLength( m_Start, m_ArcCentre );
823 VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
824
825 int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x );
826
827 // Are we close enough to the radius?
828 bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
829
830 if( radius_hit )
831 {
832 // Now check that we are within the arc angle
833
836 EDA_ANGLE start_angle( start );
837 EDA_ANGLE end_angle( end );
838
839 start_angle.Normalize();
840 end_angle.Normalize();
841
842 if( m_Start == m_End )
843 {
844 start_angle = ANGLE_0;
845 end_angle = ANGLE_360;
846 }
847 else if( end_angle < start_angle )
848 {
849 end_angle += ANGLE_360;
850 }
851
852 EDA_ANGLE test_angle( test_radius );
853 test_angle.Normalize();
854
855 return ( test_angle > start_angle && test_angle < end_angle );
856 }
857
858 return false;
859 }
860
861 case GBR_SPOT_MACRO:
862 return m_AbsolutePolygon.Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
863
864 case GBR_SEGMENT:
865 case GBR_CIRCLE:
866 case GBR_SPOT_CIRCLE:
867 break; // handled below.
868 }
869
870 // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
871 int radius = std::min( m_Size.x, m_Size.y ) >> 1;
872
873 if( radius < MIN_HIT_TEST_RADIUS )
874 radius = MIN_HIT_TEST_RADIUS;
875
876 if( m_Flashed )
877 return HitTestPoints( m_Start, ref_pos, radius );
878 else
879 return TestSegmentHit( ref_pos, m_Start, m_End, radius );
880}
881
882
883bool GERBER_DRAW_ITEM::HitTest( const BOX2I& aRefArea, bool aContained, int aAccuracy ) const
884{
886
887 if( aRefArea.Contains( pos ) )
888 return true;
889
890 pos = GetABPosition( m_End );
891
892 if( aRefArea.Contains( pos ) )
893 return true;
894
895 return false;
896}
897
898
899#if defined(DEBUG)
900
901void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
902{
903 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
904 " shape=\"" << m_ShapeType << '"' <<
905 " addr=\"" << std::hex << this << std::dec << '"' <<
906 " layer=\"" << GetLayer() << '"' <<
907 " size=\"" << m_Size << '"' <<
908 " flags=\"" << m_flags << '"' <<
909 " status=\"" << GetStatus() << '"' <<
910 "<start" << m_Start << "/>" <<
911 "<end" << m_End << "/>";
912
913 os << "</" << GetClass().Lower().mb_str() << ">\n";
914}
915
916#endif
917
918
919void GERBER_DRAW_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
920{
921 aCount = 2;
922
923 aLayers[0] = GERBER_DRAW_LAYER( GetLayer() );
924 aLayers[1] = GERBER_DCODE_LAYER( aLayers[0] );
925}
926
927
929{
930 return GetBoundingBox();
931}
932
933
934double GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
935{
936 // DCodes will be shown only if zoom is appropriate:
937 // Returns the level of detail of the item.
938 // A level of detail (LOD) is the minimal VIEW scale that
939 // is sufficient for an item to be shown on a given layer.
940 if( IsDCodeLayer( aLayer ) )
941 {
942 int size = 0;
943
944 switch( m_ShapeType )
945 {
946 case GBR_SPOT_MACRO:
947 size = GetDcodeDescr()->m_Polygon.BBox().GetWidth();
948 break;
949
950 case GBR_ARC:
952 break;
953
954 default:
955 size = m_Size.x;
956 }
957
958 // the level of details is chosen experimentally, to show
959 // only a readable text:
960 double level = (double) gerbIUScale.mmToIU( 3 );
961 return level / ( size + 1 );
962 }
963
964 // Other layers are shown without any conditions
965 return 0.0;
966}
967
968
970 const std::vector<KICAD_T>& aScanTypes )
971{
972 for( KICAD_T scanType : aScanTypes )
973 {
974 if( scanType == Type() )
975 {
976 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
978 }
979 }
980
982}
983
984
986{
987 wxString layerName = GERBER_FILE_IMAGE_LIST::GetImagesList().GetDisplayName( GetLayer(), true );
988
989 return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
990 ShowGBRShape(),
991 m_DCode,
992 GetLayer() + 1,
993 layerName );
994}
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
wxString m_AmName
The name of the aperture macro as defined like AMVB_RECTANGLE* (name is VB_RECTANGLE)
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:125
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:153
wxString m_AperFunction
the aperture attribute (created by a TA.AperFunction command).
Definition: dcode.h:203
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
VECTOR2I m_Size
Horizontal and vertical dimensions.
Definition: dcode.h:190
APERTURE_T m_ApertType
Aperture type ( Line, rectangle, circle, oval poly, macro )
Definition: dcode.h:191
SHAPE_POLY_SET m_Polygon
Definition: dcode.h:206
void ConvertShapeToPolygon(const GERBER_DRAW_ITEM *aParent)
Convert a shape to an equivalent polygon.
Definition: dcode.cpp:297
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:498
EDA_ITEM_FLAGS GetStatus() const
Definition: eda_item.h:136
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
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,...
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.
SHAPE_POLY_SET m_ShapeAsPolygon
int GetLayer() const
Return the layer this item is on.
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a pointer to an image to be used in menus.
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.
GBR_BASIC_SHAPE_TYPE m_ShapeType
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 a user-visible description string of this item.
void SetNetAttributes(const GBR_NETLIST_METADATA &aNetAttributes)
SHAPE_POLY_SET m_AbsolutePolygon
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:102
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:265
@ 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:425
@ RADIANS_T
Definition: eda_angle.h:32
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_360
Definition: eda_angle.h:435
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:429
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:201
void GRCircle(wxDC *aDC, const VECTOR2I &aPos, int aRadius, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:357
void GRFilledSegment(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:278
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:351
void GRArc(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:378
#define GERBER_DCODE_LAYER(x)
Definition: layer_ids.h:427
bool IsDCodeLayer(int aLayer)
Definition: layer_ids.h:1003
#define GERBER_DRAW_LAYER(x)
Definition: layer_ids.h:425
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:190
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)
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:589
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590