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 The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <base_units.h>
22#include <trigo.h>
23#include <bitmaps.h>
24#include <eda_text.h>
25#include <gerbview_frame.h>
27#include <gerber_draw_item.h>
28#include <gerber_file_image.h>
30#include <string_utils.h>
31#include <geometry/shape_arc.h>
32#include <math/util.h> // for KiROUND
33#include <widgets/msgpanel.h>
34
35#include <wx/msgdlg.h>
36
39{
40 m_GerberImageFile = aGerberImageFile;
42 m_Flashed = false;
43 m_DCode = 0;
44 m_UnitsMetric = false;
45 m_LayerNegative = false;
46 m_swapAxis = false;
47 m_mirrorA = false;
48 m_mirrorB = false;
49 m_drawScale.x = m_drawScale.y = 1.0;
50 m_lyrRotation = 0;
51
54}
55
56
60
61
63{
64 m_netAttributes = aNetAttributes;
65
68 {
69 m_GerberImageFile->m_ComponentsList.insert( std::make_pair( m_netAttributes.m_Cmpref, 0 ) );
70 }
71
73 m_GerberImageFile->m_NetnamesList.insert( std::make_pair( m_netAttributes.m_Netname, 0 ) );
74}
75
76
78{
79 // Return the layer this item is on, or 0 if the m_GerberImageFile is null.
80 return m_GerberImageFile ? m_GerberImageFile->m_GraphicLayer : 0;
81}
82
83
84bool GERBER_DRAW_ITEM::GetTextD_CodePrms( int& aSize, VECTOR2I& aPos, EDA_ANGLE& aOrientation )
85{
86 // calculate the best size and orientation of the D_Code text
87
88 if( m_DCode <= 0 )
89 return false; // No D_Code for this item
90
91 if( m_Flashed || m_ShapeType == GBR_ARC )
92 aPos = m_Start;
93 else // it is a line:
94 aPos = ( m_Start + m_End) / 2;
95
96 aPos = GetABPosition( aPos );
97
98 int size; // the best size for the text
99
100 if( GetDcodeDescr() )
101 size = GetDcodeDescr()->GetShapeDim( this );
102 else
103 size = std::min( m_Size.x, m_Size.y );
104
105 aOrientation = ANGLE_HORIZONTAL;
106
107 if( m_Flashed )
108 {
109 // A reasonable size for text is min_dim/3 because most of time this text has 3 chars.
110 aSize = size / 3;
111 }
112 else // this item is a line
113 {
115 EDA_ANGLE angle( delta );
116
117 aOrientation = angle.Normalize90();
118
119 // A reasonable size for text is size/2 because text needs margin below and above it.
120 // a margin = size/4 seems good, expecting the line len is large enough to show 3 chars,
121 // that is the case most of time.
122 aSize = size / 2;
123 }
124
125 return true;
126}
127
128
130{
131 /* Note: RS274Xrevd_e is obscure about the order of transforms:
132 * For instance: Rotation must be made after or before mirroring ?
133 * Note: if something is changed here, GetYXPosition must reflect changes
134 */
135 VECTOR2I abPos = aXYPosition + m_GerberImageFile->m_ImageJustifyOffset;
136
137 // We have also a draw transform (rotation and offset)
138 // order is rotation and after offset
139
140 if( m_swapAxis )
141 std::swap( abPos.x, abPos.y );
142
143 abPos += m_layerOffset + m_GerberImageFile->m_ImageOffset;
144 abPos.x = KiROUND( abPos.x * m_drawScale.x );
145 abPos.y = KiROUND( abPos.y * m_drawScale.y );
146 EDA_ANGLE rotation( m_lyrRotation + m_GerberImageFile->m_ImageRotation, DEGREES_T );
147
148 if( !rotation.IsZero() )
149 RotatePoint( abPos, -rotation );
150
151 // Negate A axis if mirrored
152 if( m_mirrorA )
153 abPos.x = -abPos.x;
154
155 // abPos.y must be negated when no mirror, because draw axis is top to bottom
156 if( !m_mirrorB )
157 abPos.y = -abPos.y;
158
159 // Now generate the draw transform
160 if( !m_GerberImageFile->m_DisplayRotation.IsZero() )
161 RotatePoint( abPos, m_GerberImageFile->m_DisplayRotation );
162
163 abPos.x += KiROUND( m_GerberImageFile->m_DisplayOffset.x * m_drawScale.x );
164 abPos.y += KiROUND( m_GerberImageFile->m_DisplayOffset.y * m_drawScale.y );
165
166 return abPos;
167}
168
169
171{
172 // do the inverse transform made by GetABPosition
173 VECTOR2I xyPos = aABPosition;
174
175 // First, undo the draw transform
176 xyPos.x -= KiROUND( m_GerberImageFile->m_DisplayOffset.x * m_drawScale.x );
177 xyPos.y -= KiROUND( m_GerberImageFile->m_DisplayOffset.y * m_drawScale.y );
178
179 if( !m_GerberImageFile->m_DisplayRotation.IsZero() )
180 RotatePoint( xyPos, -m_GerberImageFile->m_DisplayRotation );
181
182 if( m_mirrorA )
183 xyPos.x = -xyPos.x;
184
185 if( !m_mirrorB )
186 xyPos.y = -xyPos.y;
187
188 EDA_ANGLE rotation( m_lyrRotation + m_GerberImageFile->m_ImageRotation, DEGREES_T );
189
190 if( !rotation.IsZero() )
191 RotatePoint( xyPos, rotation );
192
193 xyPos.x = KiROUND( xyPos.x / m_drawScale.x );
194 xyPos.y = KiROUND( xyPos.y / m_drawScale.y );
195 xyPos -= m_layerOffset + m_GerberImageFile->m_ImageOffset;
196
197 if( m_swapAxis )
198 std::swap( xyPos.x, xyPos.y );
199
200 return xyPos - m_GerberImageFile->m_ImageJustifyOffset;
201}
202
203
205{
206 m_UnitsMetric = m_GerberImageFile->m_GerbMetric;
207 m_swapAxis = m_GerberImageFile->m_SwapAxis; // false if A = X, B = Y;
208
209 // true if A =Y, B = Y
210 m_mirrorA = m_GerberImageFile->m_MirrorA; // true: mirror / axe A
211 m_mirrorB = m_GerberImageFile->m_MirrorB; // true: mirror / axe B
212 m_drawScale = m_GerberImageFile->m_Scale; // A and B scaling factor
213 m_layerOffset = m_GerberImageFile->m_Offset; // Offset from OF command
214
215 // Rotation from RO command:
216 m_lyrRotation = m_GerberImageFile->m_LocalRotation;
217 m_LayerNegative = m_GerberImageFile->GetLayerParams().m_LayerNegative;
218}
219
220
222{
223 switch( m_ShapeType )
224 {
225 case GBR_SEGMENT: return _( "Line" );
226 case GBR_ARC: return _( "Arc" );
227 case GBR_CIRCLE: return _( "Circle" );
228 case GBR_SPOT_OVAL: return wxT( "spot_oval" );
229 case GBR_SPOT_CIRCLE: return wxT( "spot_circle" );
230 case GBR_SPOT_RECT: return wxT( "spot_rect" );
231 case GBR_SPOT_POLY: return wxT( "spot_poly" );
232 case GBR_POLYGON: return wxT( "polygon" );
233
234 case GBR_SPOT_MACRO:
235 {
236 wxString name = wxT( "apt_macro" );
237 D_CODE* dcode = GetDcodeDescr();
238
239 if( dcode && dcode->GetMacro() )
240 name << wxT(" ") << dcode->GetMacro()->m_AmName;
241
242 return name;
243 }
244
245 default: return wxT( "??" );
246 }
247}
248
249
251{
253 return nullptr;
254
255 if( m_GerberImageFile == nullptr )
256 return nullptr;
257
258 return m_GerberImageFile->GetDCODE( m_DCode );
259}
260
261
263{
264 // return a rectangle which is (pos,dim) in nature. therefore the +1
265 BOX2I bbox( m_Start, VECTOR2I( 1, 1 ) );
266 D_CODE* code = GetDcodeDescr();
267
268 // TODO(JE) GERBER_DRAW_ITEM maybe should actually be a number of subclasses.
269 // Until/unless that is changed, we need to do different things depending on
270 // what is actually being represented by this GERBER_DRAW_ITEM.
271
272 switch( m_ShapeType )
273 {
274 case GBR_POLYGON:
275 {
276 BOX2I bb = m_ShapeAsPolygon.BBox();
277 bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
278 bbox.SetOrigin( bb.GetOrigin() );
279 break;
280 }
281
282 case GBR_CIRCLE:
283 {
284 double radius = m_Start.Distance( m_End );
285 bbox.Inflate( radius, radius );
286 break;
287 }
288
289 case GBR_ARC:
290 {
291 EDA_ANGLE angle( atan2( double( m_End.y - m_ArcCentre.y ),
292 double( m_End.x - m_ArcCentre.x ) )
293 - atan2( double( m_Start.y - m_ArcCentre.y ),
294 double( m_Start.x - m_ArcCentre.x ) ),
295 RADIANS_T );
296
297 if( m_End == m_Start ) // Arc with the end point = start point is expected to be a circle.
298 angle = ANGLE_360;
299 else
300 angle.Normalize();
301
302 SHAPE_ARC arc( m_ArcCentre, m_Start, angle );
303 bbox = arc.BBox( m_Size.x / 2 ); // m_Size.x is the line thickness
304 break;
305 }
306
307 case GBR_SPOT_CIRCLE:
308 if( code )
309 {
310 int radius = code->m_Size.x >> 1;
311 bbox.Inflate( radius, radius );
312 }
313
314 break;
315
316 case GBR_SPOT_RECT:
317 if( code )
318 bbox.Inflate( code->m_Size.x / 2, code->m_Size.y / 2 );
319
320 break;
321
322 case GBR_SPOT_OVAL:
323 if( code )
324 bbox.Inflate( code->m_Size.x /2, code->m_Size.y / 2 );
325
326 break;
327
328 case GBR_SPOT_MACRO:
329 case GBR_SPOT_POLY:
330 if( code )
331 {
332 if( code->m_Polygon.OutlineCount() == 0 )
333 code->ConvertShapeToPolygon( this );
334
335 bbox.Inflate( code->m_Polygon.BBox().GetWidth() / 2,
336 code->m_Polygon.BBox().GetHeight() / 2 );
337 }
338
339 break;
340
341 case GBR_SEGMENT:
342 if( code && code->m_ApertType == APT_RECT )
343 {
344 if( m_ShapeAsPolygon.OutlineCount() == 0 )
345 {
346 // We cannot initialize m_ShapeAsPolygon, because we are in a const function.
347 // So use a temporary polygon
348 SHAPE_POLY_SET poly_shape;
349 ConvertSegmentToPolygon( &poly_shape );
350 bbox = poly_shape.BBox();
351 }
352
353 else
354 {
355 bbox = m_ShapeAsPolygon.BBox();
356 }
357 }
358 else
359 {
360 int radius = ( m_Size.x + 1 ) / 2;
361
362 int ymax = std::max( m_Start.y, m_End.y ) + radius;
363 int xmax = std::max( m_Start.x, m_End.x ) + radius;
364
365 int ymin = std::min( m_Start.y, m_End.y ) - radius;
366 int xmin = std::min( m_Start.x, m_End.x ) - radius;
367
368 bbox = BOX2I( VECTOR2I( xmin, ymin ), VECTOR2I( xmax - xmin + 1, ymax - ymin + 1 ) );
369 }
370
371 break;
372
373 default:
374 wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
375 break;
376 }
377
378 // calculate the corners coordinates in current Gerber axis orientations
379 // because the initial bbox is a horizontal rect, but the bbox in AB position
380 // is the bbox image with perhaps a rotation, we need to calculate the coords of the
381 // corners of the bbox rotated, and then calculate the final bounding box
382 VECTOR2I corners[4];
383 bbox.Normalize();
384
385 // Shape:
386 // 0...1
387 // . .
388 // . .
389 // 3...2
390 corners[0] = bbox.GetOrigin(); // top left
391 corners[2] = bbox.GetEnd(); // bottom right
392 corners[1] = VECTOR2I( corners[2].x, corners[0].y ); // top right
393 corners[3] = VECTOR2I( corners[0].x, corners[2].y ); // bottom left
394
395 VECTOR2I org = GetABPosition( bbox.GetOrigin() );;
396 VECTOR2I end = GetABPosition( bbox.GetEnd() );;
397
398 // Now calculate the bounding box of bbox, if the display image is rotated
399 // It will be perhaps a bit bigger than a better bounding box calculation, but it is fast
400 // and easy
401 // (if not rotated, this is a nop)
402 for( int ii = 0; ii < 4; ii++ )
403 {
404 corners[ii] = GetABPosition( corners[ii] );
405
406 org.x = std::min( org.x, corners[ii].x );
407 org.y = std::min( org.y, corners[ii].y );
408
409 end.x = std::max( end.x, corners[ii].x );
410 end.y = std::max( end.y, corners[ii].y );
411 }
412
413 // Set the corners position:
414 bbox.SetOrigin( org );
415 bbox.SetEnd( end );
416 bbox.Normalize();
417
418 return bbox;
419}
420
421
422void GERBER_DRAW_ITEM::MoveXY( const VECTOR2I& aMoveVector )
423{
424 m_Start += aMoveVector;
425 m_End += aMoveVector;
426 m_ArcCentre += aMoveVector;
427
428 m_ShapeAsPolygon.Move( aMoveVector );
429}
430
431
433{
434 bool isClear = m_LayerNegative ^ m_GerberImageFile->m_ImageNegative;
435
436 // if isClear is true, this item has negative shape
437 return isClear;
438}
439
440
441void GERBER_DRAW_ITEM::Print( wxDC* aDC, const VECTOR2I& aOffset, GBR_DISPLAY_OPTIONS* aOptions )
442{
443 // used when a D_CODE is not found. default D_CODE to draw a flashed item
444 static D_CODE dummyD_CODE( 0 );
445 bool isFilled;
446 int radius;
447 int halfPenWidth;
448 static bool show_err;
449 D_CODE* d_codeDescr = GetDcodeDescr();
450
451 if( d_codeDescr == nullptr )
452 d_codeDescr = &dummyD_CODE;
453
454 COLOR4D color = m_GerberImageFile->GetPositiveDrawColor();
455
456 /* isDark is true if flash is positive and should use a drawing
457 * color other than the background color, else use the background color
458 * when drawing so that an erasure happens.
459 */
460 bool isDark = !(m_LayerNegative ^ m_GerberImageFile->m_ImageNegative);
461
462 if( !isDark )
463 {
464 // draw in background color ("negative" color)
465 color = aOptions->m_NegativeDrawColor;
466 }
467
468 isFilled = aOptions->m_DisplayLinesFill;
469
470 switch( m_ShapeType )
471 {
472 case GBR_POLYGON:
473 isFilled = aOptions->m_DisplayPolygonsFill;
474
475 if( !isDark )
476 isFilled = true;
477
478 PrintGerberPoly( aDC, color, aOffset, isFilled );
479 break;
480
481 case GBR_CIRCLE:
482 radius = KiROUND( m_Start.Distance( m_End ) );
483
484 halfPenWidth = m_Size.x >> 1;
485
486 if( !isFilled )
487 {
488 // draw the border of the pen's path using two circles, each as narrow as possible
489 GRCircle( aDC, GetABPosition( m_Start ), radius - halfPenWidth, 0, color );
490 GRCircle( aDC, GetABPosition( m_Start ), radius + halfPenWidth, 0, color );
491 }
492 else // Filled mode
493 {
494 GRCircle( aDC, GetABPosition( m_Start ), radius, m_Size.x, color );
495 }
496
497 break;
498
499 case GBR_ARC:
500 // Currently, arcs plotted with a rectangular aperture are not supported.
501 // a round pen only is expected.
502 if( !isFilled )
503 {
505 GetABPosition( m_ArcCentre ), 0, color );
506 }
507 else
508 {
510 GetABPosition( m_ArcCentre ), m_Size.x, color );
511 }
512
513 break;
514
515 case GBR_SPOT_CIRCLE:
516 case GBR_SPOT_RECT:
517 case GBR_SPOT_OVAL:
518 case GBR_SPOT_POLY:
519 case GBR_SPOT_MACRO:
520 isFilled = aOptions->m_DisplayFlashedItemsFill;
521 d_codeDescr->DrawFlashedShape( this, aDC, color, m_Start, isFilled );
522 break;
523
524 case GBR_SEGMENT:
525 /* Plot a line from m_Start to m_End.
526 * Usually, a round pen is used, but some Gerber files use a rectangular pen
527 * In fact, any aperture can be used to plot a line.
528 * currently: only a square pen is handled (I believe using a polygon gives a strange plot).
529 */
530 if( d_codeDescr->m_ApertType == APT_RECT )
531 {
532 if( m_ShapeAsPolygon.OutlineCount() == 0 )
534
535 PrintGerberPoly( aDC, color, aOffset, isFilled );
536 }
537 else if( !isFilled )
538 {
539 GRCSegm( aDC, GetABPosition( m_Start ), GetABPosition( m_End ), m_Size.x, color );
540 }
541 else
542 {
544 color );
545 }
546
547 break;
548
549 default:
550 if( !show_err )
551 {
552 wxMessageBox( wxT( "Trace_Segment() type error" ) );
553 show_err = true;
554 }
555
556 break;
557 }
558}
559
560
562{
563 aPolygon->RemoveAllContours();
564 aPolygon->NewOutline();
565
566 VECTOR2I start = m_Start;
568
569 // make calculations more easy if ensure start.x < end.x
570 // (only 2 quadrants to consider)
571 if( start.x > end.x )
572 std::swap( start, end );
573
574 // calculate values relative to start point:
575 VECTOR2I delta = end - start;
576
577 // calculate corners for the first quadrant only (delta.x and delta.y > 0 )
578 // currently, delta.x already is > 0.
579 // make delta.y > 0
580 bool change = delta.y < 0;
581
582 if( change )
583 delta.y = -delta.y;
584
585 // Now create the full polygon.
586 // Due to previous changes, the shape is always something like
587 // 3 4
588 // 2 5
589 // 1 6
590 VECTOR2I corner;
591 corner.x -= m_Size.x/2;
592 corner.y -= m_Size.y/2;
593 VECTOR2I close = corner;
594 aPolygon->Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
595 corner.y += m_Size.y;
596 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
597
598 if( delta.x || delta.y )
599 {
600 corner += delta;
601 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
602 }
603
604 corner.x += m_Size.x;
605 aPolygon->Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
606 corner.y -= m_Size.y;
607 aPolygon->Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
608
609 if( delta.x || delta.y )
610 {
611 corner -= delta;
612 aPolygon->Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
613 }
614
615 aPolygon->Append( VECTOR2I( close ) ); // close the shape
616
617 // Create final polygon:
618 if( change )
619 aPolygon->Mirror( { 0, 0 }, FLIP_DIRECTION::TOP_BOTTOM );
620
621 aPolygon->Move( VECTOR2I( start ) );
622}
623
624
629
630
631void GERBER_DRAW_ITEM::PrintGerberPoly( wxDC* aDC, const COLOR4D& aColor, const VECTOR2I& aOffset,
632 bool aFilledShape )
633{
634 std::vector<VECTOR2I> points;
635 SHAPE_LINE_CHAIN& poly = m_ShapeAsPolygon.Outline( 0 );
636 int pointCount = poly.PointCount() - 1;
637
638 points.reserve( pointCount );
639
640 for( int ii = 0; ii < pointCount; ii++ )
641 {
642 VECTOR2I p( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
643 points[ii] = p + aOffset;
644 points[ii] = GetABPosition( points[ii] );
645 }
646
647 GRClosedPoly( aDC, pointCount, &points[0], aFilledShape, aColor );
648}
649
650
651void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
652{
653 wxString msg;
654 wxString text;
655
656 msg = ShowGBRShape();
657 aList.emplace_back( _( "Type" ), msg );
658
659 // Display D_Code value with its attributes for items using a DCode:
660 if( m_ShapeType == GBR_POLYGON ) // Has no DCode, but can have an attribute
661 {
662 msg = _( "Attribute" );
663
664 if( m_AperFunction.IsEmpty() )
665 text = _( "No attribute" );
666 else
668 }
669 else
670 {
671 msg.Printf( _( "D Code %d" ), m_DCode );
672 D_CODE* apertDescr = GetDcodeDescr();
673
674 if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
675 text = _( "No attribute" );
676 else
677 text = apertDescr->m_AperFunction;
678 }
679
680 aList.emplace_back( msg, text );
681
682 // Display graphic layer name
684 aList.emplace_back( _( "Graphic Layer" ), msg );
685
686 // Display item position
687 auto xStart = EDA_UNIT_UTILS::UI::ToUserUnit( gerbIUScale, aFrame->GetUserUnits(), m_Start.x );
688 auto yStart = EDA_UNIT_UTILS::UI::ToUserUnit( gerbIUScale, aFrame->GetUserUnits(), m_Start.y );
691
692 if( m_Flashed )
693 {
694 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
695 aList.emplace_back( _( "Position" ), msg );
696 }
697 else
698 {
699 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
700 aList.emplace_back( _( "Start" ), msg );
701
702 msg.Printf( wxT( "(%.4f, %.4f)" ), xEnd, yEnd );
703 aList.emplace_back( _( "End" ), msg );
704 }
705
706 // Display item rotation
707 // The full rotation is Image rotation + m_lyrRotation
708 // but m_lyrRotation is specific to this object
709 // so we display only this parameter
710 msg.Printf( wxT( "%f" ), m_lyrRotation );
711 aList.emplace_back( _( "Rotation" ), msg );
712
713 // Display item polarity (item specific)
714 msg = m_LayerNegative ? _("Clear") : _("Dark");
715 aList.emplace_back( _( "Polarity" ), msg );
716
717 // Display mirroring (item specific)
718 msg.Printf( wxT( "A:%s B:%s" ), m_mirrorA ? _( "Yes" ) : _( "No" ),
719 m_mirrorB ? _( "Yes" ) : _( "No" ) );
720 aList.emplace_back( _( "Mirror" ), msg );
721
722 // Display AB axis swap (item specific)
723 msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
724 aList.emplace_back( _( "AB axis" ), msg );
725
726 // Display net info, if exists
728 return;
729
730 // Build full net info:
731 wxString net_msg;
732 wxString cmp_pad_msg;
733
735 {
736 net_msg = _( "Net:" );
737 net_msg << wxS( " " );
738
739 if( m_netAttributes.m_Netname.IsEmpty() )
740 net_msg << _( "<no net>" );
741 else
742 net_msg << UnescapeString( m_netAttributes.m_Netname );
743 }
744
746 {
747 if( m_netAttributes.m_PadPinFunction.IsEmpty() )
748 {
749 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s" ),
750 m_netAttributes.m_Cmpref,
751 m_netAttributes.m_Padname.GetValue() );
752 }
753 else
754 {
755 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s Fct %s" ),
756 m_netAttributes.m_Cmpref,
757 m_netAttributes.m_Padname.GetValue(),
758 m_netAttributes.m_PadPinFunction.GetValue() );
759 }
760 }
761
762 else if( ( m_netAttributes.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_CMP ) )
763 {
764 cmp_pad_msg = _( "Cmp:" );
765 cmp_pad_msg << wxS( " " ) << m_netAttributes.m_Cmpref;
766 }
767
768 aList.emplace_back( net_msg, cmp_pad_msg );
769}
770
771
773{
774 if( m_Flashed )
775 return BITMAPS::pad;
776
777 switch( m_ShapeType )
778 {
779 case GBR_SEGMENT:
780 case GBR_ARC:
781 case GBR_CIRCLE:
782 return BITMAPS::add_line;
783
784 case GBR_SPOT_OVAL:
785 case GBR_SPOT_CIRCLE:
786 case GBR_SPOT_RECT:
787 case GBR_SPOT_POLY:
788 case GBR_SPOT_MACRO:
789 // should be handles by m_Flashed == true
790 return BITMAPS::pad;
791
792 case GBR_POLYGON:
794 }
795
796 return BITMAPS::info;
797}
798
799
800bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
801{
802 // In case the item has a very tiny width defined, allow it to be selected
803 const int MIN_HIT_TEST_RADIUS = gerbIUScale.mmToIU( 0.01 );
804
805 // calculate aRefPos in XY Gerber axis:
806 VECTOR2I ref_pos = GetXYPosition( aRefPos );
807
808 SHAPE_POLY_SET poly;
809
810 switch( m_ShapeType )
811 {
812 case GBR_POLYGON:
813 poly = m_ShapeAsPolygon;
814 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
815
816 case GBR_SPOT_POLY:
817 poly = GetDcodeDescr()->m_Polygon;
818 poly.Move( VECTOR2I( m_Start ) );
819 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
820
821 case GBR_SPOT_RECT:
822 return GetBoundingBox().Contains( aRefPos );
823
824 case GBR_SPOT_OVAL:
825 {
826 BOX2I bbox = GetBoundingBox();
827
828 if( ! bbox.Contains( aRefPos ) )
829 return false;
830
831 // This is similar to a segment with thickness = min( m_Size.x, m_Size.y )
832 int radius = std::min( m_Size.x, m_Size.y )/2;
833 VECTOR2I start, end;
834
835 if( m_Size.x > m_Size.y ) // Horizontal oval
836 {
837 int len = m_Size.y - m_Size.x;
838 start.x = -len/2;
839 end.x = len/2;
840 }
841 else // Vertical oval
842 {
843 int len = m_Size.x - m_Size.y;
844 start.y = -len/2;
845 end.y = len/2;
846 }
847
848 start += bbox.Centre();
849 end += bbox.Centre();
850
851 if( radius < MIN_HIT_TEST_RADIUS )
852 radius = MIN_HIT_TEST_RADIUS;
853
854 return TestSegmentHit( aRefPos, start, end, radius );
855 }
856
857 case GBR_ARC:
858 {
859 double radius = m_Start.Distance( m_ArcCentre );
860 VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
861
862 int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x );
863
864 // Are we close enough to the radius?
865 bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
866
867 if( radius_hit )
868 {
869 // Now check that we are within the arc angle
870
873 EDA_ANGLE start_angle( start );
874 EDA_ANGLE end_angle( end );
875
876 start_angle.Normalize();
877 end_angle.Normalize();
878
879 if( m_Start == m_End )
880 {
881 start_angle = ANGLE_0;
882 end_angle = ANGLE_360;
883 }
884 else if( end_angle < start_angle )
885 {
886 end_angle += ANGLE_360;
887 }
888
889 EDA_ANGLE test_angle( test_radius );
890 test_angle.Normalize();
891
892 return ( test_angle > start_angle && test_angle < end_angle );
893 }
894
895 return false;
896 }
897
898 case GBR_SPOT_MACRO:
899 return m_AbsolutePolygon.Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
900
901 case GBR_SEGMENT:
902 case GBR_CIRCLE:
903 case GBR_SPOT_CIRCLE:
904 break; // handled below.
905 }
906
907 // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
908 int radius = std::min( m_Size.x, m_Size.y ) >> 1;
909
910 if( radius < MIN_HIT_TEST_RADIUS )
911 radius = MIN_HIT_TEST_RADIUS;
912
913 if( m_Flashed )
914 return m_Start.Distance( ref_pos ) <= radius;
915 else
916 return TestSegmentHit( ref_pos, m_Start, m_End, radius );
917}
918
919
920bool GERBER_DRAW_ITEM::HitTest( const BOX2I& aRefArea, bool aContained, int aAccuracy ) const
921{
923
924 if( aRefArea.Contains( pos ) )
925 return true;
926
927 pos = GetABPosition( m_End );
928
929 if( aRefArea.Contains( pos ) )
930 return true;
931
932 return false;
933}
934
935
936#if defined(DEBUG)
937
938void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
939{
940 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
941 " shape=\"" << m_ShapeType << '"' <<
942 " addr=\"" << std::hex << this << std::dec << '"' <<
943 " layer=\"" << GetLayer() << '"' <<
944 " size=\"" << m_Size << '"' <<
945 " flags=\"" << m_flags << '"' <<
946 "<start" << m_Start << "/>" <<
947 "<end" << m_End << "/>";
948
949 os << "</" << GetClass().Lower().mb_str() << ">\n";
950}
951
952#endif
953
954
955std::vector<int> GERBER_DRAW_ITEM::ViewGetLayers() const
956{
957 std::vector<int> layers( 2 );
958 layers[0] = GERBER_DRAW_LAYER( GetLayer() );
959 layers[1] = GERBER_DCODE_LAYER( layers[0] );
960
961 return layers;
962}
963
964
966{
967 return GetBoundingBox();
968}
969
970
971double GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
972{
973 // DCodes will be shown only if zoom is appropriate:
974 // Returns the level of detail of the item.
975 // A level of detail (LOD) is the minimal VIEW scale that
976 // is sufficient for an item to be shown on a given layer.
977 if( IsDCodeLayer( aLayer ) )
978 {
979 int size = 0;
980
981 switch( m_ShapeType )
982 {
983 case GBR_SPOT_MACRO:
984 size = GetDcodeDescr()->m_Polygon.BBox().GetWidth();
985 break;
986
987 case GBR_ARC:
988 size = m_Start.Distance( m_ArcCentre );
989 break;
990
991 default:
992 size = m_Size.x;
993 }
994
995 // the level of details is chosen experimentally, to show
996 // only a readable text:
997 return lodScaleForThreshold( aView, size, gerbIUScale.mmToIU( 3.0 ) );
998 }
999
1000 // Other layers are shown without any conditions
1001 return LOD_SHOW;
1002}
1003
1004
1006 const std::vector<KICAD_T>& aScanTypes )
1007{
1008 for( KICAD_T scanType : aScanTypes )
1009 {
1010 if( scanType == Type() )
1011 {
1012 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
1013 return INSPECT_RESULT::QUIT;
1014 }
1015 }
1016
1018}
1019
1020
1021wxString GERBER_DRAW_ITEM::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1022{
1023 wxString layerName = GERBER_FILE_IMAGE_LIST::GetImagesList().GetDisplayName( GetLayer(), true );
1024
1025 return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
1026 ShowGBRShape(),
1027 m_DCode,
1028 GetLayer() + 1,
1029 layerName );
1030}
const char * name
constexpr EDA_IU_SCALE gerbIUScale
Definition base_units.h:120
BITMAPS
A list of all bitmap identifiers.
@ add_graphical_polygon
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
wxString m_AmName
The name of the aperture macro as defined like AMVB_RECTANGLE* (name is VB_RECTANGLE)
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:554
constexpr const Vec GetEnd() const
Definition box2.h:208
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:233
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:142
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr Vec Centre() const
Definition box2.h:93
constexpr size_type GetHeight() const
Definition box2.h:211
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:164
constexpr const Vec & GetOrigin() const
Definition box2.h:206
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:293
A gerber DCODE (also called Aperture) definition.
Definition dcode.h:76
APERTURE_MACRO * GetMacro() const
Definition dcode.h:132
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:149
wxString m_AperFunction
the aperture attribute (created by a TA.AperFunction command).
Definition dcode.h:210
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:111
static bool IsValidDcodeValue(int aDcodeValue)
Definition dcode.h:86
VECTOR2I m_Size
Horizontal and vertical dimensions.
Definition dcode.h:197
APERTURE_T m_ApertType
Aperture type ( Line, rectangle, circle, oval poly, macro )
Definition dcode.h:198
SHAPE_POLY_SET m_Polygon
Definition dcode.h:213
void ConvertShapeToPolygon(const GERBER_DRAW_ITEM *aParent)
Convert a shape to an equivalent polygon.
Definition dcode.cpp:293
EDA_ANGLE Normalize()
Definition eda_angle.h:229
EDA_ANGLE Normalize90()
Definition eda_angle.h:257
bool IsZero() const
Definition eda_angle.h:136
The base class for create windows for drawing purpose.
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:542
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:37
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.
@ 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)
virtual std::vector< int > ViewGetLayers() 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.
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.
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
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a pointer to an image to be used in menus.
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
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
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.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
static double lodScaleForThreshold(const KIGFX::VIEW *aView, int aWhatIu, int aThresholdIu)
Get the scale at which aWhatIu would be drawn at the same size as aThresholdIu on screen.
Definition view_item.cpp:35
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:181
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
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)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the line points about y or x (or both)
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:279
@ APT_RECT
Definition dcode.h:46
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
@ RADIANS_T
Definition eda_angle.h:32
@ DEGREES_T
Definition eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
INSPECT_RESULT
Definition eda_item.h:42
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:89
@ 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:358
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:352
void GRArc(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, int aWidth, const COLOR4D &aColor)
Definition gr_basic.cpp:379
#define GERBER_DCODE_LAYER(x)
Definition layer_ids.h:540
bool IsDCodeLayer(int aLayer)
Definition layer_ids.h:903
#define GERBER_DRAW_LAYER(x)
Definition layer_ids.h:538
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:25
Message panel definition file.
KICOMMON_API double ToUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Convert aValue in internal units to the appropriate user units defined by aUnit.
wxString UnescapeString(const wxString &aSource)
int radius
VECTOR2I end
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:171
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:225
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ GERBER_DRAW_ITEM_T
Definition typeinfo.h:207
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682