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 <api/api_enums.h>
35#include <api/board/board_types.pb.h>
36#include <pcb_barcode.h>
37#include <board.h>
39#include <pcb_text.h>
40#include <math/util.h> // for KiROUND
42#include <wx/log.h>
43#include <pgm_base.h>
46#include <scoped_set_reset.h>
47#include <stdexcept>
48#include <utility>
49#include <algorithm>
50#include <api/api_utils.h>
51#include <footprint.h>
52
53#include <backend/zint.h>
55#include <google/protobuf/any.pb.h>
56#include <properties/property.h>
58
59constexpr int ECI_UTF8 = 26;
60
62 BOARD_ITEM( aParent, PCB_BARCODE_T ),
63 m_width( pcbIUScale.mmToIU( 40 ) ),
64 m_height( pcbIUScale.mmToIU( 40 ) ),
65 m_pos( 0, 0 ),
66 m_text( this ),
68 m_angle( 0 ),
70{
72}
73
74
78
79
81 BOARD_ITEM( aOther ),
82 m_width( aOther.m_width ),
83 m_height( aOther.m_height ),
84 m_pos( aOther.m_pos ),
85 m_margin( aOther.m_margin ),
86 m_text( aOther.m_text ),
87 m_kind( aOther.m_kind ),
88 m_angle( aOther.m_angle ),
90 m_poly( aOther.m_poly ),
91 m_symbolPoly( aOther.m_symbolPoly ),
92 m_textPoly( aOther.m_textPoly ),
93 m_bbox( aOther.m_bbox )
94{
95 m_text.SetParent( this );
96}
97
98
100{
101 if( this != &aOther )
102 {
103 BOARD_ITEM::operator=( aOther );
104
105 m_width = aOther.m_width;
106 m_height = aOther.m_height;
107 m_pos = aOther.m_pos;
108 m_margin = aOther.m_margin;
109 m_text = aOther.m_text;
110 m_kind = aOther.m_kind;
111 m_angle = aOther.m_angle;
113 m_poly = aOther.m_poly;
114 m_symbolPoly = aOther.m_symbolPoly;
115 m_textPoly = aOther.m_textPoly;
116 m_bbox = aOther.m_bbox;
117
118 m_text.SetParent( this );
119 }
120
121 return *this;
122}
123
124
126{
127 VECTOR2I delta = aPos - m_pos;
128 Move( delta );
129}
130
131
133{
134 return m_pos;
135}
136
137
138void PCB_BARCODE::SetText( const wxString& aNewText )
139{
140 m_text.SetText( aNewText );
141}
142
143
144wxString PCB_BARCODE::GetText() const
145{
146 return m_text.GetText();
147}
148
149
151{
152 return m_text.GetShownText( true );
153}
154
155
156void PCB_BARCODE::Serialize( google::protobuf::Any& aContainer ) const
157{
158 using namespace kiapi::board::types;
159
160 Barcode barcode;
161
162 barcode.mutable_id()->set_value( m_Uuid.AsStdString() );
163 barcode.set_text( GetText().ToUTF8() );
164
165 switch( m_kind )
166 {
167 case BARCODE_T::CODE_39: barcode.set_kind( BK_CODE_39 ); break;
168 case BARCODE_T::CODE_128: barcode.set_kind( BK_CODE_128 ); break;
169 case BARCODE_T::DATA_MATRIX: barcode.set_kind( BK_DATA_MATRIX ); break;
170 case BARCODE_T::QR_CODE: barcode.set_kind( BK_QR_CODE ); break;
171 case BARCODE_T::MICRO_QR_CODE: barcode.set_kind( BK_MICRO_QR_CODE ); break;
172 }
173
174 switch( m_errorCorrection )
175 {
176 case BARCODE_ECC_T::L: barcode.set_error_correction( BEC_L ); break;
177 case BARCODE_ECC_T::M: barcode.set_error_correction( BEC_M ); break;
178 case BARCODE_ECC_T::Q: barcode.set_error_correction( BEC_Q ); break;
179 case BARCODE_ECC_T::H: barcode.set_error_correction( BEC_H ); break;
180 }
181
182 kiapi::common::PackVector2( *barcode.mutable_position(), m_pos );
183 barcode.mutable_orientation()->set_value_degrees( m_angle.AsDegrees() );
184 barcode.set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( GetLayer() ) );
185
186 barcode.mutable_width()->set_value_nm( m_width );
187 barcode.mutable_height()->set_value_nm( m_height );
188
189 barcode.set_show_text( m_text.IsVisible() );
190 barcode.mutable_text_height()->set_value_nm( m_text.GetTextHeight() );
191
192 barcode.set_knockout( IsKnockout() );
193 kiapi::common::PackVector2( *barcode.mutable_knockout_margin(), m_margin );
194
195 barcode.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
196 : kiapi::common::types::LockedState::LS_UNLOCKED );
197
198 aContainer.PackFrom( barcode );
199}
200
201
202bool PCB_BARCODE::Deserialize( const google::protobuf::Any& aContainer )
203{
204 using namespace kiapi::board::types;
205
206 Barcode barcode;
207
208 if( !aContainer.UnpackTo( &barcode ) )
209 return false;
210
211 SetUuidDirect( KIID( barcode.id().value() ) );
212 SetText( wxString::FromUTF8( barcode.text() ) );
213
214 switch( barcode.kind() )
215 {
216 case BK_CODE_39: SetKind( BARCODE_T::CODE_39 ); break;
217 case BK_CODE_128: SetKind( BARCODE_T::CODE_128 ); break;
218 case BK_DATA_MATRIX: SetKind( BARCODE_T::DATA_MATRIX ); break;
219 case BK_QR_CODE: SetKind( BARCODE_T::QR_CODE ); break;
220 case BK_MICRO_QR_CODE: SetKind( BARCODE_T::MICRO_QR_CODE ); break;
221 default: SetKind( BARCODE_T::QR_CODE ); break;
222 }
223
224 switch( barcode.error_correction() )
225 {
226 case BEC_L: SetErrorCorrection( BARCODE_ECC_T::L ); break;
227 case BEC_M: SetErrorCorrection( BARCODE_ECC_T::M ); break;
228 case BEC_Q: SetErrorCorrection( BARCODE_ECC_T::Q ); break;
229 case BEC_H: SetErrorCorrection( BARCODE_ECC_T::H ); break;
230 default: SetErrorCorrection( BARCODE_ECC_T::L ); break;
231 }
232
233 m_pos = kiapi::common::UnpackVector2( barcode.position() );
234 m_angle = EDA_ANGLE( barcode.orientation().value_degrees(), DEGREES_T );
236
237 m_width = barcode.width().value_nm();
238 m_height = barcode.height().value_nm();
239
240 m_text.SetLayer( m_layer );
241 m_text.SetVisible( barcode.show_text() );
242
243 if( barcode.has_text_height() )
244 {
245 int textSize = std::max( 1, static_cast<int>( barcode.text_height().value_nm() ) );
246 m_text.SetTextSize( VECTOR2I( textSize, textSize ) );
247 m_text.SetTextThickness( std::max( 1, GetPenSizeForNormal( m_text.GetTextHeight() ) ) );
248 }
249
250 m_margin = kiapi::common::UnpackVector2( barcode.knockout_margin() );
251 BOARD_ITEM::SetIsKnockout( barcode.knockout() );
252 SetLocked( barcode.locked() == kiapi::common::types::LockedState::LS_LOCKED );
253
255
256 return true;
257}
258
259
261{
262 m_layer = aLayer;
263 m_text.SetLayer( aLayer );
264
266}
267
268
269void PCB_BARCODE::SetTextSize( int aTextSize )
270{
271 m_text.SetTextSize( VECTOR2I( std::max( 1, aTextSize ), std::max( 1, aTextSize ) ) );
272 m_text.SetTextThickness( std::max( 1, GetPenSizeForNormal( m_text.GetTextHeight() ) ) );
273
275}
276
277
279{
280 return m_text.GetTextHeight();
281}
282
283
284void PCB_BARCODE::Move( const VECTOR2I& offset )
285{
286 m_pos += offset;
287 m_symbolPoly.Move( offset );
288 m_textPoly.Move( offset );
289 m_poly.Move( offset );
290 m_text.Move( offset );
291 m_bbox.Move( offset );
292}
293
294
295void PCB_BARCODE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
296{
297 RotatePoint( m_pos, aRotCentre, aAngle );
298 m_angle += aAngle;
299
301}
302
303
304void PCB_BARCODE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
305{
306 MIRROR( m_pos, aCentre, aFlipDirection );
307
308 if( aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
310
312
314}
315
316
317void PCB_BARCODE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings, bool aCheckSide )
318{
319 SetTextSize( settings.GetTextSize( GetLayer() ).y );
320}
321
322
324{
326
327 // Scale the symbol polygon to the desired barcode width/height (property values) and center it at m_pos
328 // Note: SetRect will rescale the symbol-only polygon and then rebuild m_poly
329 SetRect( m_pos - VECTOR2I( m_width / 2, m_height / 2 ),
330 m_pos + VECTOR2I( m_width / 2, m_height / 2 ) );
331
333
334 // Build full m_poly from symbol + optional text, then apply knockout if requested
335 m_poly.RemoveAllContours();
336 m_poly.Append( m_symbolPoly );
337
338 if( m_text.IsVisible() && m_textPoly.OutlineCount() )
339 m_poly.Append( m_textPoly );
340
341 m_poly.Fracture();
342
343 if( IsKnockout() )
344 {
345 // Enforce minimum margin: at least 10% of the smallest side of the barcode, rounded up
346 // to the nearest 0.1 mm. Use this as a lower bound for both axes.
347 int minSide = std::min( m_width, m_height );
348 int tenPercent = ( minSide + 9 ) / 10; // ceil(minSide * 0.1)
349 int step01mm = std::max( 1, pcbIUScale.mmToIU( 0.1 ) );
350 int tenPercentRounded = ( ( tenPercent + step01mm - 1 ) / step01mm ) * step01mm;
351
352 // Build inversion rectangle based on the local bbox of the current combined geometry
353 BOX2I bbox = m_poly.BBox();
354 bbox.Inflate( std::max( m_margin.x, tenPercentRounded ), std::max( m_margin.y, tenPercentRounded ) );
355
356 SHAPE_LINE_CHAIN rect;
357 rect.Append( bbox.GetLeft(), bbox.GetTop() );
358 rect.Append( bbox.GetRight(), bbox.GetTop() );
359 rect.Append( bbox.GetRight(), bbox.GetBottom() );
360 rect.Append( bbox.GetLeft(), bbox.GetBottom() );
361 rect.SetClosed( true );
362
364 ko.AddOutline( rect );
366 ko.Fracture();
367 m_poly = std::move( ko );
368 }
369
372
373 if( !m_angle.IsZero() )
374 m_poly.Rotate( m_angle, m_pos );
375
376 m_poly.CacheTriangulation();
377 m_bbox = m_poly.BBox();
378}
379
380
382{
383 m_textPoly.RemoveAllContours();
384
385 if( !m_text.IsVisible() )
386 return;
387
388 SHAPE_POLY_SET textPoly;
389 m_text.TransformTextToPolySet( textPoly, 0, GetMaxError(), ERROR_INSIDE );
390
391 if( textPoly.OutlineCount() == 0 )
392 return;
393
394 if( m_symbolPoly.OutlineCount() == 0 )
395 return;
396
397 BOX2I textBBox = textPoly.BBox();
398 BOX2I symbolBBox = m_symbolPoly.BBox();
399 VECTOR2I textPos;
400 int textOffset = pcbIUScale.mmToIU( 1 );
401 textPos.x = symbolBBox.GetCenter().x - textBBox.GetCenter().x;
402 textPos.y = symbolBBox.GetBottom() - textBBox.GetTop() + textOffset;
403
404 textPoly.Move( textPos );
405
406 m_textPoly = std::move( textPoly );
407 m_textPoly.CacheTriangulation();
408}
409
410
412{
413 m_symbolPoly.RemoveAllContours();
414 m_lastError.clear();
415
416 std::unique_ptr<zint_symbol, decltype( &ZBarcode_Delete )> symbol( ZBarcode_Create(), &ZBarcode_Delete );
417
418 if( !symbol )
419 {
420 wxLogError( wxT( "Zint: failed to allocate symbol" ) );
421 return;
422 }
423
424 symbol->input_mode = UNICODE_MODE;
425 symbol->show_hrt = 0; // do not show HRT
426
427 switch( m_kind )
428 {
430 symbol->symbology = BARCODE_CODE39;
431 break;
433 symbol->symbology = BARCODE_CODE128;
434 break;
436 symbol->symbology = BARCODE_QRCODE;
437 symbol->option_1 = to_underlying( m_errorCorrection );
438 break;
440 symbol->symbology = BARCODE_MICROQR;
441 symbol->option_1 = to_underlying( m_errorCorrection );
442 break;
444 symbol->symbology = BARCODE_DATAMATRIX;
445 break;
446 default:
447 wxLogError( wxT( "Zint: invalid barcode type" ) );
448 return;
449 }
450
451 wxString text = GetShownText();
452 wxScopedCharBuffer utf8Text = text.ToUTF8();
453 size_t length = utf8Text.length();
454 unsigned char* dataPtr = reinterpret_cast<unsigned char*>( utf8Text.data() );
455
456 if( text.empty() )
457 return;
458
459 if( ( m_kind == BARCODE_T::QR_CODE || m_kind == BARCODE_T::DATA_MATRIX ) && !text.IsAscii() )
460 {
461 symbol->eci = ECI_UTF8;
462 }
463
464 if( ZBarcode_Encode( symbol.get(), dataPtr, length ) >= ZINT_ERROR )
465 {
466 if( !text.IsAscii() )
467 {
468 m_lastError = _( "This barcode type does not support international "
469 "characters. Use QR Code or Data Matrix instead." );
470 }
471 else
472 {
473 m_lastError = wxString::FromUTF8( symbol->errtxt );
474 }
475 return;
476 }
477
478 if( ZBarcode_Buffer_Vector( symbol.get(), 0 ) >= ZINT_ERROR )
479 {
480 m_lastError = wxString::FromUTF8( symbol->errtxt );
481 return;
482 }
483
484 for( zint_vector_rect* rect = symbol->vector->rectangles; rect != nullptr; rect = rect->next )
485 {
486 // Round using absolute edges to avoid cumulative rounding drift across modules.
487 int x1 = KiROUND( rect->x * symbol->scale );
488 int x2 = KiROUND( ( rect->x + rect->width ) * symbol->scale );
489 int y1 = KiROUND( rect->y * symbol->scale );
490 int y2 = KiROUND( ( rect->y + rect->height ) * symbol->scale );
491
492 SHAPE_LINE_CHAIN shapeline;
493 shapeline.Append( x1, y1 );
494 shapeline.Append( x2, y1 );
495 shapeline.Append( x2, y2 );
496 shapeline.Append( x1, y2 );
497 shapeline.SetClosed( true );
498
499 m_symbolPoly.AddOutline( shapeline );
500 }
501
502 for( zint_vector_hexagon* hex = symbol->vector->hexagons; hex != nullptr; hex = hex->next )
503 {
504 // Compute vertices from center using minimal-diameter (inscribed circle) radius.
505 double r = hex->diameter / 2.0; // minimal radius
506 double cx = hex->x;
507 double cy = hex->y;
508
509 // Base orientation has apex at top; hex->rotation rotates by 0/90/180/270 degrees.
510 double baseAngles[6] = { 90.0, 30.0, -30.0, -90.0, -150.0, 150.0 };
511 double rot = static_cast<double>( hex->rotation );
512
513 SHAPE_LINE_CHAIN poly;
514
515 for( int k = 0; k < 6; ++k )
516 {
517 double ang = ( baseAngles[k] + rot ) * M_PI / 180.0;
518 int vx = KiROUND( cx + r * cos( ang ) );
519 int vy = KiROUND( cy + r * sin( ang ) );
520 poly.Append( vx, vy );
521 }
522 poly.SetClosed( true );
523
524 m_symbolPoly.AddOutline( poly );
525 }
526
527 // Set the position of the barcode to the center of the symbol polygon
528 if( m_symbolPoly.OutlineCount() > 0 )
529 {
530 VECTOR2I pos = m_symbolPoly.BBox().GetCenter();
531 m_symbolPoly.Move( -pos );
532 }
533
534 m_symbolPoly.CacheTriangulation();
535}
536
537
538void PCB_BARCODE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
539{
540 FOOTPRINT* parentFP = GetParentFootprint();
541
542 if( parentFP && aFrame->GetName() == PCB_EDIT_FRAME_NAME )
543 aList.emplace_back( _( "Footprint" ), parentFP->GetReference() );
544
545 aList.emplace_back( _( "Barcode" ), ENUM_MAP<BARCODE_T>::Instance().ToString( m_kind ) );
546
547 // Don't use GetShownText() here; we want to show the user the variable references
548 aList.emplace_back( _( "Text" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
549
550 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
551 aList.emplace_back( _( "Status" ), _( "Locked" ) );
552
553 aList.emplace_back( _( "Layer" ), GetLayerName() );
554
555 aList.emplace_back( _( "Angle" ), wxString::Format( wxT( "%g" ), m_angle.AsDegrees() ) );
556
557 aList.emplace_back( _( "Text Height" ), aFrame->MessageTextFromValue( m_text.GetTextHeight() ) );
558}
559
560
561bool PCB_BARCODE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
562{
563 if( !GetBoundingBox().Contains( aPosition ) )
564 return false;
565
566 SHAPE_POLY_SET hulls;
567
569
570 return hulls.Collide( aPosition );
571}
572
573
574bool PCB_BARCODE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
575{
576 BOX2I arect = aRect;
577 arect.Inflate( aAccuracy );
578
579 BOX2I rect = GetBoundingBox();
580
581 if( aAccuracy )
582 rect.Inflate( aAccuracy );
583
584 if( aContained )
585 return arect.Contains( rect );
586
587 return arect.Intersects( rect );
588}
589
590
591void PCB_BARCODE::SetRect( const VECTOR2I& aTopLeft, const VECTOR2I& aBotRight )
592{
593 // Rescale only the symbol polygon to the requested rectangle; text is rebuilt below
594 BOX2I bbox = m_symbolPoly.BBox();
595 int oldW = bbox.GetWidth();
596 int oldH = bbox.GetHeight();
597
598 VECTOR2I newPosition = ( aTopLeft + aBotRight ) / 2;
599 SetPosition( newPosition );
600 int newW = aBotRight.x - aTopLeft.x;
601 int newH = aBotRight.y - aTopLeft.y;
602 // Guard against zero/negative sizes from interactive edits; enforce a tiny minimum
603 int minIU = std::max( 1, pcbIUScale.mmToIU( 0.01 ) );
604 newW = std::max( newW, minIU );
605 newH = std::max( newH, minIU );
606
607 double scaleX = oldW ? static_cast<double>( newW ) / oldW : 1.0;
608 double scaleY = oldH ? static_cast<double>( newH ) / oldH : 1.0;
609
610 VECTOR2I oldCenter = bbox.GetCenter();
611 m_symbolPoly.Scale( scaleX, scaleY, oldCenter );
612
613 // After scaling, move the symbol polygon to be centered at the new position
614 VECTOR2I newCenter = m_symbolPoly.BBox().GetCenter();
615 VECTOR2I delta = newPosition - newCenter;
616
617 if( delta != VECTOR2I( 0, 0 ) )
618 m_symbolPoly.Move( delta );
619
620 // Update intended barcode symbol size (without text/margins)
621 m_width = newW;
622 m_height = newH;
623}
624
625
627{
628 return m_bbox;
629}
630
631
632wxString PCB_BARCODE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
633{
634 return wxString::Format( _( "Barcode '%s' on %s" ), GetText(), GetLayerName() );
635}
636
637
642
643
645{
646 return m_bbox;
647}
648
649
651 int aClearance, int aMaxError,
652 ERROR_LOC aErrorLoc, bool ignoreLineWidth ) const
653{
654 if( aLayer != m_layer && aLayer != UNDEFINED_LAYER )
655 return;
656
657 if( aClearance == 0 )
658 {
659 aBuffer.Append( m_poly );
660 }
661 else
662 {
663 SHAPE_POLY_SET poly = m_poly;
664 poly.Inflate( aClearance, CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS, aMaxError, aErrorLoc );
665 aBuffer.Append( poly );
666 }
667}
668
669
670std::shared_ptr<SHAPE> PCB_BARCODE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
671{
672 SHAPE_POLY_SET poly;
673 TransformShapeToPolygon( poly, aLayer, 0, 0, ERROR_INSIDE, true );
674
675 return std::make_shared<SHAPE_POLY_SET>( std::move( poly ) );
676}
677
678
679void PCB_BARCODE::GetBoundingHull( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
680 int aMaxError, ERROR_LOC aErrorLoc ) const
681{
682 auto getBoundingHull =
683 [this]( SHAPE_POLY_SET& aLocBuffer, const SHAPE_POLY_SET& aSource, int aLocClearance )
684 {
685 BOX2I rect = aSource.BBox( aLocClearance );
686 VECTOR2I corners[4];
687
688 corners[0].x = rect.GetOrigin().x;
689 corners[0].y = rect.GetOrigin().y;
690 corners[1].y = corners[0].y;
691 corners[1].x = rect.GetRight();
692 corners[2].x = corners[1].x;
693 corners[2].y = rect.GetBottom();
694 corners[3].y = corners[2].y;
695 corners[3].x = corners[0].x;
696
697 aLocBuffer.NewOutline();
698
699 for( VECTOR2I& corner : corners )
700 {
701 RotatePoint( corner, m_pos, m_angle );
702 aLocBuffer.Append( corner.x, corner.y );
703 }
704 };
705
706 if( aLayer == m_layer || aLayer == UNDEFINED_LAYER )
707 {
708 getBoundingHull( aBuffer, m_symbolPoly, aClearance );
709 getBoundingHull( aBuffer, m_textPoly, aClearance );
710 }
711}
712
713
715{
716 // Micro QR codes do not support High (H) error correction level
717 if( m_kind == BARCODE_T::MICRO_QR_CODE && aErrorCorrection == BARCODE_ECC_T::H )
719 else
720 m_errorCorrection = aErrorCorrection;
721 // Don't auto-compute here as it may be called during loading
722}
723
724
726{
727 m_kind = aKind;
728
729 // When switching to Micro QR, validate and adjust ECC if needed
732
733 // Don't auto-compute here as it may be called during loading
734}
735
736
738{
739 SetErrorCorrection( aErrorCorrection );
741}
742
743
745{
746 m_width = aWidth;
747
748 if( KeepSquare() )
749 m_height = aWidth;
750
752}
753
754
756{
757 m_height = aHeight;
758
759 if( KeepSquare() )
760 m_width = aHeight;
761
763}
764
765
767{
768 SetKind( aKind );
770}
771
772
774{
775 PCB_BARCODE* item = new PCB_BARCODE( *this );
776 item->CopyFrom( this );
777 return item;
778}
779
780
782{
783 wxCHECK_RET( aImage && aImage->Type() == PCB_BARCODE_T,
784 wxT( "Cannot swap data with non-barcode item." ) );
785
786 PCB_BARCODE* other = static_cast<PCB_BARCODE*>( aImage );
787
788 std::swap( *this, *other );
789
790 m_text.SetParent( this );
791 other->m_text.SetParent( other );
792}
793
794double PCB_BARCODE::Similarity( const BOARD_ITEM& aItem ) const
795{
796 if( !ClassOf( &aItem ) )
797 return 0.0;
798
799 const PCB_BARCODE* other = static_cast<const PCB_BARCODE*>( &aItem );
800
801 // Compare text, width, height, text height, position, and kind
802 double similarity = 0.0;
803 const double weight = 1.0 / 6.0;
804
805 if( GetText() == other->GetText() )
806 similarity += weight;
807 if( m_width == other->m_width )
808 similarity += weight;
809 if( m_height == other->m_height )
810 similarity += weight;
811 if( GetTextSize() == other->GetTextSize() )
812 similarity += weight;
813 if( GetPosition() == other->GetPosition() )
814 similarity += weight;
815 if( m_kind == other->m_kind )
816 similarity += weight;
817
818 return similarity;
819}
820
821int PCB_BARCODE::Compare( const PCB_BARCODE* aBarcode, const PCB_BARCODE* aOther )
822{
823 int diff;
824
825 if( ( diff = aBarcode->GetPosition().x - aOther->GetPosition().x ) != 0 )
826 return diff;
827
828 if( ( diff = aBarcode->GetPosition().y - aOther->GetPosition().y ) != 0 )
829 return diff;
830
831 if( ( diff = aBarcode->GetText().Cmp( aOther->GetText() ) ) != 0 )
832 return diff;
833
834 if( ( diff = aBarcode->GetWidth() - aOther->GetWidth() ) != 0 )
835 return diff;
836
837 if( ( diff = aBarcode->GetHeight() - aOther->GetHeight() ) != 0 )
838 return diff;
839
840 if( ( diff = aBarcode->GetTextSize() - aOther->GetTextSize() ) != 0 )
841 return diff;
842
843 if( ( diff = (int) aBarcode->GetKind() - (int) aOther->GetKind() ) != 0 )
844 return diff;
845
846 if( ( diff = aBarcode->m_angle.AsTenthsOfADegree() - aOther->m_angle.AsTenthsOfADegree() ) != 0 )
847 return diff;
848
849 if( ( diff = (int) aBarcode->GetErrorCorrection() - (int) aOther->GetErrorCorrection() ) != 0 )
850 return diff;
851
852 return 0;
853}
854
855
856bool PCB_BARCODE::operator==( const BOARD_ITEM& aItem ) const
857{
858 if( !ClassOf( &aItem ) )
859 return false;
860
861 const PCB_BARCODE& other = static_cast<const PCB_BARCODE&>( aItem );
862
863 return *this == other;
864}
865
866
867bool PCB_BARCODE::operator==( const PCB_BARCODE& aOther ) const
868{
869 // Compare text, width, height, text height, position, and kind
870 return ( GetText() == aOther.GetText()
871 && m_width == aOther.m_width
872 && m_height == aOther.m_height
873 && GetTextSize() == aOther.GetTextSize()
874 && GetPosition() == aOther.GetPosition()
875 && m_kind == aOther.m_kind );
876}
877
878// ---- Property registration ----
879static struct PCB_BARCODE_DESC
880{
882 {
886
887 const wxString groupBarcode = _HKI( "Barcode Properties" );
888
890 if( kindMap.Choices().GetCount() == 0 )
891 {
892 kindMap.Undefined( BARCODE_T::QR_CODE );
893 kindMap.Map( BARCODE_T::CODE_39, _HKI( "CODE_39" ) )
894 .Map( BARCODE_T::CODE_128, _HKI( "CODE_128" ) )
895 .Map( BARCODE_T::DATA_MATRIX, _HKI( "DATA_MATRIX" ) )
896 .Map( BARCODE_T::QR_CODE, _HKI( "QR_CODE" ) )
897 .Map( BARCODE_T::MICRO_QR_CODE, _HKI( "MICRO_QR_CODE" ) );
898 }
899
901 if( eccMap.Choices().GetCount() == 0 )
902 {
903 eccMap.Undefined( BARCODE_ECC_T::L );
904 eccMap.Map( BARCODE_ECC_T::L, _HKI( "L (Low)" ) )
905 .Map( BARCODE_ECC_T::M, _HKI( "M (Medium)" ) )
906 .Map( BARCODE_ECC_T::Q, _HKI( "Q (Quartile)" ) )
907 .Map( BARCODE_ECC_T::H, _HKI( "H (High)" ) );
908 }
909
910 auto hasKnockout =
911 []( INSPECTABLE* aItem ) -> bool
912 {
913 if( PCB_BARCODE* bc = dynamic_cast<PCB_BARCODE*>( aItem ) )
914 return bc->IsKnockout();
915 return false;
916 };
917
918 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, wxString>( _HKI( "Text" ),
920
921 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, bool>( _HKI( "Show Text" ),
923
924 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Text Size" ),
926 PROPERTY_DISPLAY::PT_COORD ), groupBarcode );
927
928 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Width" ),
930 PROPERTY_DISPLAY::PT_COORD ), groupBarcode );
931
932 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Height" ),
934 PROPERTY_DISPLAY::PT_COORD ), groupBarcode );
935
936 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, double>( _HKI( "Orientation" ),
938
939 propMgr.AddProperty( new PROPERTY_ENUM<PCB_BARCODE, BARCODE_T>( _HKI( "Barcode Type" ),
941
942 auto isQRCode =
943 []( INSPECTABLE* aItem ) -> bool
944 {
945 if( PCB_BARCODE* bc = dynamic_cast<PCB_BARCODE*>( aItem ) )
946 return bc->GetKind() == BARCODE_T::QR_CODE || bc->GetKind() == BARCODE_T::MICRO_QR_CODE;
947
948 return false;
949 };
950
951 propMgr.AddProperty( new PROPERTY_ENUM<PCB_BARCODE, BARCODE_ECC_T>( _HKI( "Error Correction" ),
953 groupBarcode )
954 .SetAvailableFunc( isQRCode )
955 .SetChoicesFunc( []( INSPECTABLE* aItem )
956 {
957 PCB_BARCODE* barcode = static_cast<PCB_BARCODE*>( aItem );
958 wxPGChoices choices;
959
960 choices.Add( _( "L (Low)" ), static_cast<int>( BARCODE_ECC_T::L ) );
961 choices.Add( _( "M (Medium)" ), static_cast<int>( BARCODE_ECC_T::M ) );
962 choices.Add( _( "Q (Quartile)" ), static_cast<int>( BARCODE_ECC_T::Q ) );
963
964 // Only QR_CODE has High
965 if( barcode->GetKind() == BARCODE_T::QR_CODE )
966 choices.Add( _( "H (High)" ), static_cast<int>( BARCODE_ECC_T::H ) );
967
968 return choices;
969 } );
970
971 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, bool>( _HKI( "Knockout" ),
973
974 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Margin X" ),
976 PROPERTY_DISPLAY::PT_COORD ), groupBarcode ).SetAvailableFunc( hasKnockout );
977
978 propMgr.AddProperty( new PROPERTY<PCB_BARCODE, int>( _HKI( "Margin Y" ),
980 PROPERTY_DISPLAY::PT_COORD ), groupBarcode ).SetAvailableFunc( hasKnockout );
981 }
983
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:41
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:127
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:268
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:359
PCB_LAYER_ID m_layer
Definition board_item.h:490
bool IsLocked() const override
virtual void SetIsKnockout(bool aKnockout)
Definition board_item.h:356
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)
BOARD_ITEM & operator=(const BOARD_ITEM &aOther)
Definition board_item.h:103
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.
const KIID m_Uuid
Definition eda_item.h:528
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
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:771
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:38
Definition kiid.h:48
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.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
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:95
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 Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
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)
@ DEGREES_T
Definition eda_angle.h:31
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:173
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:805
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.
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput)
Definition api_utils.cpp:86
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput)
Definition api_utils.cpp:79
#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:98
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687