KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 {
119 EDA_ANGLE angle( delta );
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 // We have also a draw transform (rotation and offset)
142 // order is rotation and after offset
143
144 if( m_swapAxis )
145 std::swap( abPos.x, abPos.y );
146
148 abPos.x = KiROUND( abPos.x * m_drawScale.x );
149 abPos.y = KiROUND( abPos.y * m_drawScale.y );
151
152 if( !rotation.IsZero() )
153 RotatePoint( abPos, -rotation );
154
155 // Negate A axis if mirrored
156 if( m_mirrorA )
157 abPos.x = -abPos.x;
158
159 // abPos.y must be negated when no mirror, because draw axis is top to bottom
160 if( !m_mirrorB )
161 abPos.y = -abPos.y;
162
163 // Now generate the draw transform
166
169
170 return abPos;
171}
172
173
175{
176 // do the inverse transform made by GetABPosition
177 VECTOR2I xyPos = aABPosition;
178
179 // First, undo the draw transform
182
185
186 if( m_mirrorA )
187 xyPos.x = -xyPos.x;
188
189 if( !m_mirrorB )
190 xyPos.y = -xyPos.y;
191
193
194 if( !rotation.IsZero() )
195 RotatePoint( xyPos, rotation );
196
197 xyPos.x = KiROUND( xyPos.x / m_drawScale.x );
198 xyPos.y = KiROUND( xyPos.y / m_drawScale.y );
200
201 if( m_swapAxis )
202 std::swap( xyPos.x, xyPos.y );
203
205}
206
207
209{
211 m_swapAxis = m_GerberImageFile->m_SwapAxis; // false if A = X, B = Y;
212
213 // true if A =Y, B = Y
214 m_mirrorA = m_GerberImageFile->m_MirrorA; // true: mirror / axe A
215 m_mirrorB = m_GerberImageFile->m_MirrorB; // true: mirror / axe B
216 m_drawScale = m_GerberImageFile->m_Scale; // A and B scaling factor
217 m_layerOffset = m_GerberImageFile->m_Offset; // Offset from OF command
218
219 // Rotation from RO command:
222}
223
224
226{
227 switch( m_ShapeType )
228 {
229 case GBR_SEGMENT: return _( "Line" );
230 case GBR_ARC: return _( "Arc" );
231 case GBR_CIRCLE: return _( "Circle" );
232 case GBR_SPOT_OVAL: return wxT( "spot_oval" );
233 case GBR_SPOT_CIRCLE: return wxT( "spot_circle" );
234 case GBR_SPOT_RECT: return wxT( "spot_rect" );
235 case GBR_SPOT_POLY: return wxT( "spot_poly" );
236 case GBR_POLYGON: return wxT( "polygon" );
237
238 case GBR_SPOT_MACRO:
239 {
240 wxString name = wxT( "apt_macro" );
241 D_CODE* dcode = GetDcodeDescr();
242
243 if( dcode && dcode->GetMacro() )
244 name << wxT(" ") << dcode->GetMacro()->m_AmName;
245
246 return name;
247 }
248
249 default: return wxT( "??" );
250 }
251}
252
253
255{
256 if( ( m_DCode < FIRST_DCODE ) || ( m_DCode > LAST_DCODE ) )
257 return nullptr;
258
259 if( m_GerberImageFile == nullptr )
260 return nullptr;
261
263}
264
265
267{
268 // return a rectangle which is (pos,dim) in nature. therefore the +1
269 BOX2I bbox( m_Start, VECTOR2I( 1, 1 ) );
270 D_CODE* code = GetDcodeDescr();
271
272 // TODO(JE) GERBER_DRAW_ITEM maybe should actually be a number of subclasses.
273 // Until/unless that is changed, we need to do different things depending on
274 // what is actually being represented by this GERBER_DRAW_ITEM.
275
276 switch( m_ShapeType )
277 {
278 case GBR_POLYGON:
279 {
281 bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
282 bbox.SetOrigin( bb.GetOrigin() );
283 break;
284 }
285
286 case GBR_CIRCLE:
287 {
288 double radius = GetLineLength( m_Start, m_End );
289 bbox.Inflate( radius, radius );
290 break;
291 }
292
293 case GBR_ARC:
294 {
295 EDA_ANGLE angle( atan2( double( m_End.y - m_ArcCentre.y ),
296 double( m_End.x - m_ArcCentre.x ) )
297 - atan2( double( m_Start.y - m_ArcCentre.y ),
298 double( m_Start.x - m_ArcCentre.x ) ),
299 RADIANS_T );
300
301 if( m_End == m_Start ) // Arc with the end point = start point is expected to be a circle.
302 angle = ANGLE_360;
303 else
304 angle.Normalize();
305
306 SHAPE_ARC arc( m_ArcCentre, m_Start, angle );
307 bbox = arc.BBox( m_Size.x / 2 ); // m_Size.x is the line thickness
308 break;
309 }
310
311 case GBR_SPOT_CIRCLE:
312 {
313 if( code )
314 {
315 int radius = code->m_Size.x >> 1;
316 bbox.Inflate( radius, radius );
317 }
318
319 break;
320 }
321
322 case GBR_SPOT_RECT:
323 {
324 if( code )
325 bbox.Inflate( code->m_Size.x / 2, code->m_Size.y / 2 );
326
327 break;
328 }
329
330 case GBR_SPOT_OVAL:
331 {
332 if( code )
333 bbox.Inflate( code->m_Size.x /2, code->m_Size.y / 2 );
334
335 break;
336 }
337
338 case GBR_SPOT_MACRO:
339 case GBR_SPOT_POLY:
340 if( code )
341 {
342 if( code->m_Polygon.OutlineCount() == 0 )
343 code->ConvertShapeToPolygon( this );
344
345 bbox.Inflate( code->m_Polygon.BBox().GetWidth() / 2,
346 code->m_Polygon.BBox().GetHeight() / 2 );
347 }
348
349 break;
350
351 case GBR_SEGMENT:
352 {
353 if( code && code->m_ApertType == APT_RECT )
354 {
355 if( m_ShapeAsPolygon.OutlineCount() == 0 )
356 {
357 // We cannot initialize m_ShapeAsPolygon, because we are in a const function.
358 // So use a temporary polygon
359 SHAPE_POLY_SET poly_shape;
360 ConvertSegmentToPolygon( &poly_shape );
361 bbox = poly_shape.BBox();
362 }
363
364 else
365 {
366 bbox = m_ShapeAsPolygon.BBox();
367 }
368 }
369 else
370 {
371 int radius = ( m_Size.x + 1 ) / 2;
372
373 int ymax = std::max( m_Start.y, m_End.y ) + radius;
374 int xmax = std::max( m_Start.x, m_End.x ) + radius;
375
376 int ymin = std::min( m_Start.y, m_End.y ) - radius;
377 int xmin = std::min( m_Start.x, m_End.x ) - radius;
378
379 bbox = BOX2I( VECTOR2I( xmin, ymin ), VECTOR2I( xmax - xmin + 1, ymax - ymin + 1 ) );
380 }
381
382 break;
383 }
384 default:
385 wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
386 break;
387 }
388
389 // calculate the corners coordinates in current Gerber axis orientations
390 // because the initial bbox is a horizontal rect, but the bbox in AB position
391 // is the bbox image with perhaps a rotation, we need to calculate the coords of the
392 // corners of the bbox rotated, and then calculate the final bounding box
393 VECTOR2I corners[4];
394 bbox.Normalize();
395
396 // Shape:
397 // 0...1
398 // . .
399 // . .
400 // 3...2
401 corners[0] = bbox.GetOrigin(); // top left
402 corners[2] = bbox.GetEnd(); // bottom right
403 corners[1] = VECTOR2I( corners[2].x, corners[0].y ); // top right
404 corners[3] = VECTOR2I( corners[0].x, corners[2].y ); // bottom left
405
406 VECTOR2I org = GetABPosition( bbox.GetOrigin() );;
407 VECTOR2I end = GetABPosition( bbox.GetEnd() );;
408
409 // Now calculate the bounding box of bbox, if the display image is rotated
410 // It will be perhaps a bit bigger than a better bounding box calculation, but it is fast
411 // and easy
412 // (if not rotated, this is a nop)
413 for( int ii = 0; ii < 4; ii++ )
414 {
415 corners[ii] = GetABPosition( corners[ii] );
416
417 org.x = std::min( org.x, corners[ii].x );
418 org.y = std::min( org.y, corners[ii].y );
419
420 end.x = std::max( end.x, corners[ii].x );
421 end.y = std::max( end.y, corners[ii].y );
422 }
423
424 // Set the corners position:
425 bbox.SetOrigin( org );
426 bbox.SetEnd( end );
427 bbox.Normalize();
428
429 return bbox;
430}
431
432
433void GERBER_DRAW_ITEM::MoveXY( const VECTOR2I& aMoveVector )
434{
435 m_Start += aMoveVector;
436 m_End += aMoveVector;
437 m_ArcCentre += aMoveVector;
438
439 m_ShapeAsPolygon.Move( aMoveVector );
440}
441
442
444{
446
447 // if isClear is true, this item has negative shape
448 return isClear;
449}
450
451
452void GERBER_DRAW_ITEM::Print( wxDC* aDC, const VECTOR2I& aOffset, GBR_DISPLAY_OPTIONS* aOptions )
453{
454 // used when a D_CODE is not found. default D_CODE to draw a flashed item
455 static D_CODE dummyD_CODE( 0 );
456 bool isFilled;
457 int radius;
458 int halfPenWidth;
459 static bool show_err;
460 D_CODE* d_codeDescr = GetDcodeDescr();
461
462 if( d_codeDescr == nullptr )
463 d_codeDescr = &dummyD_CODE;
464
466
467 /* isDark is true if flash is positive and should use a drawing
468 * color other than the background color, else use the background color
469 * when drawing so that an erasure happens.
470 */
472
473 if( !isDark )
474 {
475 // draw in background color ("negative" color)
476 color = aOptions->m_NegativeDrawColor;
477 }
478
479 isFilled = aOptions->m_DisplayLinesFill;
480
481 switch( m_ShapeType )
482 {
483 case GBR_POLYGON:
484 isFilled = aOptions->m_DisplayPolygonsFill;
485
486 if( !isDark )
487 isFilled = true;
488
489 PrintGerberPoly( aDC, color, aOffset, isFilled );
490 break;
491
492 case GBR_CIRCLE:
493 radius = KiROUND( GetLineLength( m_Start, m_End ) );
494
495 halfPenWidth = m_Size.x >> 1;
496
497 if( !isFilled )
498 {
499 // draw the border of the pen's path using two circles, each as narrow as possible
500 GRCircle( aDC, GetABPosition( m_Start ), radius - halfPenWidth, 0, color );
501 GRCircle( aDC, GetABPosition( m_Start ), radius + halfPenWidth, 0, color );
502 }
503 else // Filled mode
504 {
505 GRCircle( aDC, GetABPosition( m_Start ), radius, m_Size.x, color );
506 }
507
508 break;
509
510 case GBR_ARC:
511 // Currently, arcs plotted with a rectangular aperture are not supported.
512 // a round pen only is expected.
513 if( !isFilled )
514 {
517 }
518 else
519 {
522 }
523
524 break;
525
526 case GBR_SPOT_CIRCLE:
527 case GBR_SPOT_RECT:
528 case GBR_SPOT_OVAL:
529 case GBR_SPOT_POLY:
530 case GBR_SPOT_MACRO:
531 isFilled = aOptions->m_DisplayFlashedItemsFill;
532 d_codeDescr->DrawFlashedShape( this, aDC, color, m_Start, isFilled );
533 break;
534
535 case GBR_SEGMENT:
536 /* Plot a line from m_Start to m_End.
537 * Usually, a round pen is used, but some Gerber files use a rectangular pen
538 * In fact, any aperture can be used to plot a line.
539 * currently: only a square pen is handled (I believe using a polygon gives a strange plot).
540 */
541 if( d_codeDescr->m_ApertType == APT_RECT )
542 {
543 if( m_ShapeAsPolygon.OutlineCount() == 0 )
545
546 PrintGerberPoly( aDC, color, aOffset, isFilled );
547 }
548 else if( !isFilled )
549 {
551 }
552 else
553 {
555 color );
556 }
557
558 break;
559
560 default:
561 if( !show_err )
562 {
563 wxMessageBox( wxT( "Trace_Segment() type error" ) );
564 show_err = true;
565 }
566
567 break;
568 }
569}
570
571
573{
574 aPolygon->RemoveAllContours();
575 aPolygon->NewOutline();
576
577 VECTOR2I start = m_Start;
578 VECTOR2I end = m_End;
579
580 // make calculations more easy if ensure start.x < end.x
581 // (only 2 quadrants to consider)
582 if( start.x > end.x )
583 std::swap( start, end );
584
585 // calculate values relative to start point:
586 VECTOR2I delta = end - start;
587
588 // calculate corners for the first quadrant only (delta.x and delta.y > 0 )
589 // currently, delta.x already is > 0.
590 // make delta.y > 0
591 bool change = delta.y < 0;
592
593 if( change )
594 delta.y = -delta.y;
595
596 // Now create the full polygon.
597 // Due to previous changes, the shape is always something like
598 // 3 4
599 // 2 5
600 // 1 6
601 VECTOR2I corner;
602 corner.x -= m_Size.x/2;
603 corner.y -= m_Size.y/2;
604 VECTOR2I close = corner;
605 aPolygon->Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
606 corner.y += m_Size.y;
607 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
608
609 if( delta.x || delta.y )
610 {
611 corner += delta;
612 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
613 }
614
615 corner.x += m_Size.x;
616 aPolygon->Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
617 corner.y -= m_Size.y;
618 aPolygon->Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
619
620 if( delta.x || delta.y )
621 {
622 corner -= delta;
623 aPolygon->Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
624 }
625
626 aPolygon->Append( VECTOR2I( close ) ); // close the shape
627
628 // Create final polygon:
629 if( change )
630 aPolygon->Mirror( false, true );
631
632 aPolygon->Move( VECTOR2I( start ) );
633}
634
635
637{
639}
640
641
642void GERBER_DRAW_ITEM::PrintGerberPoly( wxDC* aDC, const COLOR4D& aColor, const VECTOR2I& aOffset,
643 bool aFilledShape )
644{
645 std::vector<VECTOR2I> points;
647 int pointCount = poly.PointCount() - 1;
648
649 points.reserve( pointCount );
650
651 for( int ii = 0; ii < pointCount; ii++ )
652 {
653 VECTOR2I p( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
654 points[ii] = p + aOffset;
655 points[ii] = GetABPosition( points[ii] );
656 }
657
658 GRClosedPoly( aDC, pointCount, &points[0], aFilledShape, aColor );
659}
660
661
662void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
663{
664 wxString msg;
665 wxString text;
666
667 msg = ShowGBRShape();
668 aList.emplace_back( _( "Type" ), msg );
669
670 // Display D_Code value with its attributes for items using a DCode:
671 if( m_ShapeType == GBR_POLYGON ) // Has no DCode, but can have an attribute
672 {
673 msg = _( "Attribute" );
674
675 if( m_AperFunction.IsEmpty() )
676 text = _( "No attribute" );
677 else
679 }
680 else
681 {
682 msg.Printf( _( "D Code %d" ), m_DCode );
683 D_CODE* apertDescr = GetDcodeDescr();
684
685 if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
686 text = _( "No attribute" );
687 else
688 text = apertDescr->m_AperFunction;
689 }
690
691 aList.emplace_back( msg, text );
692
693 // Display graphic layer name
695 aList.emplace_back( _( "Graphic Layer" ), msg );
696
697 // Display item position
702
703 if( m_Flashed )
704 {
705 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
706 aList.emplace_back( _( "Position" ), msg );
707 }
708 else
709 {
710 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
711 aList.emplace_back( _( "Start" ), msg );
712
713 msg.Printf( wxT( "(%.4f, %.4f)" ), xEnd, yEnd );
714 aList.emplace_back( _( "End" ), msg );
715 }
716
717 // Display item rotation
718 // The full rotation is Image rotation + m_lyrRotation
719 // but m_lyrRotation is specific to this object
720 // so we display only this parameter
721 msg.Printf( wxT( "%f" ), m_lyrRotation );
722 aList.emplace_back( _( "Rotation" ), msg );
723
724 // Display item polarity (item specific)
725 msg = m_LayerNegative ? _("Clear") : _("Dark");
726 aList.emplace_back( _( "Polarity" ), msg );
727
728 // Display mirroring (item specific)
729 msg.Printf( wxT( "A:%s B:%s" ), m_mirrorA ? _( "Yes" ) : _( "No" ),
730 m_mirrorB ? _( "Yes" ) : _( "No" ) );
731 aList.emplace_back( _( "Mirror" ), msg );
732
733 // Display AB axis swap (item specific)
734 msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
735 aList.emplace_back( _( "AB axis" ), msg );
736
737 // Display net info, if exists
739 return;
740
741 // Build full net info:
742 wxString net_msg;
743 wxString cmp_pad_msg;
744
746 {
747 net_msg = _( "Net:" );
748 net_msg << wxS( " " );
749
750 if( m_netAttributes.m_Netname.IsEmpty() )
751 net_msg << _( "<no net>" );
752 else
754 }
755
757 {
759 {
760 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s" ),
763 }
764 else
765 {
766 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s Fct %s" ),
770 }
771 }
772
774 {
775 cmp_pad_msg = _( "Cmp:" );
776 cmp_pad_msg << wxS( " " ) << m_netAttributes.m_Cmpref;
777 }
778
779 aList.emplace_back( net_msg, cmp_pad_msg );
780}
781
782
784{
785 if( m_Flashed )
786 return BITMAPS::pad;
787
788 switch( m_ShapeType )
789 {
790 case GBR_SEGMENT:
791 case GBR_ARC:
792 case GBR_CIRCLE:
793 return BITMAPS::add_line;
794
795 case GBR_SPOT_OVAL:
796 case GBR_SPOT_CIRCLE:
797 case GBR_SPOT_RECT:
798 case GBR_SPOT_POLY:
799 case GBR_SPOT_MACRO:
800 // should be handles by m_Flashed == true
801 return BITMAPS::pad;
802
803 case GBR_POLYGON:
804 return BITMAPS::add_graphical_polygon;
805 }
806
807 return BITMAPS::info;
808}
809
810
811bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
812{
813 // In case the item has a very tiny width defined, allow it to be selected
814 const int MIN_HIT_TEST_RADIUS = gerbIUScale.mmToIU( 0.01 );
815
816 // calculate aRefPos in XY Gerber axis:
817 VECTOR2I ref_pos = GetXYPosition( aRefPos );
818
819 SHAPE_POLY_SET poly;
820
821 switch( m_ShapeType )
822 {
823 case GBR_POLYGON:
824 poly = m_ShapeAsPolygon;
825 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
826
827 case GBR_SPOT_POLY:
828 poly = GetDcodeDescr()->m_Polygon;
829 poly.Move( VECTOR2I( m_Start ) );
830 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
831
832 case GBR_SPOT_RECT:
833 return GetBoundingBox().Contains( aRefPos );
834
835 case GBR_SPOT_OVAL:
836 {
837 BOX2I bbox = GetBoundingBox();
838
839 if( ! bbox.Contains( aRefPos ) )
840 return false;
841
842 // This is similar to a segment with thickness = min( m_Size.x, m_Size.y )
843 int radius = std::min( m_Size.x, m_Size.y )/2;
844 VECTOR2I start, end;
845
846 if( m_Size.x > m_Size.y ) // Horizontal oval
847 {
848 int len = m_Size.y - m_Size.x;
849 start.x = -len/2;
850 end.x = len/2;
851 }
852 else // Vertical oval
853 {
854 int len = m_Size.x - m_Size.y;
855 start.y = -len/2;
856 end.y = len/2;
857 }
858
859 start += bbox.Centre();
860 end += bbox.Centre();
861
862 if( radius < MIN_HIT_TEST_RADIUS )
863 radius = MIN_HIT_TEST_RADIUS;
864
865 return TestSegmentHit( aRefPos, start, end, radius );
866 }
867
868 case GBR_ARC:
869 {
870 double radius = GetLineLength( m_Start, m_ArcCentre );
871 VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
872
873 int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x );
874
875 // Are we close enough to the radius?
876 bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
877
878 if( radius_hit )
879 {
880 // Now check that we are within the arc angle
881
884 EDA_ANGLE start_angle( start );
885 EDA_ANGLE end_angle( end );
886
887 start_angle.Normalize();
888 end_angle.Normalize();
889
890 if( m_Start == m_End )
891 {
892 start_angle = ANGLE_0;
893 end_angle = ANGLE_360;
894 }
895 else if( end_angle < start_angle )
896 {
897 end_angle += ANGLE_360;
898 }
899
900 EDA_ANGLE test_angle( test_radius );
901 test_angle.Normalize();
902
903 return ( test_angle > start_angle && test_angle < end_angle );
904 }
905
906 return false;
907 }
908
909 case GBR_SPOT_MACRO:
910 return m_AbsolutePolygon.Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
911
912 case GBR_SEGMENT:
913 case GBR_CIRCLE:
914 case GBR_SPOT_CIRCLE:
915 break; // handled below.
916 }
917
918 // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
919 int radius = std::min( m_Size.x, m_Size.y ) >> 1;
920
921 if( radius < MIN_HIT_TEST_RADIUS )
922 radius = MIN_HIT_TEST_RADIUS;
923
924 if( m_Flashed )
925 return HitTestPoints( m_Start, ref_pos, radius );
926 else
927 return TestSegmentHit( ref_pos, m_Start, m_End, radius );
928}
929
930
931bool GERBER_DRAW_ITEM::HitTest( const BOX2I& aRefArea, bool aContained, int aAccuracy ) const
932{
934
935 if( aRefArea.Contains( pos ) )
936 return true;
937
938 pos = GetABPosition( m_End );
939
940 if( aRefArea.Contains( pos ) )
941 return true;
942
943 return false;
944}
945
946
947#if defined(DEBUG)
948
949void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
950{
951 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
952 " shape=\"" << m_ShapeType << '"' <<
953 " addr=\"" << std::hex << this << std::dec << '"' <<
954 " layer=\"" << GetLayer() << '"' <<
955 " size=\"" << m_Size << '"' <<
956 " flags=\"" << m_flags << '"' <<
957 "<start" << m_Start << "/>" <<
958 "<end" << m_End << "/>";
959
960 os << "</" << GetClass().Lower().mb_str() << ">\n";
961}
962
963#endif
964
965
966void GERBER_DRAW_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
967{
968 aCount = 2;
969
970 aLayers[0] = GERBER_DRAW_LAYER( GetLayer() );
971 aLayers[1] = GERBER_DCODE_LAYER( aLayers[0] );
972}
973
974
976{
977 return GetBoundingBox();
978}
979
980
981double GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
982{
983 // DCodes will be shown only if zoom is appropriate:
984 // Returns the level of detail of the item.
985 // A level of detail (LOD) is the minimal VIEW scale that
986 // is sufficient for an item to be shown on a given layer.
987 if( IsDCodeLayer( aLayer ) )
988 {
989 int size = 0;
990
991 switch( m_ShapeType )
992 {
993 case GBR_SPOT_MACRO:
994 size = GetDcodeDescr()->m_Polygon.BBox().GetWidth();
995 break;
996
997 case GBR_ARC:
999 break;
1000
1001 default:
1002 size = m_Size.x;
1003 }
1004
1005 // the level of details is chosen experimentally, to show
1006 // only a readable text:
1007 double level = (double) gerbIUScale.mmToIU( 3 );
1008 return level / ( size + 1 );
1009 }
1010
1011 // Other layers are shown without any conditions
1012 return 0.0;
1013}
1014
1015
1017 const std::vector<KICAD_T>& aScanTypes )
1018{
1019 for( KICAD_T scanType : aScanTypes )
1020 {
1021 if( scanType == Type() )
1022 {
1023 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
1024 return INSPECT_RESULT::QUIT;
1025 }
1026 }
1027
1028 return INSPECT_RESULT::CONTINUE;
1029}
1030
1031
1033{
1034 wxString layerName = GERBER_FILE_IMAGE_LIST::GetImagesList().GetDisplayName( GetLayer(), true );
1035
1036 return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
1037 ShowGBRShape(),
1038 m_DCode,
1039 GetLayer() + 1,
1040 layerName );
1041}
int color
Definition: DXF_plotter.cpp:58
const char * name
Definition: DXF_plotter.cpp:57
constexpr EDA_IU_SCALE gerbIUScale
Definition: base_units.h:107
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
BOX2< VECTOR2I > BOX2I
Definition: box2.h:877
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:227
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:136
const Vec & GetOrigin() const
Definition: box2.h:200
size_type GetHeight() const
Definition: box2.h:205
size_type GetWidth() const
Definition: box2.h:204
const Vec GetEnd() const
Definition: box2.h:202
bool Contains(const Vec &aPoint) const
Definition: box2.h:158
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
Vec Centre() const
Definition: box2.h:87
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:280
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:255
EDA_ANGLE Normalize90()
Definition: eda_angle.h:283
bool IsZero() const
Definition: eda_angle.h:175
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:88
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:490
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.
VECTOR2I m_DisplayOffset
< Parameters used only to draw (display) items on this layer.
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:68
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:371
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 RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
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)
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)
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.
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_0
Definition: eda_angle.h:435
@ RADIANS_T
Definition: eda_angle.h:32
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:431
static constexpr EDA_ANGLE ANGLE_360
Definition: eda_angle.h:441
INSPECT_RESULT
Definition: eda_item.h:43
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h:81
@ 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:441
bool IsDCodeLayer(int aLayer)
Definition: layer_ids.h:1057
#define GERBER_DRAW_LAYER(x)
Definition: layer_ids.h:439
Message panel definition file.
KICOMMON_API 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:259
wxString UnescapeString(const wxString &aSource)
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
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:174
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:228
bool HitTestPoints(const VECTOR2I &pointA, const VECTOR2I &pointB, double threshold)
Test if two points are near each other.
Definition: trigo.h:165
double GetLineLength(const VECTOR2I &aPointA, const VECTOR2I &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:194
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:209
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:118
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588