KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_barcode.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) 2020 Thomas Pointhuber <[email protected]>
5 * Copyright (C) 2020 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 <core/type_helpers.h>
26#include <bitmaps.h>
27#include <gr_basic.h>
28#include <macros.h>
29#include <pcb_edit_frame.h>
30#include <richio.h>
31#include <trigo.h>
32
33#include <base_units.h>
34#include <pcb_barcode.h>
35#include <board.h>
37#include <pcb_text.h>
38#include <math/util.h> // for KiROUND
40#include <wx/log.h>
41#include <pgm_base.h>
44#include <scoped_set_reset.h>
45#include <stdexcept>
46#include <utility>
47#include <algorithm>
48#include <footprint.h>
49
50#include <backend/zint.h>
52#include <properties/property.h>
54
55constexpr int ECI_UTF8 = 26;
56
58 BOARD_ITEM( aParent, PCB_BARCODE_T ),
59 m_width( pcbIUScale.mmToIU( 40 ) ),
60 m_height( pcbIUScale.mmToIU( 40 ) ),
61 m_pos( 0, 0 ),
62 m_text( this ),
64 m_angle( 0 ),
66{
68}
69
70
74
75
77 BOARD_ITEM( aOther ),
78 m_width( aOther.m_width ),
79 m_height( aOther.m_height ),
80 m_pos( aOther.m_pos ),
81 m_margin( aOther.m_margin ),
82 m_text( aOther.m_text ),
83 m_kind( aOther.m_kind ),
84 m_angle( aOther.m_angle ),
86 m_poly( aOther.m_poly ),
87 m_symbolPoly( aOther.m_symbolPoly ),
88 m_textPoly( aOther.m_textPoly ),
89 m_bbox( aOther.m_bbox )
90{
91 m_text.SetParent( this );
92}
93
94
96{
97 if( this != &aOther )
98 {
99 BOARD_ITEM::operator=( aOther );
100
101 m_width = aOther.m_width;
102 m_height = aOther.m_height;
103 m_pos = aOther.m_pos;
104 m_margin = aOther.m_margin;
105 m_text = aOther.m_text;
106 m_kind = aOther.m_kind;
107 m_angle = aOther.m_angle;
109 m_poly = aOther.m_poly;
110 m_symbolPoly = aOther.m_symbolPoly;
111 m_textPoly = aOther.m_textPoly;
112 m_bbox = aOther.m_bbox;
113
114 m_text.SetParent( this );
115 }
116
117 return *this;
118}
119
120
122{
123 VECTOR2I delta = aPos - m_pos;
124 Move( delta );
125}
126
127
129{
130 return m_pos;
131}
132
133
134void PCB_BARCODE::SetText( const wxString& aNewText )
135{
136 m_text.SetText( aNewText );
137}
138
139
140wxString PCB_BARCODE::GetText() const
141{
142 return m_text.GetText();
143}
144
145
147{
148 return m_text.GetShownText( true );
149}
150
151
153{
154 m_layer = aLayer;
155 m_text.SetLayer( aLayer );
156
158}
159
160
161void PCB_BARCODE::SetTextSize( int aTextSize )
162{
163 m_text.SetTextSize( VECTOR2I( std::max( 1, aTextSize ), std::max( 1, aTextSize ) ) );
164 m_text.SetTextThickness( std::max( 1, GetPenSizeForNormal( m_text.GetTextHeight() ) ) );
165
167}
168
169
171{
172 return m_text.GetTextHeight();
173}
174
175
176void PCB_BARCODE::Move( const VECTOR2I& offset )
177{
178 m_pos += offset;
179 m_symbolPoly.Move( offset );
180 m_textPoly.Move( offset );
181 m_poly.Move( offset );
182 m_text.Move( offset );
183 m_bbox.Move( offset );
184}
185
186
187void PCB_BARCODE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
188{
189 RotatePoint( m_pos, aRotCentre, aAngle );
190 m_angle += aAngle;
191
193}
194
195
196void PCB_BARCODE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
197{
198 MIRROR( m_pos, aCentre, aFlipDirection );
199
200 if( aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
202
204
206}
207
208
209void PCB_BARCODE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings, bool aCheckSide )
210{
211 SetTextSize( settings.GetTextSize( GetLayer() ).y );
212}
213
214
216{
218
219 // Scale the symbol polygon to the desired barcode width/height (property values) and center it at m_pos
220 // Note: SetRect will rescale the symbol-only polygon and then rebuild m_poly
221 SetRect( m_pos - VECTOR2I( m_width / 2, m_height / 2 ),
222 m_pos + VECTOR2I( m_width / 2, m_height / 2 ) );
223
225
226 // Build full m_poly from symbol + optional text, then apply knockout if requested
227 m_poly.RemoveAllContours();
228 m_poly.Append( m_symbolPoly );
229
230 if( m_text.IsVisible() && m_textPoly.OutlineCount() )
231 m_poly.Append( m_textPoly );
232
233 m_poly.Fracture();
234
235 if( IsKnockout() )
236 {
237 // Enforce minimum margin: at least 10% of the smallest side of the barcode, rounded up
238 // to the nearest 0.1 mm. Use this as a lower bound for both axes.
239 int minSide = std::min( m_width, m_height );
240 int tenPercent = ( minSide + 9 ) / 10; // ceil(minSide * 0.1)
241 int step01mm = std::max( 1, pcbIUScale.mmToIU( 0.1 ) );
242 int tenPercentRounded = ( ( tenPercent + step01mm - 1 ) / step01mm ) * step01mm;
243
244 // Build inversion rectangle based on the local bbox of the current combined geometry
245 BOX2I bbox = m_poly.BBox();
246 bbox.Inflate( std::max( m_margin.x, tenPercentRounded ), std::max( m_margin.y, tenPercentRounded ) );
247
248 SHAPE_LINE_CHAIN rect;
249 rect.Append( bbox.GetLeft(), bbox.GetTop() );
250 rect.Append( bbox.GetRight(), bbox.GetTop() );
251 rect.Append( bbox.GetRight(), bbox.GetBottom() );
252 rect.Append( bbox.GetLeft(), bbox.GetBottom() );
253 rect.SetClosed( true );
254
256 ko.AddOutline( rect );
258 ko.Fracture();
259 m_poly = std::move( ko );
260 }
261
264
265 if( !m_angle.IsZero() )
266 m_poly.Rotate( m_angle, m_pos );
267
268 m_poly.CacheTriangulation( false );
269 m_bbox = m_poly.BBox();
270}
271
272
274{
275 m_textPoly.RemoveAllContours();
276
277 if( !m_text.IsVisible() )
278 return;
279
280 SHAPE_POLY_SET textPoly;
281 m_text.TransformTextToPolySet( textPoly, 0, GetMaxError(), ERROR_INSIDE );
282
283 if( textPoly.OutlineCount() == 0 )
284 return;
285
286 if( m_symbolPoly.OutlineCount() == 0 )
287 return;
288
289 BOX2I textBBox = textPoly.BBox();
290 BOX2I symbolBBox = m_symbolPoly.BBox();
291 VECTOR2I textPos;
292 int textOffset = pcbIUScale.mmToIU( 1 );
293 textPos.x = symbolBBox.GetCenter().x - textBBox.GetCenter().x;
294 textPos.y = symbolBBox.GetBottom() - textBBox.GetTop() + textOffset;
295
296 textPoly.Move( textPos );
297
298 m_textPoly = std::move( textPoly );
299 m_textPoly.CacheTriangulation();
300}
301
302
304{
305 m_symbolPoly.RemoveAllContours();
306 m_lastError.clear();
307
308 std::unique_ptr<zint_symbol, decltype( &ZBarcode_Delete )> symbol( ZBarcode_Create(), &ZBarcode_Delete );
309
310 if( !symbol )
311 {
312 wxLogError( wxT( "Zint: failed to allocate symbol" ) );
313 return;
314 }
315
316 symbol->input_mode = UNICODE_MODE;
317 symbol->show_hrt = 0; // do not show HRT
318
319 switch( m_kind )
320 {
322 symbol->symbology = BARCODE_CODE39;
323 break;
325 symbol->symbology = BARCODE_CODE128;
326 break;
328 symbol->symbology = BARCODE_QRCODE;
329 symbol->option_1 = to_underlying( m_errorCorrection );
330 break;
332 symbol->symbology = BARCODE_MICROQR;
333 symbol->option_1 = to_underlying( m_errorCorrection );
334 break;
336 symbol->symbology = BARCODE_DATAMATRIX;
337 break;
338 default:
339 wxLogError( wxT( "Zint: invalid barcode type" ) );
340 return;
341 }
342
343 wxString text = GetShownText();
344 wxScopedCharBuffer utf8Text = text.ToUTF8();
345 size_t length = utf8Text.length();
346 unsigned char* dataPtr = reinterpret_cast<unsigned char*>( utf8Text.data() );
347
348 if( text.empty() )
349 return;
350
351 if( ( m_kind == BARCODE_T::QR_CODE || m_kind == BARCODE_T::DATA_MATRIX ) && !text.IsAscii() )
352 {
353 symbol->eci = ECI_UTF8;
354 }
355
356 if( ZBarcode_Encode( symbol.get(), dataPtr, length ) >= ZINT_ERROR )
357 {
358 if( !text.IsAscii() )
359 {
360 m_lastError = _( "This barcode type does not support international "
361 "characters. Use QR Code or Data Matrix instead." );
362 }
363 else
364 {
365 m_lastError = wxString::FromUTF8( symbol->errtxt );
366 }
367 return;
368 }
369
370 if( ZBarcode_Buffer_Vector( symbol.get(), 0 ) >= ZINT_ERROR )
371 {
372 m_lastError = wxString::FromUTF8( symbol->errtxt );
373 return;
374 }
375
376 for( zint_vector_rect* rect = symbol->vector->rectangles; rect != nullptr; rect = rect->next )
377 {
378 // Round using absolute edges to avoid cumulative rounding drift across modules.
379 int x1 = KiROUND( rect->x * symbol->scale );
380 int x2 = KiROUND( ( rect->x + rect->width ) * symbol->scale );
381 int y1 = KiROUND( rect->y * symbol->scale );
382 int y2 = KiROUND( ( rect->y + rect->height ) * symbol->scale );
383
384 SHAPE_LINE_CHAIN shapeline;
385 shapeline.Append( x1, y1 );
386 shapeline.Append( x2, y1 );
387 shapeline.Append( x2, y2 );
388 shapeline.Append( x1, y2 );
389 shapeline.SetClosed( true );
390
391 m_symbolPoly.AddOutline( shapeline );
392 }
393
394 for( zint_vector_hexagon* hex = symbol->vector->hexagons; hex != nullptr; hex = hex->next )
395 {
396 // Compute vertices from center using minimal-diameter (inscribed circle) radius.
397 double r = hex->diameter / 2.0; // minimal radius
398 double cx = hex->x;
399 double cy = hex->y;
400
401 // Base orientation has apex at top; hex->rotation rotates by 0/90/180/270 degrees.
402 double baseAngles[6] = { 90.0, 30.0, -30.0, -90.0, -150.0, 150.0 };
403 double rot = static_cast<double>( hex->rotation );
404
405 SHAPE_LINE_CHAIN poly;
406
407 for( int k = 0; k < 6; ++k )
408 {
409 double ang = ( baseAngles[k] + rot ) * M_PI / 180.0;
410 int vx = KiROUND( cx + r * cos( ang ) );
411 int vy = KiROUND( cy + r * sin( ang ) );
412 poly.Append( vx, vy );
413 }
414 poly.SetClosed( true );
415
416 m_symbolPoly.AddOutline( poly );
417 }
418
419 // Set the position of the barcode to the center of the symbol polygon
420 if( m_symbolPoly.OutlineCount() > 0 )
421 {
422 VECTOR2I pos = m_symbolPoly.BBox().GetCenter();
423 m_symbolPoly.Move( -pos );
424 }
425
426 m_symbolPoly.CacheTriangulation();
427}
428
429
430void PCB_BARCODE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
431{
432 FOOTPRINT* parentFP = GetParentFootprint();
433
434 if( parentFP && aFrame->GetName() == PCB_EDIT_FRAME_NAME )
435 aList.emplace_back( _( "Footprint" ), parentFP->GetReference() );
436
437 aList.emplace_back( _( "Barcode" ), ENUM_MAP<BARCODE_T>::Instance().ToString( m_kind ) );
438
439 // Don't use GetShownText() here; we want to show the user the variable references
440 aList.emplace_back( _( "Text" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
441
442 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
443 aList.emplace_back( _( "Status" ), _( "Locked" ) );
444
445 aList.emplace_back( _( "Layer" ), GetLayerName() );
446
447 aList.emplace_back( _( "Angle" ), wxString::Format( wxT( "%g" ), m_angle.AsDegrees() ) );
448
449 aList.emplace_back( _( "Text Height" ), aFrame->MessageTextFromValue( m_text.GetTextHeight() ) );
450}
451
452
453bool PCB_BARCODE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
454{
455 if( !GetBoundingBox().Contains( aPosition ) )
456 return false;
457
458 SHAPE_POLY_SET hulls;
459
461
462 return hulls.Collide( aPosition );
463}
464
465
466bool PCB_BARCODE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
467{
468 BOX2I arect = aRect;
469 arect.Inflate( aAccuracy );
470
471 BOX2I rect = GetBoundingBox();
472
473 if( aAccuracy )
474 rect.Inflate( aAccuracy );
475
476 if( aContained )
477 return arect.Contains( rect );
478
479 return arect.Intersects( rect );
480}
481
482
483void PCB_BARCODE::SetRect( const VECTOR2I& aTopLeft, const VECTOR2I& aBotRight )
484{
485 // Rescale only the symbol polygon to the requested rectangle; text is rebuilt below
486 BOX2I bbox = m_symbolPoly.BBox();
487 int oldW = bbox.GetWidth();
488 int oldH = bbox.GetHeight();
489
490 VECTOR2I newPosition = ( aTopLeft + aBotRight ) / 2;
491 SetPosition( newPosition );
492 int newW = aBotRight.x - aTopLeft.x;
493 int newH = aBotRight.y - aTopLeft.y;
494 // Guard against zero/negative sizes from interactive edits; enforce a tiny minimum
495 int minIU = std::max( 1, pcbIUScale.mmToIU( 0.01 ) );
496 newW = std::max( newW, minIU );
497 newH = std::max( newH, minIU );
498
499 double scaleX = oldW ? static_cast<double>( newW ) / oldW : 1.0;
500 double scaleY = oldH ? static_cast<double>( newH ) / oldH : 1.0;
501
502 VECTOR2I oldCenter = bbox.GetCenter();
503 m_symbolPoly.Scale( scaleX, scaleY, oldCenter );
504
505 // After scaling, move the symbol polygon to be centered at the new position
506 VECTOR2I newCenter = m_symbolPoly.BBox().GetCenter();
507 VECTOR2I delta = newPosition - newCenter;
508
509 if( delta != VECTOR2I( 0, 0 ) )
510 m_symbolPoly.Move( delta );
511
512 // Update intended barcode symbol size (without text/margins)
513 m_width = newW;
514 m_height = newH;
515}
516
517
519{
520 return m_bbox;
521}
522
523
524wxString PCB_BARCODE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
525{
526 return wxString::Format( _( "Barcode '%s' on %s" ), GetText(), GetLayerName() );
527}
528
529
534
535
537{
538 return m_bbox;
539}
540
541
543 int aClearance, int aMaxError,
544 ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
545{
546 if( aLayer != m_layer && aLayer != UNDEFINED_LAYER )
547 return;
548
549 if( aClearance == 0 )
550 {
551 aBuffer.Append( m_poly );
552 }
553 else
554 {
555 SHAPE_POLY_SET poly = m_poly;
556 poly.Inflate( aClearance, CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS, aMaxError, aErrorLoc );
557 aBuffer.Append( poly );
558 }
559}
560
561
562std::shared_ptr<SHAPE> PCB_BARCODE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
563{
564 SHAPE_POLY_SET poly;
565 TransformShapeToPolygon( poly, aLayer, 0, 0, ERROR_INSIDE, true );
566
567 return std::make_shared<SHAPE_POLY_SET>( std::move( poly ) );
568}
569
570
571void PCB_BARCODE::GetBoundingHull( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
572 int aMaxError, ERROR_LOC aErrorLoc ) const
573{
574 auto getBoundingHull =
575 [this]( SHAPE_POLY_SET& aLocBuffer, const SHAPE_POLY_SET& aSource, int aLocClearance )
576 {
577 BOX2I rect = aSource.BBox( aLocClearance );
578 VECTOR2I corners[4];
579
580 corners[0].x = rect.GetOrigin().x;
581 corners[0].y = rect.GetOrigin().y;
582 corners[1].y = corners[0].y;
583 corners[1].x = rect.GetRight();
584 corners[2].x = corners[1].x;
585 corners[2].y = rect.GetBottom();
586 corners[3].y = corners[2].y;
587 corners[3].x = corners[0].x;
588
589 aLocBuffer.NewOutline();
590
591 for( VECTOR2I& corner : corners )
592 {
593 RotatePoint( corner, m_pos, m_angle );
594 aLocBuffer.Append( corner.x, corner.y );
595 }
596 };
597
598 if( aLayer == m_layer || aLayer == UNDEFINED_LAYER )
599 {
600 getBoundingHull( aBuffer, m_symbolPoly, aClearance );
601 getBoundingHull( aBuffer, m_textPoly, aClearance );
602 }
603}
604
605
607{
608 // Micro QR codes do not support High (H) error correction level
609 if( m_kind == BARCODE_T::MICRO_QR_CODE && aErrorCorrection == BARCODE_ECC_T::H )
611 else
612 m_errorCorrection = aErrorCorrection;
613 // Don't auto-compute here as it may be called during loading
614}
615
616
618{
619 m_kind = aKind;
620
621 // When switching to Micro QR, validate and adjust ECC if needed
624
625 // Don't auto-compute here as it may be called during loading
626}
627
628
630{
631 SetErrorCorrection( aErrorCorrection );
633}
634
635
637{
638 m_width = aWidth;
639
640 if( KeepSquare() )
641 m_height = aWidth;
642
644}
645
646
648{
649 m_height = aHeight;
650
651 if( KeepSquare() )
652 m_width = aHeight;
653
655}
656
657
659{
660 SetKind( aKind );
662}
663
664
666{
667 PCB_BARCODE* item = new PCB_BARCODE( *this );
668 item->CopyFrom( this );
669 return item;
670}
671
672
674{
675 wxCHECK_RET( aImage && aImage->Type() == PCB_BARCODE_T,
676 wxT( "Cannot swap data with non-barcode item." ) );
677
678 PCB_BARCODE* other = static_cast<PCB_BARCODE*>( aImage );
679
680 std::swap( *this, *other );
681
682 m_text.SetParent( this );
683 other->m_text.SetParent( other );
684}
685
686double PCB_BARCODE::Similarity( const BOARD_ITEM& aItem ) const
687{
688 if( !ClassOf( &aItem ) )
689 return 0.0;
690
691 const PCB_BARCODE* other = static_cast<const PCB_BARCODE*>( &aItem );
692
693 // Compare text, width, height, text height, position, and kind
694 double similarity = 0.0;
695 const double weight = 1.0 / 6.0;
696
697 if( GetText() == other->GetText() )
698 similarity += weight;
699 if( m_width == other->m_width )
700 similarity += weight;
701 if( m_height == other->m_height )
702 similarity += weight;
703 if( GetTextSize() == other->GetTextSize() )
704 similarity += weight;
705 if( GetPosition() == other->GetPosition() )
706 similarity += weight;
707 if( m_kind == other->m_kind )
708 similarity += weight;
709
710 return similarity;
711}
712
713int PCB_BARCODE::Compare( const PCB_BARCODE* aBarcode, const PCB_BARCODE* aOther )
714{
715 int diff;
716
717 if( ( diff = aBarcode->GetPosition().x - aOther->GetPosition().x ) != 0 )
718 return diff;
719
720 if( ( diff = aBarcode->GetPosition().y - aOther->GetPosition().y ) != 0 )
721 return diff;
722
723 if( ( diff = aBarcode->GetText().Cmp( aOther->GetText() ) ) != 0 )
724 return diff;
725
726 if( ( diff = aBarcode->GetWidth() - aOther->GetWidth() ) != 0 )
727 return diff;
728
729 if( ( diff = aBarcode->GetHeight() - aOther->GetHeight() ) != 0 )
730 return diff;
731
732 if( ( diff = aBarcode->GetTextSize() - aOther->GetTextSize() ) != 0 )
733 return diff;
734
735 if( ( diff = (int) aBarcode->GetKind() - (int) aOther->GetKind() ) != 0 )
736 return diff;
737
738 if( ( diff = aBarcode->m_angle.AsTenthsOfADegree() - aOther->m_angle.AsTenthsOfADegree() ) != 0 )
739 return diff;
740
741 if( ( diff = (int) aBarcode->GetErrorCorrection() - (int) aOther->GetErrorCorrection() ) != 0 )
742 return diff;
743
744 return 0;
745}
746
747
748bool PCB_BARCODE::operator==( const BOARD_ITEM& aItem ) const
749{
750 if( !ClassOf( &aItem ) )
751 return false;
752
753 const PCB_BARCODE* other = static_cast<const PCB_BARCODE*>( &aItem );
754
755 // Compare text, width, height, text height, position, and kind
756 return ( GetText() == other->GetText()
757 && m_width == other->m_width
758 && m_height == other->m_height
759 && GetTextSize() == other->GetTextSize()
760 && GetPosition() == other->GetPosition()
761 && m_kind == other->m_kind );
762}
763
764// ---- Property registration ----
765static struct PCB_BARCODE_DESC
766{
768 {
772
773 const wxString groupBarcode = _HKI( "Barcode Properties" );
774
776 if( kindMap.Choices().GetCount() == 0 )
777 {
778 kindMap.Undefined( BARCODE_T::QR_CODE );
779 kindMap.Map( BARCODE_T::CODE_39, _HKI( "CODE_39" ) )
780 .Map( BARCODE_T::CODE_128, _HKI( "CODE_128" ) )
781 .Map( BARCODE_T::DATA_MATRIX, _HKI( "DATA_MATRIX" ) )
782 .Map( BARCODE_T::QR_CODE, _HKI( "QR_CODE" ) )
783 .Map( BARCODE_T::MICRO_QR_CODE, _HKI( "MICRO_QR_CODE" ) );
784 }
785
787 if( eccMap.Choices().GetCount() == 0 )
788 {
789 eccMap.Undefined( BARCODE_ECC_T::L );
790 eccMap.Map( BARCODE_ECC_T::L, _HKI( "L (Low)" ) )
791 .Map( BARCODE_ECC_T::M, _HKI( "M (Medium)" ) )
792 .Map( BARCODE_ECC_T::Q, _HKI( "Q (Quartile)" ) )
793 .Map( BARCODE_ECC_T::H, _HKI( "H (High)" ) );
794 }
795
796 auto hasKnockout =
797 []( INSPECTABLE* aItem ) -> bool
798 {
799 if( PCB_BARCODE* bc = dynamic_cast<PCB_BARCODE*>( aItem ) )
800 return bc->IsKnockout();
801 return false;
802 };
803
804 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, wxString>( _HKI( "Text" ),
806
807 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, bool>( _HKI( "Show Text" ),
809
810 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Text Size" ),
812 PROPERTY_DISPLAY::PT_COORD ), groupBarcode );
813
814 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Width" ),
816 PROPERTY_DISPLAY::PT_COORD ), groupBarcode );
817
818 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Height" ),
820 PROPERTY_DISPLAY::PT_COORD ), groupBarcode );
821
822 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, double>( _HKI( "Orientation" ),
824
825 propMgr.AddProperty( new PROPERTY_ENUM<PCB_BARCODE, BARCODE_T>( _HKI( "Barcode Type" ),
827
828 auto isQRCode =
829 []( INSPECTABLE* aItem ) -> bool
830 {
831 if( PCB_BARCODE* bc = dynamic_cast<PCB_BARCODE*>( aItem ) )
832 return bc->GetKind() == BARCODE_T::QR_CODE || bc->GetKind() == BARCODE_T::MICRO_QR_CODE;
833
834 return false;
835 };
836
837 propMgr.AddProperty( new PROPERTY_ENUM<PCB_BARCODE, BARCODE_ECC_T>( _HKI( "Error Correction" ),
839 groupBarcode )
840 .SetAvailableFunc( isQRCode )
841 .SetChoicesFunc( []( INSPECTABLE* aItem )
842 {
843 PCB_BARCODE* barcode = static_cast<PCB_BARCODE*>( aItem );
844 wxPGChoices choices;
845
846 choices.Add( _( "L (Low)" ), static_cast<int>( BARCODE_ECC_T::L ) );
847 choices.Add( _( "M (Medium)" ), static_cast<int>( BARCODE_ECC_T::M ) );
848 choices.Add( _( "Q (Quartile)" ), static_cast<int>( BARCODE_ECC_T::Q ) );
849
850 // Only QR_CODE has High
851 if( barcode->GetKind() == BARCODE_T::QR_CODE )
852 choices.Add( _( "H (High)" ), static_cast<int>( BARCODE_ECC_T::H ) );
853
854 return choices;
855 } );
856
857 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, bool>( _HKI( "Knockout" ),
859
860 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Margin X" ),
862 PROPERTY_DISPLAY::PT_COORD ), groupBarcode ).SetAvailableFunc( hasKnockout );
863
864 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Margin Y" ),
866 PROPERTY_DISPLAY::PT_COORD ), groupBarcode ).SetAvailableFunc( hasKnockout );
867 }
869
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_OUTSIDE
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
constexpr int ARC_LOW_DEF
Definition base_units.h:128
BITMAPS
A list of all bitmap identifiers.
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
Container for design settings for a BOARD object.
VECTOR2I GetTextSize(PCB_LAYER_ID aLayer) const
Return the default text size from the layer class for the given layer.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:237
PCB_LAYER_ID m_layer
Definition board_item.h:459
bool IsLocked() const override
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
virtual void CopyFrom(const BOARD_ITEM *aOther)
bool IsSideSpecific() const
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
int GetMaxError() const
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 size_type GetWidth() const
Definition box2.h:214
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr coord_type GetTop() const
Definition box2.h:229
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
constexpr coord_type GetBottom() const
Definition box2.h:222
int AsTenthsOfADegree() const
Definition eda_angle.h:118
The base class for create windows for drawing purpose.
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition eda_item.cpp:338
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:93
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:41
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:727
static ENUM_MAP< T > & Instance()
Definition property.h:721
ENUM_MAP & Undefined(T aValue)
Definition property.h:734
wxPGChoices & Choices()
Definition property.h:770
const wxString & GetReference() const
Definition footprint.h:751
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:38
void SetKind(BARCODE_T aKind)
void SetTextSize(int aTextSize)
Change the height of the human-readable text displayed below the barcode.
void ComputeTextPoly()
Generate the internal polygon representation for the human-readable text.
double GetOrientation() const
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
~PCB_BARCODE()
Destructor.
VECTOR2I m_pos
Position of the barcode.
const BOX2I GetBoundingBox() const override
Get the axis-aligned bounding box of the barcode including text.
void SetBarcodeErrorCorrection(BARCODE_ECC_T aErrorCorrection)
void SetRect(const VECTOR2I &aTopLeft, const VECTOR2I &aBotRight)
Set the bounding rectangle of the barcode.
virtual const BOX2I ViewBBox() const override
Get the bbox used for drawing/view culling, may include additional view-only extents.
SHAPE_POLY_SET m_textPoly
Human-readable text only (cached, centered/positioned)
EDA_ITEM * Clone() const override
Create a copy of this item.
void SetErrorCorrection(BARCODE_ECC_T aErrorCorrection)
Set the error correction level used for QR codes.
void SetBarcodeHeight(int aHeight)
wxString m_lastError
void SetShowText(bool aShow)
SHAPE_POLY_SET m_poly
Full geometry (barcode + optional text or knockout)
EDA_ANGLE m_angle
SHAPE_POLY_SET m_symbolPoly
Barcode symbol only (cached, centered at origin)
void SetMarginY(int aY)
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
bool KeepSquare() const
void SetBarcodeText(const wxString &aText)
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Produce a short human-readable description of the item for UI lists.
void SetBarcodeKind(BARCODE_T aKind)
void GetBoundingHull(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
void AssembleBarcode()
Assemble the barcode polygon and text polygons into a single polygonal representation.
PCB_BARCODE & operator=(const PCB_BARCODE &aOther)
Copy assignment operator.
VECTOR2I GetPosition() const override
Get the position (center) of the barcode in internal units.
wxString GetText() const
void SetPosition(const VECTOR2I &aPos) override
void SetMarginX(int aX)
void SetOrientation(double aDegrees)
double Similarity(const BOARD_ITEM &aItem) const override
Compute a simple similarity score between this barcode and another board item.
int m_height
Barcode height.
PCB_TEXT m_text
void SetLayer(PCB_LAYER_ID aLayer) override
Set the drawing layer for the barcode and its text.
bool operator==(const BOARD_ITEM &aItem) const override
Equality comparison operator for board-level deduplication.
VECTOR2I m_margin
Margin around the barcode (only valid for knockout)
BOX2I m_bbox
BBox of m_poly (ie: barcode + text)
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate message panel information entries (e.g.
int GetTextSize() const
void SetBarcodeWidth(int aWidth)
bool IsKnockout() const override
int GetHeight() const
Get the barcode height (in internal units).
BITMAPS GetMenuImage() const override
Icon to show in context menus/toolbars for this item type.
wxString GetShownText() const
BARCODE_ECC_T m_errorCorrection
Error correction level for QR codes.
void SetIsKnockout(bool aEnable) override
static bool ClassOf(const EDA_ITEM *aItem)
Type-check helper.
Definition pcb_barcode.h:97
bool HitTest(const VECTOR2I &aPosition, int aAccuracy) const override
Hit-test a point against the barcode (text and symbol area).
PCB_BARCODE(BOARD_ITEM *aParent)
Construct a PCB_BARCODE.
int m_width
Barcode width.
int GetMarginY() const
void swapData(BOARD_ITEM *aImage) override
BARCODE_ECC_T GetErrorCorrection() const
bool GetShowText() const
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate the barcode around a given centre by the given angle.
int GetMarginX() const
BARCODE_T m_kind
static int Compare(const PCB_BARCODE *aBarcode, const PCB_BARCODE *aOther)
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the barcode (text + symbol shapes) to polygonal geometry suitable for filling/collision tests...
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipLeftRight) override
Flip the barcode horizontally or vertically around a centre point.
void ComputeBarcode()
Generate the internal polygon representation for the current barcode text, kind and error correction.
BARCODE_T GetKind() const
Returns the type of the barcode (QR, CODE_39, etc.).
int GetWidth() const
Get the barcode width (in internal units).
void SetText(const wxString &aText)
Set the barcode content text to encode.
void Move(const VECTOR2I &offset) override
Function Move.
PROPERTY_BASE & SetChoicesFunc(std::function< wxPGChoices(INSPECTABLE *)> aFunc)
Definition property.h:276
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
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.
int OutlineCount() const
Return the number of outlines in the set.
void Move(const VECTOR2I &aVector) override
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
@ CHAMFER_ACUTE_CORNERS
Acute angles are chamfered.
#define _(s)
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
#define PCB_EDIT_FRAME_NAME
int GetPenSizeForNormal(int aTextSize)
Definition gr_text.cpp:61
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:172
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:184
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:803
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Dwgs_User
Definition layer_ids.h:107
@ UNDEFINED_LAYER
Definition layer_ids.h:61
This file contains miscellaneous commonly used macros and functions.
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:45
FLIP_DIRECTION
Definition mirror.h:27
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:28
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:29
KICOMMON_API wxString EllipsizeStatusText(wxWindow *aWindow, const wxString &aString)
Ellipsize text (at the end) to be no more than 1/3 of the window width.
#define _HKI(x)
Definition page_info.cpp:44
static struct PCB_BARCODE_DESC _PCB_BARCODE_DESC
constexpr int ECI_UTF8
BARCODE class definition.
BARCODE_ECC_T
Definition pcb_barcode.h:52
BARCODE_T
Definition pcb_barcode.h:43
see class PGM_BASE
#define TYPE_HASH(x)
Definition property.h:74
#define IMPLEMENT_ENUM_TO_WXANY(type)
Definition property.h:821
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
Definition property.h:65
#define REGISTER_TYPE(x)
int delta
#define M_PI
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
constexpr auto to_underlying(E e) noexcept
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:101
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695