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, 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
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.
84 return m_GerberImageFile ? m_GerberImageFile->m_GraphicLayer : 0;
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
147 abPos += m_layerOffset + m_GerberImageFile->m_ImageOffset;
148 abPos.x = KiROUND( abPos.x * m_drawScale.x );
149 abPos.y = KiROUND( abPos.y * m_drawScale.y );
150 EDA_ANGLE rotation( m_lyrRotation + m_GerberImageFile->m_ImageRotation, DEGREES_T );
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
164 if( !m_GerberImageFile->m_DisplayRotation.IsZero() )
165 RotatePoint( abPos, m_GerberImageFile->m_DisplayRotation );
166
167 abPos.x += KiROUND( m_GerberImageFile->m_DisplayOffset.x * m_drawScale.x );
168 abPos.y += KiROUND( m_GerberImageFile->m_DisplayOffset.y * m_drawScale.y );
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
180 xyPos.x -= KiROUND( m_GerberImageFile->m_DisplayOffset.x * m_drawScale.x );
181 xyPos.y -= KiROUND( m_GerberImageFile->m_DisplayOffset.y * m_drawScale.y );
182
183 if( !m_GerberImageFile->m_DisplayRotation.IsZero() )
184 RotatePoint( xyPos, -m_GerberImageFile->m_DisplayRotation );
185
186 if( m_mirrorA )
187 xyPos.x = -xyPos.x;
188
189 if( !m_mirrorB )
190 xyPos.y = -xyPos.y;
191
192 EDA_ANGLE rotation( m_lyrRotation + m_GerberImageFile->m_ImageRotation, DEGREES_T );
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 );
199 xyPos -= m_layerOffset + m_GerberImageFile->m_ImageOffset;
200
201 if( m_swapAxis )
202 std::swap( xyPos.x, xyPos.y );
203
204 return xyPos - m_GerberImageFile->m_ImageJustifyOffset;
205}
206
207
209{
210 m_UnitsMetric = m_GerberImageFile->m_GerbMetric;
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:
220 m_lyrRotation = m_GerberImageFile->m_LocalRotation;
221 m_LayerNegative = m_GerberImageFile->GetLayerParams().m_LayerNegative;
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{
257 return nullptr;
258
259 if( m_GerberImageFile == nullptr )
260 return nullptr;
261
262 return m_GerberImageFile->GetDCODE( m_DCode );
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 {
280 BOX2I bb = m_ShapeAsPolygon.BBox();
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 = m_Start.Distance( 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 if( code )
313 {
314 int radius = code->m_Size.x >> 1;
315 bbox.Inflate( radius, radius );
316 }
317
318 break;
319
320 case GBR_SPOT_RECT:
321 if( code )
322 bbox.Inflate( code->m_Size.x / 2, code->m_Size.y / 2 );
323
324 break;
325
326 case GBR_SPOT_OVAL:
327 if( code )
328 bbox.Inflate( code->m_Size.x /2, code->m_Size.y / 2 );
329
330 break;
331
332 case GBR_SPOT_MACRO:
333 case GBR_SPOT_POLY:
334 if( code )
335 {
336 if( code->m_Polygon.OutlineCount() == 0 )
337 code->ConvertShapeToPolygon( this );
338
339 bbox.Inflate( code->m_Polygon.BBox().GetWidth() / 2,
340 code->m_Polygon.BBox().GetHeight() / 2 );
341 }
342
343 break;
344
345 case GBR_SEGMENT:
346 if( code && code->m_ApertType == APT_RECT )
347 {
348 if( m_ShapeAsPolygon.OutlineCount() == 0 )
349 {
350 // We cannot initialize m_ShapeAsPolygon, because we are in a const function.
351 // So use a temporary polygon
352 SHAPE_POLY_SET poly_shape;
353 ConvertSegmentToPolygon( &poly_shape );
354 bbox = poly_shape.BBox();
355 }
356
357 else
358 {
359 bbox = m_ShapeAsPolygon.BBox();
360 }
361 }
362 else
363 {
364 int radius = ( m_Size.x + 1 ) / 2;
365
366 int ymax = std::max( m_Start.y, m_End.y ) + radius;
367 int xmax = std::max( m_Start.x, m_End.x ) + radius;
368
369 int ymin = std::min( m_Start.y, m_End.y ) - radius;
370 int xmin = std::min( m_Start.x, m_End.x ) - radius;
371
372 bbox = BOX2I( VECTOR2I( xmin, ymin ), VECTOR2I( xmax - xmin + 1, ymax - ymin + 1 ) );
373 }
374
375 break;
376
377 default:
378 wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
379 break;
380 }
381
382 // calculate the corners coordinates in current Gerber axis orientations
383 // because the initial bbox is a horizontal rect, but the bbox in AB position
384 // is the bbox image with perhaps a rotation, we need to calculate the coords of the
385 // corners of the bbox rotated, and then calculate the final bounding box
386 VECTOR2I corners[4];
387 bbox.Normalize();
388
389 // Shape:
390 // 0...1
391 // . .
392 // . .
393 // 3...2
394 corners[0] = bbox.GetOrigin(); // top left
395 corners[2] = bbox.GetEnd(); // bottom right
396 corners[1] = VECTOR2I( corners[2].x, corners[0].y ); // top right
397 corners[3] = VECTOR2I( corners[0].x, corners[2].y ); // bottom left
398
399 VECTOR2I org = GetABPosition( bbox.GetOrigin() );;
400 VECTOR2I end = GetABPosition( bbox.GetEnd() );;
401
402 // Now calculate the bounding box of bbox, if the display image is rotated
403 // It will be perhaps a bit bigger than a better bounding box calculation, but it is fast
404 // and easy
405 // (if not rotated, this is a nop)
406 for( int ii = 0; ii < 4; ii++ )
407 {
408 corners[ii] = GetABPosition( corners[ii] );
409
410 org.x = std::min( org.x, corners[ii].x );
411 org.y = std::min( org.y, corners[ii].y );
412
413 end.x = std::max( end.x, corners[ii].x );
414 end.y = std::max( end.y, corners[ii].y );
415 }
416
417 // Set the corners position:
418 bbox.SetOrigin( org );
419 bbox.SetEnd( end );
420 bbox.Normalize();
421
422 return bbox;
423}
424
425
426void GERBER_DRAW_ITEM::MoveXY( const VECTOR2I& aMoveVector )
427{
428 m_Start += aMoveVector;
429 m_End += aMoveVector;
430 m_ArcCentre += aMoveVector;
431
432 m_ShapeAsPolygon.Move( aMoveVector );
433}
434
435
437{
438 bool isClear = m_LayerNegative ^ m_GerberImageFile->m_ImageNegative;
439
440 // if isClear is true, this item has negative shape
441 return isClear;
442}
443
444
445void GERBER_DRAW_ITEM::Print( wxDC* aDC, const VECTOR2I& aOffset, GBR_DISPLAY_OPTIONS* aOptions )
446{
447 // used when a D_CODE is not found. default D_CODE to draw a flashed item
448 static D_CODE dummyD_CODE( 0 );
449 bool isFilled;
450 int radius;
451 int halfPenWidth;
452 static bool show_err;
453 D_CODE* d_codeDescr = GetDcodeDescr();
454
455 if( d_codeDescr == nullptr )
456 d_codeDescr = &dummyD_CODE;
457
458 COLOR4D color = m_GerberImageFile->GetPositiveDrawColor();
459
460 /* isDark is true if flash is positive and should use a drawing
461 * color other than the background color, else use the background color
462 * when drawing so that an erasure happens.
463 */
464 bool isDark = !(m_LayerNegative ^ m_GerberImageFile->m_ImageNegative);
465
466 if( !isDark )
467 {
468 // draw in background color ("negative" color)
469 color = aOptions->m_NegativeDrawColor;
470 }
471
472 isFilled = aOptions->m_DisplayLinesFill;
473
474 switch( m_ShapeType )
475 {
476 case GBR_POLYGON:
477 isFilled = aOptions->m_DisplayPolygonsFill;
478
479 if( !isDark )
480 isFilled = true;
481
482 PrintGerberPoly( aDC, color, aOffset, isFilled );
483 break;
484
485 case GBR_CIRCLE:
486 radius = KiROUND( m_Start.Distance( m_End ) );
487
488 halfPenWidth = m_Size.x >> 1;
489
490 if( !isFilled )
491 {
492 // draw the border of the pen's path using two circles, each as narrow as possible
493 GRCircle( aDC, GetABPosition( m_Start ), radius - halfPenWidth, 0, color );
494 GRCircle( aDC, GetABPosition( m_Start ), radius + halfPenWidth, 0, color );
495 }
496 else // Filled mode
497 {
498 GRCircle( aDC, GetABPosition( m_Start ), radius, m_Size.x, color );
499 }
500
501 break;
502
503 case GBR_ARC:
504 // Currently, arcs plotted with a rectangular aperture are not supported.
505 // a round pen only is expected.
506 if( !isFilled )
507 {
509 GetABPosition( m_ArcCentre ), 0, color );
510 }
511 else
512 {
514 GetABPosition( m_ArcCentre ), m_Size.x, color );
515 }
516
517 break;
518
519 case GBR_SPOT_CIRCLE:
520 case GBR_SPOT_RECT:
521 case GBR_SPOT_OVAL:
522 case GBR_SPOT_POLY:
523 case GBR_SPOT_MACRO:
524 isFilled = aOptions->m_DisplayFlashedItemsFill;
525 d_codeDescr->DrawFlashedShape( this, aDC, color, m_Start, isFilled );
526 break;
527
528 case GBR_SEGMENT:
529 /* Plot a line from m_Start to m_End.
530 * Usually, a round pen is used, but some Gerber files use a rectangular pen
531 * In fact, any aperture can be used to plot a line.
532 * currently: only a square pen is handled (I believe using a polygon gives a strange plot).
533 */
534 if( d_codeDescr->m_ApertType == APT_RECT )
535 {
536 if( m_ShapeAsPolygon.OutlineCount() == 0 )
538
539 PrintGerberPoly( aDC, color, aOffset, isFilled );
540 }
541 else if( !isFilled )
542 {
543 GRCSegm( aDC, GetABPosition( m_Start ), GetABPosition( m_End ), m_Size.x, color );
544 }
545 else
546 {
548 color );
549 }
550
551 break;
552
553 default:
554 if( !show_err )
555 {
556 wxMessageBox( wxT( "Trace_Segment() type error" ) );
557 show_err = true;
558 }
559
560 break;
561 }
562}
563
564
566{
567 aPolygon->RemoveAllContours();
568 aPolygon->NewOutline();
569
570 VECTOR2I start = m_Start;
572
573 // make calculations more easy if ensure start.x < end.x
574 // (only 2 quadrants to consider)
575 if( start.x > end.x )
576 std::swap( start, end );
577
578 // calculate values relative to start point:
579 VECTOR2I delta = end - start;
580
581 // calculate corners for the first quadrant only (delta.x and delta.y > 0 )
582 // currently, delta.x already is > 0.
583 // make delta.y > 0
584 bool change = delta.y < 0;
585
586 if( change )
587 delta.y = -delta.y;
588
589 // Now create the full polygon.
590 // Due to previous changes, the shape is always something like
591 // 3 4
592 // 2 5
593 // 1 6
594 VECTOR2I corner;
595 corner.x -= m_Size.x/2;
596 corner.y -= m_Size.y/2;
597 VECTOR2I close = corner;
598 aPolygon->Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
599 corner.y += m_Size.y;
600 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
601
602 if( delta.x || delta.y )
603 {
604 corner += delta;
605 aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
606 }
607
608 corner.x += m_Size.x;
609 aPolygon->Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
610 corner.y -= m_Size.y;
611 aPolygon->Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
612
613 if( delta.x || delta.y )
614 {
615 corner -= delta;
616 aPolygon->Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
617 }
618
619 aPolygon->Append( VECTOR2I( close ) ); // close the shape
620
621 // Create final polygon:
622 if( change )
623 aPolygon->Mirror( { 0, 0 }, FLIP_DIRECTION::TOP_BOTTOM );
624
625 aPolygon->Move( VECTOR2I( start ) );
626}
627
628
633
634
635void GERBER_DRAW_ITEM::PrintGerberPoly( wxDC* aDC, const COLOR4D& aColor, const VECTOR2I& aOffset,
636 bool aFilledShape )
637{
638 std::vector<VECTOR2I> points;
639 SHAPE_LINE_CHAIN& poly = m_ShapeAsPolygon.Outline( 0 );
640 int pointCount = poly.PointCount() - 1;
641
642 points.reserve( pointCount );
643
644 for( int ii = 0; ii < pointCount; ii++ )
645 {
646 VECTOR2I p( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
647 points[ii] = p + aOffset;
648 points[ii] = GetABPosition( points[ii] );
649 }
650
651 GRClosedPoly( aDC, pointCount, &points[0], aFilledShape, aColor );
652}
653
654
655void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
656{
657 wxString msg;
658 wxString text;
659
660 msg = ShowGBRShape();
661 aList.emplace_back( _( "Type" ), msg );
662
663 // Display D_Code value with its attributes for items using a DCode:
664 if( m_ShapeType == GBR_POLYGON ) // Has no DCode, but can have an attribute
665 {
666 msg = _( "Attribute" );
667
668 if( m_AperFunction.IsEmpty() )
669 text = _( "No attribute" );
670 else
672 }
673 else
674 {
675 msg.Printf( _( "D Code %d" ), m_DCode );
676 D_CODE* apertDescr = GetDcodeDescr();
677
678 if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
679 text = _( "No attribute" );
680 else
681 text = apertDescr->m_AperFunction;
682 }
683
684 aList.emplace_back( msg, text );
685
686 // Display graphic layer name
688 aList.emplace_back( _( "Graphic Layer" ), msg );
689
690 // Display item position
691 auto xStart = EDA_UNIT_UTILS::UI::ToUserUnit( gerbIUScale, aFrame->GetUserUnits(), m_Start.x );
692 auto yStart = EDA_UNIT_UTILS::UI::ToUserUnit( gerbIUScale, aFrame->GetUserUnits(), m_Start.y );
695
696 if( m_Flashed )
697 {
698 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
699 aList.emplace_back( _( "Position" ), msg );
700 }
701 else
702 {
703 msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
704 aList.emplace_back( _( "Start" ), msg );
705
706 msg.Printf( wxT( "(%.4f, %.4f)" ), xEnd, yEnd );
707 aList.emplace_back( _( "End" ), msg );
708 }
709
710 // Display item rotation
711 // The full rotation is Image rotation + m_lyrRotation
712 // but m_lyrRotation is specific to this object
713 // so we display only this parameter
714 msg.Printf( wxT( "%f" ), m_lyrRotation );
715 aList.emplace_back( _( "Rotation" ), msg );
716
717 // Display item polarity (item specific)
718 msg = m_LayerNegative ? _("Clear") : _("Dark");
719 aList.emplace_back( _( "Polarity" ), msg );
720
721 // Display mirroring (item specific)
722 msg.Printf( wxT( "A:%s B:%s" ), m_mirrorA ? _( "Yes" ) : _( "No" ),
723 m_mirrorB ? _( "Yes" ) : _( "No" ) );
724 aList.emplace_back( _( "Mirror" ), msg );
725
726 // Display AB axis swap (item specific)
727 msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
728 aList.emplace_back( _( "AB axis" ), msg );
729
730 // Display net info, if exists
732 return;
733
734 // Build full net info:
735 wxString net_msg;
736 wxString cmp_pad_msg;
737
739 {
740 net_msg = _( "Net:" );
741 net_msg << wxS( " " );
742
743 if( m_netAttributes.m_Netname.IsEmpty() )
744 net_msg << _( "<no net>" );
745 else
746 net_msg << UnescapeString( m_netAttributes.m_Netname );
747 }
748
750 {
751 if( m_netAttributes.m_PadPinFunction.IsEmpty() )
752 {
753 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s" ),
754 m_netAttributes.m_Cmpref,
755 m_netAttributes.m_Padname.GetValue() );
756 }
757 else
758 {
759 cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s Fct %s" ),
760 m_netAttributes.m_Cmpref,
761 m_netAttributes.m_Padname.GetValue(),
762 m_netAttributes.m_PadPinFunction.GetValue() );
763 }
764 }
765
766 else if( ( m_netAttributes.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_CMP ) )
767 {
768 cmp_pad_msg = _( "Cmp:" );
769 cmp_pad_msg << wxS( " " ) << m_netAttributes.m_Cmpref;
770 }
771
772 aList.emplace_back( net_msg, cmp_pad_msg );
773}
774
775
777{
778 if( m_Flashed )
779 return BITMAPS::pad;
780
781 switch( m_ShapeType )
782 {
783 case GBR_SEGMENT:
784 case GBR_ARC:
785 case GBR_CIRCLE:
786 return BITMAPS::add_line;
787
788 case GBR_SPOT_OVAL:
789 case GBR_SPOT_CIRCLE:
790 case GBR_SPOT_RECT:
791 case GBR_SPOT_POLY:
792 case GBR_SPOT_MACRO:
793 // should be handles by m_Flashed == true
794 return BITMAPS::pad;
795
796 case GBR_POLYGON:
798 }
799
800 return BITMAPS::info;
801}
802
803
804bool GERBER_DRAW_ITEM::HitTest( const VECTOR2I& aRefPos, int aAccuracy ) const
805{
806 // In case the item has a very tiny width defined, allow it to be selected
807 const int MIN_HIT_TEST_RADIUS = gerbIUScale.mmToIU( 0.01 );
808
809 // calculate aRefPos in XY Gerber axis:
810 VECTOR2I ref_pos = GetXYPosition( aRefPos );
811
812 SHAPE_POLY_SET poly;
813
814 switch( m_ShapeType )
815 {
816 case GBR_POLYGON:
817 poly = m_ShapeAsPolygon;
818 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
819
820 case GBR_SPOT_POLY:
821 poly = GetDcodeDescr()->m_Polygon;
822 poly.Move( VECTOR2I( m_Start ) );
823 return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
824
825 case GBR_SPOT_RECT:
826 return GetBoundingBox().Contains( aRefPos );
827
828 case GBR_SPOT_OVAL:
829 {
830 BOX2I bbox = GetBoundingBox();
831
832 if( ! bbox.Contains( aRefPos ) )
833 return false;
834
835 // This is similar to a segment with thickness = min( m_Size.x, m_Size.y )
836 int radius = std::min( m_Size.x, m_Size.y )/2;
837 VECTOR2I start, end;
838
839 if( m_Size.x > m_Size.y ) // Horizontal oval
840 {
841 int len = m_Size.y - m_Size.x;
842 start.x = -len/2;
843 end.x = len/2;
844 }
845 else // Vertical oval
846 {
847 int len = m_Size.x - m_Size.y;
848 start.y = -len/2;
849 end.y = len/2;
850 }
851
852 start += bbox.Centre();
853 end += bbox.Centre();
854
855 if( radius < MIN_HIT_TEST_RADIUS )
856 radius = MIN_HIT_TEST_RADIUS;
857
858 return TestSegmentHit( aRefPos, start, end, radius );
859 }
860
861 case GBR_ARC:
862 {
863 double radius = m_Start.Distance( m_ArcCentre );
864 VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
865
866 int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x );
867
868 // Are we close enough to the radius?
869 bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
870
871 if( radius_hit )
872 {
873 // Now check that we are within the arc angle
874
877 EDA_ANGLE start_angle( start );
878 EDA_ANGLE end_angle( end );
879
880 start_angle.Normalize();
881 end_angle.Normalize();
882
883 if( m_Start == m_End )
884 {
885 start_angle = ANGLE_0;
886 end_angle = ANGLE_360;
887 }
888 else if( end_angle < start_angle )
889 {
890 end_angle += ANGLE_360;
891 }
892
893 EDA_ANGLE test_angle( test_radius );
894 test_angle.Normalize();
895
896 return ( test_angle > start_angle && test_angle < end_angle );
897 }
898
899 return false;
900 }
901
902 case GBR_SPOT_MACRO:
903 return m_AbsolutePolygon.Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
904
905 case GBR_SEGMENT:
906 case GBR_CIRCLE:
907 case GBR_SPOT_CIRCLE:
908 break; // handled below.
909 }
910
911 // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
912 int radius = std::min( m_Size.x, m_Size.y ) >> 1;
913
914 if( radius < MIN_HIT_TEST_RADIUS )
915 radius = MIN_HIT_TEST_RADIUS;
916
917 if( m_Flashed )
918 return m_Start.Distance( ref_pos ) <= radius;
919 else
920 return TestSegmentHit( ref_pos, m_Start, m_End, radius );
921}
922
923
924bool GERBER_DRAW_ITEM::HitTest( const BOX2I& aRefArea, bool aContained, int aAccuracy ) const
925{
927
928 if( aRefArea.Contains( pos ) )
929 return true;
930
931 pos = GetABPosition( m_End );
932
933 if( aRefArea.Contains( pos ) )
934 return true;
935
936 return false;
937}
938
939
940#if defined(DEBUG)
941
942void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
943{
944 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
945 " shape=\"" << m_ShapeType << '"' <<
946 " addr=\"" << std::hex << this << std::dec << '"' <<
947 " layer=\"" << GetLayer() << '"' <<
948 " size=\"" << m_Size << '"' <<
949 " flags=\"" << m_flags << '"' <<
950 "<start" << m_Start << "/>" <<
951 "<end" << m_End << "/>";
952
953 os << "</" << GetClass().Lower().mb_str() << ">\n";
954}
955
956#endif
957
958
959std::vector<int> GERBER_DRAW_ITEM::ViewGetLayers() const
960{
961 std::vector<int> layers( 2 );
962 layers[0] = GERBER_DRAW_LAYER( GetLayer() );
963 layers[1] = GERBER_DCODE_LAYER( layers[0] );
964
965 return layers;
966}
967
968
970{
971 return GetBoundingBox();
972}
973
974
975double GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
976{
977 // DCodes will be shown only if zoom is appropriate:
978 // Returns the level of detail of the item.
979 // A level of detail (LOD) is the minimal VIEW scale that
980 // is sufficient for an item to be shown on a given layer.
981 if( IsDCodeLayer( aLayer ) )
982 {
983 int size = 0;
984
985 switch( m_ShapeType )
986 {
987 case GBR_SPOT_MACRO:
988 size = GetDcodeDescr()->m_Polygon.BBox().GetWidth();
989 break;
990
991 case GBR_ARC:
992 size = m_Start.Distance( m_ArcCentre );
993 break;
994
995 default:
996 size = m_Size.x;
997 }
998
999 // the level of details is chosen experimentally, to show
1000 // only a readable text:
1001 return lodScaleForThreshold( aView, size, gerbIUScale.mmToIU( 3.0 ) );
1002 }
1003
1004 // Other layers are shown without any conditions
1005 return LOD_SHOW;
1006}
1007
1008
1010 const std::vector<KICAD_T>& aScanTypes )
1011{
1012 for( KICAD_T scanType : aScanTypes )
1013 {
1014 if( scanType == Type() )
1015 {
1016 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
1017 return INSPECT_RESULT::QUIT;
1018 }
1019 }
1020
1022}
1023
1024
1025wxString GERBER_DRAW_ITEM::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1026{
1027 wxString layerName = GERBER_FILE_IMAGE_LIST::GetImagesList().GetDisplayName( GetLayer(), true );
1028
1029 return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
1030 ShowGBRShape(),
1031 m_DCode,
1032 GetLayer() + 1,
1033 layerName );
1034}
const char * name
constexpr EDA_IU_SCALE gerbIUScale
Definition base_units.h:111
BITMAPS
A list of all bitmap identifiers.
@ add_graphical_polygon
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
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:558
constexpr const Vec GetEnd() const
Definition box2.h:212
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr Vec Centre() const
Definition box2.h:97
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
A gerber DCODE (also called Aperture) definition.
Definition dcode.h:80
APERTURE_MACRO * GetMacro() const
Definition dcode.h:136
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:214
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
static bool IsValidDcodeValue(int aDcodeValue)
Definition dcode.h:90
VECTOR2I m_Size
Horizontal and vertical dimensions.
Definition dcode.h:201
APERTURE_T m_ApertType
Aperture type ( Line, rectangle, circle, oval poly, macro )
Definition dcode.h:202
SHAPE_POLY_SET m_Polygon
Definition dcode.h:217
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: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:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:527
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:39
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:105
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:39
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:185
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
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:283
@ APT_RECT
Definition dcode.h:50
#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:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
@ 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:542
bool IsDCodeLayer(int aLayer)
Definition layer_ids.h:905
#define GERBER_DRAW_LAYER(x)
Definition layer_ids.h:540
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:29
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:175
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694