KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_dimension.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) 2012 Jean-Pierre Charras, [email protected]
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2012 Wayne Stambaugh <[email protected]>
7 * Copyright (C) 2023 CERN
8 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24#include <bitmaps.h>
25#include <pcb_edit_frame.h>
26#include <base_units.h>
28#include <font/font.h>
29#include <board.h>
30#include <footprint.h>
31#include <pcb_dimension.h>
32#include <pcb_painter.h>
33#include <pcb_text.h>
34#include <view/view.h>
39#include <geometry/shape_rect.h>
43#include <trigo.h>
44#include <api/api_enums.h>
45#include <api/api_utils.h>
46#include <api/board/board_types.pb.h>
47#include <properties/property.h>
50
53
54
56
57static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
58
59
68static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
69 bool aStart = true )
70{
71 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
72 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
73
74 if( aPoly.Contains( start ) )
75 return std::nullopt;
76
77 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
78 {
79 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
80 {
81 if( ( *intersection - start ).SquaredEuclideanNorm()
82 < ( endpoint - start ).SquaredEuclideanNorm() )
83 endpoint = *intersection;
84 }
85 }
86
87 if( start == endpoint )
88 return std::nullopt;
89
90 return OPT_VECTOR2I( endpoint );
91}
92
93
94static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true )
95{
96 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
97 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
98
99 if( aCircle.Contains( start ) )
100 return std::nullopt;
101
102 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
103
104 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
105 {
106 if( ( intersection - start ).SquaredEuclideanNorm()
107 < ( endpoint - start ).SquaredEuclideanNorm() )
108 endpoint = intersection;
109 }
110
111 if( start == endpoint )
112 return std::nullopt;
113
114 return OPT_VECTOR2I( endpoint );
115}
116
117
122static void CollectKnockedOutSegments( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
123 std::vector<std::shared_ptr<SHAPE>>& aSegmentsAfterKnockout )
124{
125 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
126 const bool containsA = aPoly.Contains( aSeg.A );
127 const bool containsB = aPoly.Contains( aSeg.B );
128
129 const OPT_VECTOR2I endpointA = segPolyIntersection( aPoly, aSeg );
130 const OPT_VECTOR2I endpointB = segPolyIntersection( aPoly, aSeg, false );
131
132 if( endpointA )
133 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg.A, *endpointA ) );
134
135 if( endpointB )
136 {
137 bool can_add = true;
138
139 if( endpointA )
140 {
141 if( ( *endpointB == aSeg.A && *endpointA == aSeg.B )
142 || ( *endpointA == *endpointB && aSeg.A == aSeg.B ) )
143 can_add = false;
144 }
145
146 if( can_add )
147 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( *endpointB, aSeg.B ) );
148 }
149
150 if( !containsA && !containsB && !endpointA && !endpointB )
151 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg ) );
152}
153
154
156 PCB_TEXT( aParent, aType ),
157 m_overrideTextEnabled( false ),
159 m_autoUnits( false ),
163 m_suppressZeroes( false ),
164 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
165 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
168 m_keepTextAligned( true ),
169 m_measuredValue( 0 ),
170 m_start( 0, 0 ),
171 m_end( 0, 0 ),
172 m_inClearRenderCache( false )
173{
175 m_busy = false;
176}
177
178
180{
181 if( const FOOTPRINT* fp = GetParentFootprint() )
182 return fp->GetTransform().Apply( m_start );
183
184 return m_start;
185}
186
187
189{
190 if( const FOOTPRINT* fp = GetParentFootprint() )
191 return fp->GetTransform().Apply( m_end );
192
193 return m_end;
194}
195
196
198{
199 if( const FOOTPRINT* fp = GetParentFootprint() )
200 m_start = fp->GetTransform().InverseApply( aPoint );
201 else
202 m_start = aPoint;
203}
204
205
207{
208 if( const FOOTPRINT* fp = GetParentFootprint() )
209 m_end = fp->GetTransform().InverseApply( aPoint );
210 else
211 m_end = aPoint;
212}
213
214
215void PCB_DIMENSION_BASE::OnFootprintRescaled( double /* aRatioX */, double /* aRatioY */, double /* aLinearFactor */,
216 const VECTOR2I& /* aAnchor */, const EDA_ANGLE& /* aParentRotate */ )
217{
220}
221
222
230
231
233{
234 if( Type() != aOther.Type() )
235 return false;
236
237 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
238
239 return *this == other;
240}
241
242
244{
245 if( m_textPosition != aOther.m_textPosition )
246 return false;
247
249 return false;
250
251 if( m_units != aOther.m_units )
252 return false;
253
254 if( m_autoUnits != aOther.m_autoUnits )
255 return false;
256
257 if( m_unitsFormat != aOther.m_unitsFormat )
258 return false;
259
260 if( m_precision != aOther.m_precision )
261 return false;
262
263 if( m_suppressZeroes != aOther.m_suppressZeroes )
264 return false;
265
266 if( m_lineThickness != aOther.m_lineThickness )
267 return false;
268
269 if( m_arrowLength != aOther.m_arrowLength )
270 return false;
271
273 return false;
274
275 if( m_measuredValue != aOther.m_measuredValue )
276 return false;
277
278 return EDA_TEXT::operator==( aOther );
279}
280
281
282double PCB_DIMENSION_BASE::Similarity( const BOARD_ITEM& aOther ) const
283{
284 if( m_Uuid == aOther.m_Uuid )
285 return 1.0;
286
287 if( Type() != aOther.Type() )
288 return 0.0;
289
290 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
291
292 double similarity = 1.0;
293
294 if( m_textPosition != other.m_textPosition )
295 similarity *= 0.9;
296
298 similarity *= 0.9;
299
300 if( m_units != other.m_units )
301 similarity *= 0.9;
302
303 if( m_autoUnits != other.m_autoUnits )
304 similarity *= 0.9;
305
306 if( m_unitsFormat != other.m_unitsFormat )
307 similarity *= 0.9;
308
309 if( m_precision != other.m_precision )
310 similarity *= 0.9;
311
313 similarity *= 0.9;
314
315 if( m_lineThickness != other.m_lineThickness )
316 similarity *= 0.9;
317
318 if( m_arrowLength != other.m_arrowLength )
319 similarity *= 0.9;
320
322 similarity *= 0.9;
323
324 if( m_measuredValue != other.m_measuredValue )
325 similarity *= 0.9;
326
327 similarity *= EDA_TEXT::Similarity( other );
328
329 return similarity;
330}
331
332
333void PCB_DIMENSION_BASE::Serialize( google::protobuf::Any &aContainer ) const
334{
335 using namespace kiapi::common;
336 using namespace kiapi::board::types;
337 Dimension dimension;
338
339 dimension.mutable_id()->set_value( m_Uuid.AsStdString() );
340 dimension.set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( GetLayer() ) );
341 dimension.set_locked( IsLocked() ? types::LockedState::LS_LOCKED
342 : types::LockedState::LS_UNLOCKED );
343
344 google::protobuf::Any any;
346 any.UnpackTo( dimension.mutable_text() );
347
348 types::Text* text = dimension.mutable_text();
349 text->set_text( GetValueText() );
350
351 dimension.set_override_text_enabled( m_overrideTextEnabled );
352 dimension.set_override_text( m_valueString.ToUTF8() );
353 dimension.set_prefix( m_prefix.ToUTF8() );
354 dimension.set_suffix( m_suffix.ToUTF8() );
355
357 dimension.set_unit_format(
359 dimension.set_arrow_direction(
362 dimension.set_suppress_trailing_zeroes( m_suppressZeroes );
363
364 dimension.mutable_line_thickness()->set_value_nm( m_lineThickness );
365 dimension.mutable_arrow_length()->set_value_nm( m_arrowLength );
366 dimension.mutable_extension_offset()->set_value_nm( m_extensionOffset );
367 dimension.set_text_position(
369 dimension.set_keep_text_aligned( m_keepTextAligned );
370
371 aContainer.PackFrom( dimension );
372}
373
374
375bool PCB_DIMENSION_BASE::Deserialize( const google::protobuf::Any &aContainer )
376{
377 using namespace kiapi::common;
378 kiapi::board::types::Dimension dimension;
379
380 if( !aContainer.UnpackTo( &dimension ) )
381 return false;
382
384 SetUuidDirect( KIID( dimension.id().value() ) );
385 SetLocked( dimension.locked() == types::LockedState::LS_LOCKED );
386
387 google::protobuf::Any any;
388 any.PackFrom( dimension.text() );
390
391 SetOverrideTextEnabled( dimension.override_text_enabled() );
392 SetOverrideText( wxString::FromUTF8( dimension.override_text() ) );
393 SetPrefix( wxString::FromUTF8( dimension.prefix() ) );
394 SetSuffix( wxString::FromUTF8( dimension.suffix() ) );
395
396 SetUnitsMode( FromProtoEnum<DIM_UNITS_MODE>( dimension.unit() ) );
397 SetUnitsFormat( FromProtoEnum<DIM_UNITS_FORMAT>( dimension.unit_format() ) );
398 SetArrowDirection( FromProtoEnum<DIM_ARROW_DIRECTION>( dimension.arrow_direction() ) );
399 SetPrecision( FromProtoEnum<DIM_PRECISION>( dimension.precision() ) );
400 SetSuppressZeroes( dimension.suppress_trailing_zeroes() );
401
402 SetLineThickness( dimension.line_thickness().value_nm() );
403 SetArrowLength( dimension.arrow_length().value_nm() );
404 SetExtensionOffset( dimension.extension_offset().value_nm() );
405 SetTextPositionMode( FromProtoEnum<DIM_TEXT_POSITION>( dimension.text_position() ) );
406 SetKeepTextAligned( dimension.keep_text_aligned() );
407
408 Update();
409
410 return true;
411}
412
413
414void PCB_DIMENSION_BASE::drawAnArrow( VECTOR2I startPoint, EDA_ANGLE anAngle, int aLength )
415{
416 if( aLength )
417 {
418 VECTOR2I tailEnd( aLength, 0 );
419 RotatePoint( tailEnd, -anAngle );
420 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + tailEnd ) );
421 }
422
423 VECTOR2I arrowEndPos( m_arrowLength, 0 );
424 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
425
426 RotatePoint( arrowEndPos, -anAngle + s_arrowAngle );
427 RotatePoint( arrowEndNeg, -anAngle - s_arrowAngle );
428
429 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndPos ) );
430 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndNeg ) );
431}
432
433
435{
437
438 switch( m_unitsFormat )
439 {
440 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
441 break;
442
443 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
445 break;
446
447 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
448 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
449 break;
450 }
451
452 text.Prepend( m_prefix );
453 text.Append( m_suffix );
454
455 SetText( text );
456}
457
458
460{
462
463 // We use EDA_TEXT::ClearRenderCache() as a signal that the properties of the EDA_TEXT
464 // have changed and we may need to update the dimension text
465
467 {
469 Update();
470 m_inClearRenderCache = false;
471 }
472}
473
474
475template<typename ShapeType>
476void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
477{
478 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
479}
480
481
483{
484 struct lconv* lc = localeconv();
485 wxChar sep = lc->decimal_point[0];
486
487 int val = GetMeasuredValue();
488 int precision = static_cast<int>( m_precision );
489 wxString text;
490
491 if( precision >= 6 )
492 {
493 switch( m_units )
494 {
495 case EDA_UNITS::INCH: precision = precision - 4; break;
496 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
497 case EDA_UNITS::MM: precision = precision - 5; break;
498 default: precision = precision - 4; break;
499 }
500 }
501
502 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
503
504 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
505
506 if( m_suppressZeroes )
507 {
508 while( text.EndsWith( '0' ) )
509 {
510 text.RemoveLast();
511
512 if( text.EndsWith( '.' ) || text.EndsWith( sep ) )
513 {
514 text.RemoveLast();
515 break;
516 }
517 }
518 }
519
520 return text;
521}
522
523
525{
526 // Read only here but shared lookup helpers require a mutable board pointer
527 BOARD* board = const_cast<BOARD*>( GetBoard() );
528
529 return DimensionValueMode( board, this );
530}
531
532
538
539
541{
542 switch( GetValueMode() )
543 {
545 {
546 PCB_CONSTRAINT* lengthConstraint =
547 FindDimensionLengthConstraint( const_cast<BOARD*>( GetBoard() ), this );
548
549 if( lengthConstraint && lengthConstraint->GetValue() )
550 {
552 *lengthConstraint->GetValue() );
553 }
554
555 return GetValueText();
556 }
557
559 return GetOverrideText();
560
562 default:
563 return GetValueText();
564 }
565}
566
567
568void PCB_DIMENSION_BASE::ChangeValueFieldText( const wxString& aText )
569{
571 {
572 SetOverrideText( aText );
573 Update();
574 }
575}
576
577
578void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
579{
580 m_prefix = aPrefix;
581}
582
583
584void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
585{
586 m_suffix = aSuffix;
587}
588
589
591{
592 m_units = aUnits;
593}
594
595
597{
598 if( m_autoUnits )
599 {
601 }
602 else
603 {
604 switch( m_units )
605 {
606 default:
610 }
611 }
612}
613
614
616{
617 switch( aMode )
618 {
620 m_autoUnits = false;
622 break;
623
625 m_autoUnits = false;
627 break;
628
630 m_autoUnits = false;
632 break;
633
635 m_autoUnits = true;
637 break;
638 }
639}
640
641
643{
644 SetTextAngleDegrees( aDegrees );
645 // Create or repair any knockouts
646 Update();
647}
648
649
651{
652 SetKeepTextAligned( aKeepAligned );
653 // Re-align the text and repair any knockouts
654 Update();
655}
656
657
659{
660 PCB_TEXT::Offset( offset );
661
662 if( const FOOTPRINT* fp = GetParentFootprint() )
663 {
664 const TRANSFORM_TRS& xform = fp->GetTransform();
665 VECTOR2I libOffset = xform.InverseApply( offset ) - xform.InverseApply( VECTOR2I( 0, 0 ) );
666 m_start += libOffset;
667 m_end += libOffset;
668 }
669 else
670 {
671 m_start += offset;
672 m_end += offset;
673 }
674
675 Update();
676}
677
678
679void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
680{
681 EDA_ANGLE newAngle = GetTextAngle() + aAngle;
682 newAngle.Normalize();
683 SetTextAngle( newAngle );
684
685 VECTOR2I pt = GetTextPos();
686 RotatePoint( pt, aRotCentre, aAngle );
687 SetTextPos( pt );
688
689 VECTOR2I boardStart = GetStart();
690 VECTOR2I boardEnd = GetEnd();
691 RotatePoint( boardStart, aRotCentre, aAngle );
692 RotatePoint( boardEnd, aRotCentre, aAngle );
693
694 if( const FOOTPRINT* fp = GetParentFootprint() )
695 {
696 m_start = fp->GetTransform().InverseApply( boardStart );
697 m_end = fp->GetTransform().InverseApply( boardEnd );
698 }
699 else
700 {
701 m_start = boardStart;
702 m_end = boardEnd;
703 }
704
705 Update();
706}
707
708
709void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
710{
711 Mirror( aCentre, aFlipDirection );
712
714}
715
716
717void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
718{
719 if( const FOOTPRINT* fp = GetParentFootprint() )
720 {
721 const VECTOR2I libAxis = fp->GetTransform().InverseApply( axis_pos );
722
723 auto mirrorPt = [&]( VECTOR2I& p )
724 {
725 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
726 p.x = 2 * libAxis.x - p.x;
727 else
728 p.y = 2 * libAxis.y - p.y;
729 };
730
731 mirrorPt( m_start );
732 mirrorPt( m_end );
733
734 VECTOR2I libTextPos = EDA_TEXT::GetTextPos();
735 mirrorPt( libTextPos );
736 EDA_TEXT::SetTextPos( libTextPos );
737
738 EDA_ANGLE newLibAngle =
740 SetLibTextAngle( newLibAngle );
741
742 if( IsSideSpecific() )
744
746 Update();
747 return;
748 }
749
750 VECTOR2I newPos = GetTextPos();
751
752 MIRROR( newPos, axis_pos, aFlipDirection );
753
754 SetTextPos( newPos );
755
756 // invert angle
758
759 MIRROR( m_start, axis_pos, aFlipDirection );
760 MIRROR( m_end, axis_pos, aFlipDirection );
761
762 if( IsSideSpecific() )
764
765 Update();
766}
767
768
769void PCB_DIMENSION_BASE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings, bool aCheckSide )
770{
771 PCB_TEXT::StyleFromSettings( settings, aCheckSide );
772
780
781 Update(); // refresh text & geometry
782
783}
784
785
787 std::vector<MSG_PANEL_ITEM>& aList )
788{
789 // for now, display only the text within the DIMENSION using class PCB_TEXT.
790 wxString msg;
791
792 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
793
794 // Don't use GetShownText(); we want to see the variable references here
795 aList.emplace_back( _( "Dimension" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
796
797 aList.emplace_back( _( "Prefix" ), GetPrefix() );
798
800 {
801 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
802 }
803 else
804 {
805 aList.emplace_back( _( "Value" ), GetValueText() );
806
807 switch( GetPrecision() )
808 {
809 case DIM_PRECISION::V_VV: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
810 case DIM_PRECISION::V_VVV: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
811 case DIM_PRECISION::V_VVVV: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
812 case DIM_PRECISION::V_VVVVV: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
813 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
814 }
815
816 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
817 }
818
819 aList.emplace_back( _( "Suffix" ), GetSuffix() );
820
821 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
822 // in frame's units.
823 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
824 unitsProvider.SetUserUnits( GetUnits() );
825
826 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
827
828 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
829 aList.emplace_back( _( "Text Thickness" ), unitsProvider.MessageTextFromValue( GetTextThickness() ) );
830 aList.emplace_back( _( "Text Width" ), unitsProvider.MessageTextFromValue( GetTextWidth() ) );
831 aList.emplace_back( _( "Text Height" ), unitsProvider.MessageTextFromValue( GetTextHeight() ) );
832
833 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
834
835 if( Type() == PCB_DIM_CENTER_T )
836 {
837 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
838 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
839 aFrame->MessageTextFromValue( startCoord.x ),
840 aFrame->MessageTextFromValue( startCoord.y ) );
841
842 aList.emplace_back( start, wxEmptyString );
843 }
844 else
845 {
846 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
847 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
848 aFrame->MessageTextFromValue( startCoord.x ),
849 aFrame->MessageTextFromValue( startCoord.y ) );
850 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
851 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
852 aFrame->MessageTextFromValue( endCoord.x ),
853 aFrame->MessageTextFromValue( endCoord.y ) );
854
855 aList.emplace_back( start, end );
856 }
857
858 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
859 aList.emplace_back( _( "Status" ), _( "Locked" ) );
860
861 aList.emplace_back( _( "Layer" ), GetLayerName() );
862}
863
864
865std::shared_ptr<SHAPE> PCB_DIMENSION_BASE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
866{
867 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
868
869 effectiveShape->AddShape( GetEffectiveTextShape()->Clone() );
870
871 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
872 effectiveShape->AddShape( shape->Clone() );
873
874 return effectiveShape;
875}
876
877
878bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
879{
880 if( TextHitTest( aPosition ) )
881 return true;
882
883 int dist_max = aAccuracy + ( m_lineThickness / 2 );
884
885 // Locate SEGMENTS
886
887 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
888 {
889 if( shape->Collide( aPosition, dist_max ) )
890 return true;
891 }
892
893 return false;
894}
895
896
897bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
898{
899 BOX2I arect = aRect;
900 arect.Inflate( aAccuracy );
901
902 BOX2I rect = GetBoundingBox();
903
904 if( aAccuracy )
905 rect.Inflate( aAccuracy );
906
907 if( aContained )
908 return arect.Contains( rect );
909
910 return arect.Intersects( rect );
911}
912
913
914bool PCB_DIMENSION_BASE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
915{
916 // Note: Can't use GetEffectiveShape() because we want text as BoundingBox, not as graphics.
917 SHAPE_COMPOUND effShape;
918
919 // Add shapes
920 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
921 effShape.AddShape( shape );
922
923 if( aContained )
924 return TextHitTest( aPoly, aContained ) && KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
925 else
926 return TextHitTest( aPoly, aContained ) || KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
927}
928
929
931{
932 BOX2I bBox;
933 int xmin, xmax, ymin, ymax;
934
935 bBox = GetTextBox( nullptr );
936 xmin = bBox.GetX();
937 xmax = bBox.GetRight();
938 ymin = bBox.GetY();
939 ymax = bBox.GetBottom();
940
941 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
942 {
943 BOX2I shapeBox = shape->BBox();
944 shapeBox.Inflate( m_lineThickness / 2 );
945
946 xmin = std::min( xmin, shapeBox.GetOrigin().x );
947 xmax = std::max( xmax, shapeBox.GetEnd().x );
948 ymin = std::min( ymin, shapeBox.GetOrigin().y );
949 ymax = std::max( ymax, shapeBox.GetEnd().y );
950 }
951
952 bBox.SetX( xmin );
953 bBox.SetY( ymin );
954 bBox.SetWidth( xmax - xmin + 1 );
955 bBox.SetHeight( ymax - ymin + 1 );
956
957 bBox.Normalize();
958
959 return bBox;
960}
961
962
963wxString PCB_DIMENSION_BASE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
964{
965 return wxString::Format( _( "Dimension '%s' on %s" ),
966 aFull ? GetShownText( false ) : KIUI::EllipsizeMenuText( GetText() ),
967 GetLayerName() );
968}
969
970
971
973{
975 VECTOR2I( GetBoundingBox().GetSize() ) );
976 dimBBox.Merge( PCB_TEXT::ViewBBox() );
977
978 return dimBBox;
979}
980
981
982std::vector<int> PCB_DIMENSION_BASE::ViewGetLayers() const
983{
984 std::vector<int> layers = PCB_TEXT::ViewGetLayers();
985
986 // Always advertised while ViewGetLOD gates the draw on actual constraint reference
987 layers.push_back( LAYER_CONSTRAINT_SHADOW );
988
989 return layers;
990}
991
992
993double PCB_DIMENSION_BASE::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
994{
995 if( aLayer == LAYER_CONSTRAINT_SHADOW && aView )
996 {
997 KIGFX::PCB_RENDER_SETTINGS& renderSettings =
998 *static_cast<KIGFX::PCB_PAINTER&>( *aView->GetPainter() ).GetSettings();
999
1000 if( !renderSettings.GetConstrainedItems().count( m_Uuid ) )
1001 return LOD_HIDE;
1002
1003 if( !aView->IsLayerVisibleCached( GetLayer() ) )
1004 return LOD_HIDE;
1005
1006 if( renderSettings.GetHighContrast() && GetLayer() != renderSettings.GetPrimaryHighContrastLayer() )
1007 return LOD_HIDE;
1008
1009 return LOD_SHOW;
1010 }
1011
1012 return PCB_TEXT::ViewGetLOD( aLayer, aView );
1013}
1014
1015
1017 int aClearance, int aError, ERROR_LOC aErrorLoc,
1018 bool aIgnoreLineWidth ) const
1019{
1020 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
1021
1022 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
1023 {
1024 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
1025 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
1026
1027 if( circle )
1028 {
1029 TransformCircleToPolygon( aBuffer, circle->GetCenter(),
1030 circle->GetRadius() + m_lineThickness / 2 + aClearance,
1031 aError, aErrorLoc );
1032 }
1033 else if( seg )
1034 {
1035 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
1036 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
1037 }
1038 else
1039 {
1040 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
1041 }
1042 }
1043}
1044
1045
1047 PCB_DIMENSION_BASE( aParent, aType ),
1048 m_height( 0 )
1049{
1050 // To preserve look of old dimensions, initialize extension height based on default arrow length
1051 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1052}
1053
1054
1056{
1057 return new PCB_DIM_ALIGNED( *this );
1058}
1059
1060
1062{
1063 wxCHECK( aOther && aOther->Type() == PCB_DIM_ALIGNED_T, /* void */ );
1064 *this = *static_cast<const PCB_DIM_ALIGNED*>( aOther );
1065}
1066
1067void PCB_DIM_ALIGNED::Serialize( google::protobuf::Any &aContainer ) const
1068{
1069 using namespace kiapi::common;
1070 kiapi::board::types::Dimension dimension;
1071
1072 PCB_DIMENSION_BASE::Serialize( aContainer );
1073 aContainer.UnpackTo( &dimension );
1074
1075 PackVector2( *dimension.mutable_aligned()->mutable_start(), GetStart() );
1076 PackVector2( *dimension.mutable_aligned()->mutable_end(), GetEnd() );
1077 dimension.mutable_aligned()->mutable_height()->set_value_nm( m_height );
1078 dimension.mutable_aligned()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1079
1080 aContainer.PackFrom( dimension );
1081}
1082
1083
1084bool PCB_DIM_ALIGNED::Deserialize( const google::protobuf::Any &aContainer )
1085{
1086 using namespace kiapi::common;
1087
1088 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1089 return false;
1090
1091 kiapi::board::types::Dimension dimension;
1092 aContainer.UnpackTo( &dimension );
1093
1094 if( !dimension.has_aligned() )
1095 return false;
1096
1097 SetStart( UnpackVector2( dimension.aligned().start() ) );
1098 SetEnd( UnpackVector2( dimension.aligned().end() ) );
1099 SetHeight( dimension.aligned().height().value_nm());
1100 SetExtensionHeight( dimension.aligned().extension_height().value_nm() );
1101
1102 Update();
1103
1104 return true;
1105}
1106
1107
1109{
1110 wxASSERT( aImage->Type() == Type() );
1111
1112 m_shapes.clear();
1113 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
1114
1115 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
1116
1117 Update();
1118}
1119
1120
1121void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1122{
1123 m_height = -m_height;
1124 // Call this last for the Update()
1125 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1126}
1127
1128
1133
1134
1135void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
1136{
1137 VECTOR2D height( aCrossbarStart - GetStart() );
1138 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
1139
1140 if( height.Cross( crossBar ) > 0 )
1141 m_height = -height.EuclideanNorm();
1142 else
1143 m_height = height.EuclideanNorm();
1144
1145 Update();
1146}
1147
1148
1150{
1151 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1152 return;
1153
1154 m_busy = true;
1155
1156 m_shapes.clear();
1157
1158 const VECTOR2I start = GetStart();
1159 const VECTOR2I end = GetEnd();
1160 VECTOR2I dimension( end - start );
1161
1162 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
1163
1164 VECTOR2I extension;
1165
1166 if( m_height > 0 )
1167 extension = VECTOR2I( -dimension.y, dimension.x );
1168 else
1169 extension = VECTOR2I( dimension.y, -dimension.x );
1170
1171 // Add extension lines
1172 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1173
1174 VECTOR2I extStart( start );
1175 extStart += extension.Resize( m_extensionOffset );
1176
1177 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1178
1179 extStart = VECTOR2I( end );
1180 extStart += extension.Resize( m_extensionOffset );
1181
1182 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1183
1184 // Add crossbar
1185 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1186 m_crossBarStart = start + crossBarDistance;
1187 m_crossBarEnd = end + crossBarDistance;
1188
1189 // Update text after calculating crossbar position but before adding crossbar lines
1190 updateText();
1191
1192 // Now that we have the text updated, we can determine how to draw the crossbar.
1193 // First we need to create an appropriate bounding polygon to collide with
1194 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, - GetEffectiveTextPenWidth() );
1195
1196 SHAPE_POLY_SET polyBox;
1197 polyBox.NewOutline();
1198 polyBox.Append( textBox.GetOrigin() );
1199 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1200 polyBox.Append( textBox.GetEnd() );
1201 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1202 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1203
1204 // The ideal crossbar, if the text doesn't collide
1205 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1206
1207 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1208
1210 {
1211 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ),
1213 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ),
1215 }
1216 else
1217 {
1218 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ), 0 );
1219 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ), 0 );
1220 }
1221
1222 m_busy = false;
1223}
1224
1225
1227{
1228 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1229
1231 {
1232 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1233 EDA_ANGLE rotation;
1234
1235 if( crossbarCenter.x == 0 )
1236 rotation = ANGLE_90 * sign( -crossbarCenter.y );
1237 else if( crossbarCenter.x < 0 )
1238 rotation = -ANGLE_90;
1239 else
1240 rotation = ANGLE_90;
1241
1242 VECTOR2I textOffset = crossbarCenter;
1243 RotatePoint( textOffset, rotation );
1244 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
1245
1246 SetTextPos( m_crossBarStart + textOffset );
1247 }
1249 {
1250 SetTextPos( m_crossBarStart + crossbarCenter );
1251 }
1252
1253 if( m_keepTextAligned )
1254 {
1255 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
1256 textAngle.Normalize();
1257
1258 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1259 textAngle -= ANGLE_180;
1260
1261 SetTextAngle( textAngle );
1262 }
1263
1265}
1266
1267
1268void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1269{
1270 PCB_DIMENSION_BASE::GetMsgPanelInfo( aFrame, aList );
1271
1272 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
1273 // in frame's units.
1274 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
1275 unitsProvider.SetUserUnits( GetUnits() );
1276
1277 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
1278}
1279
1280
1283{
1284 // To preserve look of old dimensions, initialize extension height based on default arrow length
1285 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1287}
1288
1289
1291{
1292 return new PCB_DIM_ORTHOGONAL( *this );
1293}
1294
1295
1297{
1298 wxCHECK( aOther && aOther->Type() == PCB_DIM_ORTHOGONAL_T, /* void */ );
1299 *this = *static_cast<const PCB_DIM_ORTHOGONAL*>( aOther );
1300}
1301
1302void PCB_DIM_ORTHOGONAL::Serialize( google::protobuf::Any &aContainer ) const
1303{
1304 using namespace kiapi::common;
1305 kiapi::board::types::Dimension dimension;
1306
1307 PCB_DIMENSION_BASE::Serialize( aContainer );
1308 aContainer.UnpackTo( &dimension );
1309
1310 PackVector2( *dimension.mutable_orthogonal()->mutable_start(), GetStart() );
1311 PackVector2( *dimension.mutable_orthogonal()->mutable_end(), GetEnd() );
1312 dimension.mutable_orthogonal()->mutable_height()->set_value_nm( m_height );
1313 dimension.mutable_orthogonal()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1314
1315 dimension.mutable_orthogonal()->set_alignment( m_orientation == DIR::VERTICAL
1316 ? types::AxisAlignment::AA_Y_AXIS
1317 : types::AxisAlignment::AA_X_AXIS );
1318 aContainer.PackFrom( dimension );
1319}
1320
1321
1322bool PCB_DIM_ORTHOGONAL::Deserialize( const google::protobuf::Any &aContainer )
1323{
1324 using namespace kiapi::common;
1325
1326 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1327 return false;
1328
1329 kiapi::board::types::Dimension dimension;
1330 aContainer.UnpackTo( &dimension );
1331
1332 if( !dimension.has_orthogonal() )
1333 return false;
1334
1335 SetStart( UnpackVector2( dimension.orthogonal().start() ) );
1336 SetEnd( UnpackVector2( dimension.orthogonal().end() ) );
1337 SetHeight( dimension.orthogonal().height().value_nm());
1338 SetExtensionHeight( dimension.orthogonal().extension_height().value_nm() );
1339 SetOrientation( dimension.orthogonal().alignment() == types::AxisAlignment::AA_Y_AXIS
1341 : DIR::HORIZONTAL );
1342
1343 Update();
1344
1345 return true;
1346}
1347
1348
1350{
1351 wxASSERT( aImage->Type() == Type() );
1352
1353 m_shapes.clear();
1354 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
1355
1356 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
1357 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
1358
1359 Update();
1360}
1361
1362
1363void PCB_DIM_ORTHOGONAL::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1364{
1365 // Only reverse the height if the height is aligned with the flip
1366 if( m_orientation == DIR::HORIZONTAL && aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
1367 m_height = -m_height;
1368 else if( m_orientation == DIR::VERTICAL && aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1369 m_height = -m_height;
1370
1371 // Call this last, as we need the Update()
1372 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1373}
1374
1375
1380
1381
1383{
1384 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1385 return;
1386
1387 m_busy = true;
1388 m_shapes.clear();
1389
1390 const VECTOR2I start = GetStart();
1391 const VECTOR2I end = GetEnd();
1392
1393 int measurement = ( m_orientation == DIR::HORIZONTAL ? end.x - start.x : end.y - start.y );
1395
1396 VECTOR2I extension;
1397
1399 extension = VECTOR2I( 0, m_height );
1400 else
1401 extension = VECTOR2I( m_height, 0 );
1402
1403 // Add first extension line
1404 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1405
1406 VECTOR2I extStart( start );
1407 extStart += extension.Resize( m_extensionOffset );
1408
1409 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1410
1411 // Add crossbar
1412 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1413 m_crossBarStart = start + crossBarDistance;
1414
1417 else
1419
1420 // Add second extension line (end to crossbar end)
1422 extension = VECTOR2I( 0, end.y - m_crossBarEnd.y );
1423 else
1424 extension = VECTOR2I( end.x - m_crossBarEnd.x, 0 );
1425
1426 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
1427
1428 extStart = VECTOR2I( m_crossBarEnd );
1429 extStart -= extension.Resize( m_extensionHeight );
1430
1431 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1432
1433 // Update text after calculating crossbar position but before adding crossbar lines
1434 updateText();
1435
1436 // Now that we have the text updated, we can determine how to draw the crossbar.
1437 // First we need to create an appropriate bounding polygon to collide with
1438 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1439
1440 SHAPE_POLY_SET polyBox;
1441 polyBox.NewOutline();
1442 polyBox.Append( textBox.GetOrigin() );
1443 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1444 polyBox.Append( textBox.GetEnd() );
1445 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1446 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1447
1448 // The ideal crossbar, if the text doesn't collide
1449 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1450
1451 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1452
1453 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
1454
1456 {
1457 // Arrows with fixed length.
1458 drawAnArrow( m_crossBarStart, crossBarAngle + EDA_ANGLE( 180 ),
1461 }
1462 else
1463 {
1464 drawAnArrow( m_crossBarStart, crossBarAngle, 0 );
1465 drawAnArrow( m_crossBarEnd, crossBarAngle + EDA_ANGLE( 180 ), 0 );
1466 }
1467
1468 m_busy = false;
1469}
1470
1471
1473{
1474 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1475
1477 {
1478 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1479
1480 VECTOR2I textOffset;
1481
1483 textOffset.y = -textOffsetDistance;
1484 else
1485 textOffset.x = -textOffsetDistance;
1486
1487 textOffset += crossbarCenter;
1488
1489 SetTextPos( m_crossBarStart + textOffset );
1490 }
1492 {
1493 SetTextPos( m_crossBarStart + crossbarCenter );
1494 }
1495
1496 if( m_keepTextAligned )
1497 {
1498 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
1500 else
1502 }
1503
1505}
1506
1507
1508void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1509{
1510 EDA_ANGLE angle( aAngle );
1511
1512 // restrict angle to -179.9 to 180.0 degrees
1513 angle.Normalize180();
1514
1515 // adjust orientation and height to new angle
1516 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
1517 // in the other cases we will use the nearest 90 degree angle to
1518 // choose at least an approximate axis for the target orientation
1519 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
1520 if( angle > ANGLE_45 && angle <= ANGLE_135 )
1521 {
1522 // about 90 degree
1524 {
1526 }
1527 else
1528 {
1530 m_height = -m_height;
1531 }
1532 }
1533 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
1534 {
1535 // about -90 degree
1537 {
1539 m_height = -m_height;
1540 }
1541 else
1542 {
1544 }
1545 }
1546 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
1547 {
1548 // about 180 degree
1549 m_height = -m_height;
1550 }
1551
1552 // this will update m_crossBarStart and m_crossbarEnd
1553 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
1554}
1555
1556
1567
1568
1570{
1571 wxCHECK( aOther && aOther->Type() == PCB_DIM_LEADER_T, /* void */ );
1572 *this = *static_cast<const PCB_DIM_LEADER*>( aOther );
1573}
1574
1575void PCB_DIM_LEADER::Serialize( google::protobuf::Any &aContainer ) const
1576{
1577 using namespace kiapi::common;
1578 kiapi::board::types::Dimension dimension;
1579
1580 PCB_DIMENSION_BASE::Serialize( aContainer );
1581 aContainer.UnpackTo( &dimension );
1582
1583 PackVector2( *dimension.mutable_leader()->mutable_start(), GetStart() );
1584 PackVector2( *dimension.mutable_leader()->mutable_end(), GetEnd() );
1585 dimension.mutable_leader()->set_border_style(
1587 m_textBorder ) );
1588
1589 aContainer.PackFrom( dimension );
1590}
1591
1592
1593bool PCB_DIM_LEADER::Deserialize( const google::protobuf::Any &aContainer )
1594{
1595 using namespace kiapi::common;
1596
1597 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1598 return false;
1599
1600 kiapi::board::types::Dimension dimension;
1601 aContainer.UnpackTo( &dimension );
1602
1603 if( !dimension.has_leader() )
1604 return false;
1605
1606 SetStart( UnpackVector2( dimension.leader().start() ) );
1607 SetEnd( UnpackVector2( dimension.leader().end() ) );
1608 SetTextBorder( FromProtoEnum<DIM_TEXT_BORDER>( dimension.leader().border_style() ) );
1609
1610 Update();
1611
1612 return true;
1613}
1614
1615
1617{
1618 return new PCB_DIM_LEADER( *this );
1619}
1620
1621
1623{
1624 wxASSERT( aImage->Type() == Type() );
1625
1626 m_shapes.clear();
1627 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
1628
1629 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
1630
1631 Update();
1632}
1633
1634
1639
1640
1642{
1643 // Our geometry is dependent on the size of the text, so just update the whole shebang
1645}
1646
1647
1649{
1650 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1651 return;
1652
1653 m_busy = true;
1654
1655 m_shapes.clear();
1656
1658
1659 // Now that we have the text updated, we can determine how to draw the second line
1660 // First we need to create an appropriate bounding polygon to collide with
1661 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1662
1663 SHAPE_POLY_SET polyBox;
1664 polyBox.NewOutline();
1665 polyBox.Append( textBox.GetOrigin() );
1666 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1667 polyBox.Append( textBox.GetEnd() );
1668 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1669 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1670
1671 const VECTOR2I boardStart = GetStart();
1672 const VECTOR2I boardEnd = GetEnd();
1673
1674 VECTOR2I firstLine( boardEnd - boardStart );
1675 VECTOR2I start( boardStart );
1676 start += firstLine.Resize( m_extensionOffset );
1677
1678 SEG arrowSeg( boardStart, boardEnd );
1679 SEG textSeg( boardEnd, GetTextPos() );
1680 OPT_VECTOR2I arrowSegEnd;
1681 OPT_VECTOR2I textSegEnd;
1682
1684 {
1685 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1686 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1687 CIRCLE circle( textBox.GetCenter(), radius );
1688
1689 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1690 textSegEnd = segCircleIntersection( circle, textSeg );
1691 }
1692 else
1693 {
1694 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1695 textSegEnd = segPolyIntersection( polyBox, textSeg );
1696 }
1697
1698 if( !arrowSegEnd )
1699 arrowSegEnd = boardEnd;
1700
1701 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1702
1703 drawAnArrow( start, EDA_ANGLE( firstLine ), 0 );
1704
1705 if( !GetText().IsEmpty() )
1706 {
1707 switch( m_textBorder )
1708 {
1710 {
1711 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1712 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1713
1714 break;
1715 }
1716
1718 {
1719 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1720 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1721 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1722
1723 break;
1724 }
1725
1726 default:
1727 break;
1728 }
1729 }
1730
1731 if( textSegEnd && *arrowSegEnd == boardEnd )
1732 m_shapes.emplace_back( new SHAPE_SEGMENT( boardEnd, *textSegEnd ) );
1733
1734 m_busy = false;
1735}
1736
1737
1738void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1739{
1740 // Don't use GetShownText(); we want to see the variable references here
1741 aList.emplace_back( _( "Leader" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
1742
1743 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
1744
1745 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1746 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1747 aFrame->MessageTextFromValue( startCoord.x ),
1748 aFrame->MessageTextFromValue( startCoord.y ) );
1749
1750 aList.emplace_back( start, wxEmptyString );
1751
1752 aList.emplace_back( _( "Layer" ), GetLayerName() );
1753}
1754
1755
1765
1767{
1768 wxCHECK( aOther && aOther->Type() == PCB_DIM_RADIAL_T, /* void */ );
1769 *this = *static_cast<const PCB_DIM_RADIAL*>( aOther );
1770}
1771
1772void PCB_DIM_RADIAL::Serialize( google::protobuf::Any &aContainer ) const
1773{
1774 using namespace kiapi::common;
1775 kiapi::board::types::Dimension dimension;
1776
1777 PCB_DIMENSION_BASE::Serialize( aContainer );
1778 aContainer.UnpackTo( &dimension );
1779
1780 PackVector2( *dimension.mutable_radial()->mutable_center(), GetStart() );
1781 PackVector2( *dimension.mutable_radial()->mutable_radius_point(), GetEnd() );
1782 dimension.mutable_radial()->mutable_leader_length()->set_value_nm( m_leaderLength );
1783
1784 aContainer.PackFrom( dimension );
1785}
1786
1787
1788bool PCB_DIM_RADIAL::Deserialize( const google::protobuf::Any &aContainer )
1789{
1790 using namespace kiapi::common;
1791
1792 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1793 return false;
1794
1795 kiapi::board::types::Dimension dimension;
1796 aContainer.UnpackTo( &dimension );
1797
1798 if( !dimension.has_radial() )
1799 return false;
1800
1801 SetStart( UnpackVector2( dimension.radial().center() ) );
1802 SetEnd( UnpackVector2( dimension.radial().radius_point() ) );
1803 SetLeaderLength( dimension.radial().leader_length().value_nm() );
1804
1805 Update();
1806
1807 return true;
1808}
1809
1810
1812{
1813 return new PCB_DIM_RADIAL( *this );
1814}
1815
1816
1818{
1819 wxASSERT( aImage->Type() == Type() );
1820
1821 m_shapes.clear();
1822 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1823
1824 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1825
1826 Update();
1827}
1828
1829
1834
1835
1837{
1838 const VECTOR2I end = GetEnd();
1839 VECTOR2I radial( end - GetStart() );
1840
1841 return end + radial.Resize( m_leaderLength );
1842}
1843
1844
1846{
1847 if( m_keepTextAligned )
1848 {
1849 VECTOR2I textLine( GetTextPos() - GetKnee() );
1850 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1851
1852 textAngle.Normalize();
1853
1854 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1855 textAngle -= ANGLE_180;
1856
1857 // Round to nearest degree
1858 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1859
1860 SetTextAngle( textAngle );
1861 }
1862
1864}
1865
1866
1868{
1869 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1870 return;
1871
1872 m_busy = true;
1873
1874 m_shapes.clear();
1875
1876 const VECTOR2I boardStart = GetStart();
1877 const VECTOR2I boardEnd = GetEnd();
1878
1879 VECTOR2I center( boardStart );
1880 VECTOR2I centerArm( 0, m_arrowLength );
1881
1882 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1883
1884 RotatePoint( centerArm, -ANGLE_90 );
1885
1886 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1887
1888 VECTOR2I radius( boardEnd - boardStart );
1889
1890 m_measuredValue = KiROUND( radius.EuclideanNorm() );
1891
1892 updateText();
1893
1894 // Now that we have the text updated, we can determine how to draw the second line
1895 // First we need to create an appropriate bounding polygon to collide with
1896 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1897
1898 SHAPE_POLY_SET polyBox;
1899 polyBox.NewOutline();
1900 polyBox.Append( textBox.GetOrigin() );
1901 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1902 polyBox.Append( textBox.GetEnd() );
1903 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1904 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1905
1906 VECTOR2I radial( boardEnd - boardStart );
1907 radial = radial.Resize( m_leaderLength );
1908
1909 SEG arrowSeg( boardEnd, boardEnd + radial );
1910 SEG textSeg( arrowSeg.B, GetTextPos() );
1911
1912 CollectKnockedOutSegments( polyBox, arrowSeg, m_shapes );
1913 CollectKnockedOutSegments( polyBox, textSeg, m_shapes );
1914
1915 drawAnArrow( boardEnd, EDA_ANGLE( radial ), 0 );
1916
1917 m_busy = false;
1918}
1919
1920
1927
1929{
1930 wxCHECK( aOther && aOther->Type() == PCB_DIM_CENTER_T, /* void */ );
1931 *this = *static_cast<const PCB_DIM_CENTER*>( aOther );
1932}
1933
1934void PCB_DIM_CENTER::Serialize( google::protobuf::Any &aContainer ) const
1935{
1936 using namespace kiapi::common;
1937 kiapi::board::types::Dimension dimension;
1938
1939 PCB_DIMENSION_BASE::Serialize( aContainer );
1940 aContainer.UnpackTo( &dimension );
1941
1942 PackVector2( *dimension.mutable_center()->mutable_center(), GetStart() );
1943 PackVector2( *dimension.mutable_center()->mutable_end(), GetEnd() );
1944
1945 aContainer.PackFrom( dimension );
1946}
1947
1948
1949bool PCB_DIM_CENTER::Deserialize( const google::protobuf::Any &aContainer )
1950{
1951 using namespace kiapi::common;
1952
1953 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1954 return false;
1955
1956 kiapi::board::types::Dimension dimension;
1957 aContainer.UnpackTo( &dimension );
1958
1959 if( !dimension.has_center() )
1960 return false;
1961
1962 SetStart( UnpackVector2( dimension.center().center() ) );
1963 SetEnd( UnpackVector2( dimension.center().end() ) );
1964
1965 Update();
1966
1967 return true;
1968}
1969
1970
1972{
1973 return new PCB_DIM_CENTER( *this );
1974}
1975
1976
1978{
1979 wxASSERT( aImage->Type() == Type() );
1980
1981 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1982}
1983
1984
1989
1990
1992{
1993 BOX2I bBox;
1994 int xmin, xmax, ymin, ymax;
1995
1996 const VECTOR2I start = GetStart();
1997 xmin = start.x;
1998 xmax = start.x;
1999 ymin = start.y;
2000 ymax = start.y;
2001
2002 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
2003 {
2004 BOX2I shapeBox = shape->BBox();
2005 shapeBox.Inflate( m_lineThickness / 2 );
2006
2007 xmin = std::min( xmin, shapeBox.GetOrigin().x );
2008 xmax = std::max( xmax, shapeBox.GetEnd().x );
2009 ymin = std::min( ymin, shapeBox.GetOrigin().y );
2010 ymax = std::max( ymax, shapeBox.GetEnd().y );
2011 }
2012
2013 bBox.SetX( xmin );
2014 bBox.SetY( ymin );
2015 bBox.SetWidth( xmax - xmin + 1 );
2016 bBox.SetHeight( ymax - ymin + 1 );
2017
2018 bBox.Normalize();
2019
2020 return bBox;
2021}
2022
2023
2025{
2026 return GetBoundingBox();
2027}
2028
2029
2031{
2032 // Even if PCB_DIM_CENTER has no text, we still need to update its text position
2033 // so GetTextPos() users get a valid value. Required at least for lasso hit-testing.
2034 SetTextPos( GetStart() );
2035
2037}
2038
2039
2041{
2042 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
2043 return;
2044
2045 m_busy = true;
2046
2047 m_shapes.clear();
2048
2049 const VECTOR2I boardStart = GetStart();
2050 const VECTOR2I boardEnd = GetEnd();
2051 VECTOR2I center( boardStart );
2052 VECTOR2I arm( boardEnd - boardStart );
2053
2054 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
2055
2056 RotatePoint( arm, -ANGLE_90 );
2057
2058 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
2059
2060 updateText();
2061
2062 m_busy = false;
2063}
2064
2065
2066static struct DIMENSION_DESC
2067{
2069 {
2071 .Map( DIM_PRECISION::X, _HKI( "0" ) )
2072 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
2073 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
2074 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
2075 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
2076 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
2077 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
2078 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
2079 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
2080 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
2081
2083 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
2084 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
2085 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
2086
2088 .Map( DIM_UNITS_MODE::INCH, _HKI( "Inches" ) )
2089 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
2090 .Map( DIM_UNITS_MODE::MM, _HKI( "Millimeters" ) )
2091 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
2092
2094 .Map( DIM_ARROW_DIRECTION::INWARD, _HKI( "Inward" ) )
2095 .Map( DIM_ARROW_DIRECTION::OUTWARD, _HKI( "Outward" ) );
2096
2098 .Map( DIM_VALUE_MODE::DRIVEN, _HKI( "Driven" ) )
2099 .Map( DIM_VALUE_MODE::DRIVING, _HKI( "Driving" ) )
2100 .Map( DIM_VALUE_MODE::ARBITRARY, _HKI( "Arbitrary" ) );
2101
2110
2111 propMgr.Mask( TYPE_HASH( PCB_DIMENSION_BASE ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
2112
2113 const wxString groupDimension = _HKI( "Dimension Properties" );
2114
2115 auto isLeader =
2116 []( INSPECTABLE* aItem ) -> bool
2117 {
2118 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) != nullptr;
2119 };
2120
2121 auto isNotLeader =
2122 []( INSPECTABLE* aItem ) -> bool
2123 {
2124 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) == nullptr;
2125 };
2126
2127 auto isMultiArrowDirection =
2128 []( INSPECTABLE* aItem ) -> bool
2129 {
2130 return dynamic_cast<PCB_DIM_ALIGNED*>( aItem ) != nullptr;
2131 };
2132
2135 groupDimension )
2136 .SetAvailableFunc( isNotLeader );
2139 groupDimension )
2140 .SetAvailableFunc( isNotLeader );
2141 auto hasValueMode =
2142 []( INSPECTABLE* aItem ) -> bool
2143 {
2144 return DimensionHasValueMode( dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) );
2145 };
2146
2147 // Value bearing dims use Value row instead while leaders keep Text below
2148 // Override Text left for centre mark only
2149 auto usesOverrideText =
2150 [isLeader, hasValueMode]( INSPECTABLE* aItem ) -> bool
2151 {
2152 return aItem && !isLeader( aItem ) && !hasValueMode( aItem );
2153 };
2154
2155 // Driving needs both endpoints bound to movable geometry
2156 // Dropdown always offers it so gate the transition here
2157 auto valueModeValidator =
2158 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2159 {
2160 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2161
2162 if( !dim )
2163 return std::nullopt;
2164
2165 int mode = 0;
2166
2167 if( aValue.CheckType<DIM_VALUE_MODE>() )
2168 mode = static_cast<int>( aValue.As<DIM_VALUE_MODE>() );
2169 else if( !aValue.GetAs( &mode ) )
2170 return std::nullopt;
2171
2172 if( mode == static_cast<int>( DIM_VALUE_MODE::DRIVING )
2173 && !DimensionCanDrive( dim->GetBoard(), dim ) )
2174 {
2175 return std::make_unique<VALIDATION_ERROR_MSG>(
2176 _( "Driving requires both dimension endpoints bound to objects" ) );
2177 }
2178
2179 return std::nullopt;
2180 };
2181
2182 // Driving edits length constraint which must stay positive
2183 // Catches zero and negative and stale exprs parsing to zero
2184 auto drivingValueValidator =
2185 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2186 {
2187 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2188
2189 if( !dim || dim->GetValueMode() != DIM_VALUE_MODE::DRIVING )
2190 return std::nullopt;
2191
2192 wxString text;
2193
2194 if( !aValue.GetAs( &text ) )
2195 return std::nullopt;
2196
2198 text );
2199
2200 if( !( iu > 0.0 ) )
2201 {
2202 return std::make_unique<VALIDATION_ERROR_MSG>(
2203 _( "Enter a positive length for a driving dimension" ) );
2204 }
2205
2206 return std::nullopt;
2207 };
2208
2209 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
2211 groupDimension )
2212 .SetAvailableFunc( usesOverrideText );
2213
2216 groupDimension )
2217 .SetAvailableFunc( hasValueMode )
2218 .SetValidator( std::move( valueModeValidator ) );
2219
2222 groupDimension )
2223 .SetAvailableFunc( hasValueMode )
2225 []( INSPECTABLE* aItem ) -> bool
2226 {
2227 // Driven mirrors measured geometry so grey it out since edit would not stick
2228 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2229 return dim && dim->GetValueMode() != DIM_VALUE_MODE::DRIVEN;
2230 } )
2231 .SetValidator( std::move( drivingValueValidator ) );
2232
2235 groupDimension )
2236 .SetAvailableFunc( isLeader );
2237
2240 groupDimension )
2241 .SetAvailableFunc( isNotLeader );
2244 groupDimension )
2245 .SetAvailableFunc( isNotLeader );
2248 groupDimension )
2249 .SetAvailableFunc( isNotLeader );
2250 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
2252 groupDimension )
2253 .SetAvailableFunc( isNotLeader );
2254
2257 groupDimension )
2258 .SetAvailableFunc( isMultiArrowDirection );
2259
2260 const wxString groupText = _HKI( "Text Properties" );
2261
2262 const auto isTextOrientationWriteable =
2263 []( INSPECTABLE* aItem ) -> bool
2264 {
2265 return !static_cast<PCB_DIMENSION_BASE*>( aItem )->GetKeepTextAligned();
2266 };
2267
2268 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Keep Aligned with Dimension" ),
2271 groupText );
2272
2273 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, double>( _HKI( "Orientation" ),
2277 groupText )
2278 .SetWriteableFunc( isTextOrientationWriteable );
2279 }
2281
2287
2288
2290{
2292 {
2303
2304 const wxString groupDimension = _HKI( "Dimension Properties" );
2305
2306 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
2309 groupDimension );
2310 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
2313 groupDimension );
2314
2316 _HKI( "Text" ),
2317 []( INSPECTABLE* aItem ) { return false; } );
2319 _HKI( "Vertical Justification" ),
2320 []( INSPECTABLE* aItem ) { return false; } );
2322 _HKI( "Hyperlink" ),
2323 []( INSPECTABLE* aItem ) { return false; } );
2325 _HKI( "Knockout" ),
2326 []( INSPECTABLE* aItem ) { return false; } );
2327 }
2329
2330
2332{
2334 {
2347
2349 _HKI( "Text" ),
2350 []( INSPECTABLE* aItem ) { return false; } );
2352 _HKI( "Vertical Justification" ),
2353 []( INSPECTABLE* aItem ) { return false; } );
2355 _HKI( "Hyperlink" ),
2356 []( INSPECTABLE* aItem ) { return false; } );
2358 _HKI( "Knockout" ),
2359 []( INSPECTABLE* aItem ) { return false; } );
2360 }
2362
2363
2365{
2367 {
2378
2379 const wxString groupDimension = _HKI( "Dimension Properties" );
2380
2381 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
2384 groupDimension );
2385
2387 _HKI( "Text" ),
2388 []( INSPECTABLE* aItem ) { return false; } );
2390 _HKI( "Vertical Justification" ),
2391 []( INSPECTABLE* aItem ) { return false; } );
2393 _HKI( "Hyperlink" ),
2394 []( INSPECTABLE* aItem ) { return false; } );
2396 _HKI( "Knockout" ),
2397 []( INSPECTABLE* aItem ) { return false; } );
2398 }
2400
2401
2403{
2405 {
2407 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
2408 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
2409 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
2410
2421
2422 const wxString groupDimension = _HKI( "Dimension Properties" );
2423
2426 groupDimension );
2427
2429 _HKI( "Text" ),
2430 []( INSPECTABLE* aItem ) { return false; } );
2432 _HKI( "Vertical Justification" ),
2433 []( INSPECTABLE* aItem ) { return false; } );
2435 _HKI( "Hyperlink" ),
2436 []( INSPECTABLE* aItem ) { return false; } );
2438 _HKI( "Knockout" ),
2439 []( INSPECTABLE* aItem ) { return false; } );
2440 }
2442
2444
2445
2447{
2449 {
2460
2461
2463 _HKI( "Text" ),
2464 []( INSPECTABLE* aItem ) { return false; } );
2466 _HKI( "Vertical Justification" ),
2467 []( INSPECTABLE* aItem ) { return false; } );
2469 _HKI( "Hyperlink" ),
2470 []( INSPECTABLE* aItem ) { return false; } );
2472 _HKI( "Knockout" ),
2473 []( INSPECTABLE* aItem ) { return false; } );
2474 }
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:47
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
BITMAPS
A list of all bitmap identifiers.
@ add_radial_dimension
@ add_aligned_dimension
@ add_center_dimension
@ add_orthogonal_dimension
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
Container for design settings for a BOARD object.
DIM_PRECISION m_DimensionPrecision
Number of digits after the decimal.
DIM_UNITS_FORMAT m_DimensionUnitsFormat
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
DIM_TEXT_POSITION m_DimensionTextPosition
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:85
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:295
friend class BOARD
Definition board_item.h:548
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:386
PCB_LAYER_ID m_layer
Definition board_item.h:540
bool IsLocked() const override
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:343
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
bool IsSideSpecific() const
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
EDA_UNITS GetUserUnits()
Definition board.h:913
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:554
constexpr void SetHeight(size_type val)
Definition box2.h:288
constexpr const Vec GetEnd() const
Definition box2.h:208
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:142
constexpr coord_type GetY() const
Definition box2.h:204
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr coord_type GetX() const
Definition box2.h:203
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
constexpr const Vec GetCenter() const
Definition box2.h:226
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:164
constexpr void SetWidth(size_type val)
Definition box2.h:283
constexpr void SetX(coord_type val)
Definition box2.h:273
constexpr const Vec & GetOrigin() const
Definition box2.h:206
constexpr void SetY(coord_type val)
Definition box2.h:278
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:307
constexpr coord_type GetBottom() const
Definition box2.h:218
Represent basic circle geometry with utility geometry functions.
Definition circle.h:33
std::vector< VECTOR2I > Intersect(const CIRCLE &aCircle) const
Compute the intersection points between this circle and aCircle.
Definition circle.cpp:243
bool Contains(const VECTOR2I &aP) const
Return true if aP is on the circumference of this circle.
Definition circle.cpp:188
EDA_ANGLE Normalize()
Definition eda_angle.h:229
double AsDegrees() const
Definition eda_angle.h:116
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
ORIGIN_TRANSFORMS & GetOriginTransforms() override
Return a reference to the default ORIGIN_TRANSFORMS object.
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
const KIID m_Uuid
Definition eda_item.h:531
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:543
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:89
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition eda_text.cpp:165
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:294
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:576
virtual int GetTextHeight() const
Definition eda_text.h:288
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition eda_text.cpp:208
KIFONT::FONT * GetFont() const
Definition eda_text.h:268
void SetMirrored(bool isMirrored)
Definition eda_text.cpp:388
BOX2I GetTextBox(const RENDER_SETTINGS *aSettings, int aLine=-1) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition eda_text.cpp:773
virtual int GetTextWidth() const
Definition eda_text.h:285
virtual void ClearBoundingBoxCache()
Definition eda_text.cpp:695
double Similarity(const EDA_TEXT &aOther) const
virtual void ClearRenderCache()
Definition eda_text.cpp:689
bool IsMirrored() const
Definition eda_text.h:211
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition eda_text.cpp:461
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape(bool aTriangulate=true, const BOX2I &aBBox=BOX2I(), const EDA_ANGLE &aAngle=ANGLE_0) const
build a list of segments (SHAPE_SEGMENT) to describe a text shape.
void SetTextAngleDegrees(double aOrientation)
Definition eda_text.h:171
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:265
bool operator==(const EDA_TEXT &aRhs) const
Definition eda_text.h:419
static ENUM_MAP< T > & Instance()
Definition property.h:721
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:38
Contains methods for drawing PCB-specific items.
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:80
const std::unordered_set< KIID > & GetConstrainedItems() const
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:176
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:181
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
bool IsLayerVisibleCached(int aLayer) const
Definition view.h:437
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:225
Definition kiid.h:46
A class to perform either relative or absolute display origin transforms for a single axis of a point...
T ToDisplayAbs(const T &aValue) const
A geometric constraint between board items (issue #2329).
std::optional< double > GetValue() const
Abstract dimension API.
EDA_UNITS GetUnits() const
bool m_autoUnits
If true, follow the currently selected UI units.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
void Update()
Update the dimension's cached text and geometry.
void ChangeSuffix(const wxString &aSuffix)
void OnFootprintRescaled(double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I &aAnchor, const EDA_ANGLE &aParentRotate) override
Apply a parent footprint scale to this item.
wxString GetOverrideText() const
wxString GetSuffix() const
std::vector< std::shared_ptr< SHAPE > > m_shapes
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void ClearRenderCache() override
int m_lineThickness
Thickness used for all graphics in the dimension.
virtual void SetEnd(const VECTOR2I &aPoint)
void Move(const VECTOR2I &offset) override
Move this object.
void SetUnitsFormat(const DIM_UNITS_FORMAT aFormat)
bool m_suppressZeroes
Suppress trailing zeroes.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
void SetUnits(EDA_UNITS aUnits)
VECTOR2I m_start
Start, FP-relative when in a footprint, board absolute otherwise.
DIM_PRECISION m_precision
Number of digits to display after decimal.
virtual void SetStart(const VECTOR2I &aPoint)
void addShape(const ShapeType &aShape)
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.
void SetPrefix(const wxString &aPrefix)
wxString m_suffix
String appended to the value.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void ChangeOverrideText(const wxString &aValue)
void SetExtensionOffset(int aOffset)
void SetSuppressZeroes(bool aSuppress)
bool m_inClearRenderCache
re-entrancy guard
PCB_DIMENSION_BASE(BOARD_ITEM *aParent, KICAD_T aType=PCB_DIMENSION_T)
int m_extensionOffset
Distance from feature points to extension line start.
void ChangeArrowDirection(const DIM_ARROW_DIRECTION &aDirection)
bool GetKeepTextAligned() const
void OnFootprintTransformed() override
Hook for items inside a footprint to refresh after the FP transform changes (translate,...
void ChangeTextAngleDegrees(double aDegrees)
bool m_keepTextAligned
Calculate text orientation to match dimension.
DIM_PRECISION GetPrecision() const
wxString GetPrefix() const
void SetOverrideTextEnabled(bool aOverride)
void SetSuffix(const wxString &aSuffix)
bool operator==(const PCB_DIMENSION_BASE &aOther) const
void ChangeValueMode(DIM_VALUE_MODE aMode)
Property panel setter for value mode override text flag lives on dimension length constraint is board...
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
DIM_UNITS_MODE GetUnitsMode() const
void drawAnArrow(VECTOR2I aStartPoint, EDA_ANGLE anAngle, int aLength)
Draws an arrow and updates the shape container.
void SetTextPositionMode(DIM_TEXT_POSITION aMode)
virtual void updateText()
Update the text field value from the current geometry (called by updateGeometry normally).
bool HitTest(const VECTOR2I &aPosition, int aAccuracy) const override
Test if aPosition is inside or on the boundary of this item.
EDA_UNITS m_units
0 = inches, 1 = mm
int m_measuredValue
value of PCB dimensions
DIM_VALUE_MODE GetValueMode() const
Value mode from board state via DimensionValueMode.
DIM_UNITS_FORMAT GetUnitsFormat() const
void SetLineThickness(int aWidth)
void SetArrowLength(int aLength)
DIM_ARROW_DIRECTION GetArrowDirection() const
wxString m_valueString
Displayed value when m_overrideValue = true.
virtual VECTOR2I GetEnd() const
void ChangePrecision(DIM_PRECISION aPrecision)
void SetPrecision(DIM_PRECISION aPrecision)
bool m_overrideTextEnabled
Manually specify the displayed measurement value.
DIM_UNITS_FORMAT m_unitsFormat
How to render the units suffix.
int GetMeasuredValue() const
bool GetSuppressZeroes() const
void SetArrowDirection(const DIM_ARROW_DIRECTION &aDirection)
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
DIM_TEXT_POSITION m_textPosition
How to position the text.
void SetOverrideText(const wxString &aValue)
wxString GetValueText() const
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
void ChangePrefix(const wxString &aPrefix)
wxString m_prefix
String prepended to the value.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
virtual VECTOR2I GetStart() const
The dimension's origin is the first feature point for the dimension.
DIM_ARROW_DIRECTION m_arrowDirection
direction of dimension arrow.
void ChangeKeepTextAligned(bool aKeepAligned)
void ChangeUnitsFormat(const DIM_UNITS_FORMAT aFormat)
wxString GetValueFieldText() const
Mode aware value for panel driving shows constraint length arbitrary shows override text otherwise sh...
void ChangeSuppressZeroes(bool aSuppress)
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.
void ChangeValueFieldText(const wxString &aText)
Property panel setter for value arbitrary text owned by dimension driving edits board level constrain...
double GetTextAngleDegreesProp() const
bool GetOverrideTextEnabled() const
void SetUnitsMode(DIM_UNITS_MODE aMode)
int m_arrowLength
Length of arrow shapes.
virtual void Mirror(const VECTOR2I &axis_pos, FLIP_DIRECTION aFlipDirection) override
Mirror the dimension relative to a given horizontal axis.
VECTOR2I m_end
End, FP-relative when in a footprint, board absolute otherwise.
void ChangeUnitsMode(DIM_UNITS_MODE aMode)
void SetKeepTextAligned(bool aKeepAligned)
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
VECTOR2I GetPosition() const override
For better understanding of the points that make a dimension:
int GetHeight() const
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
int m_height
Perpendicular distance from features to crossbar.
void ChangeExtensionHeight(int aHeight)
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
void SetExtensionHeight(int aHeight)
VECTOR2I m_crossBarStart
Crossbar start control point.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void Mirror(const VECTOR2I &axis_pos, FLIP_DIRECTION aFlipDirection) override
Mirror the dimension relative to a given horizontal axis.
void UpdateHeight(const VECTOR2I &aCrossbarStart, const VECTOR2I &aCrossbarEnd)
Update the stored height basing on points coordinates.
virtual void swapData(BOARD_ITEM *aImage) override
int m_extensionHeight
Length of extension lines past the crossbar.
void CopyFrom(const BOARD_ITEM *aOther) override
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
VECTOR2I m_crossBarEnd
Crossbar end control point.
PCB_DIM_ALIGNED(BOARD_ITEM *aParent, KICAD_T aType=PCB_DIM_ALIGNED_T)
void ChangeHeight(int aHeight)
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
int GetExtensionHeight() const
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.
Mark the center of a circle or arc with a cross shape.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void CopyFrom(const BOARD_ITEM *aOther) override
virtual void swapData(BOARD_ITEM *aImage) override
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
PCB_DIM_CENTER(BOARD_ITEM *aParent)
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
A leader is a dimension-like object pointing to a specific point.
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.
DIM_TEXT_BORDER m_textBorder
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
DIM_TEXT_BORDER GetTextBorder() const
void CopyFrom(const BOARD_ITEM *aOther) override
virtual void swapData(BOARD_ITEM *aImage) override
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
void SetTextBorder(DIM_TEXT_BORDER aBorder)
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
PCB_DIM_LEADER(BOARD_ITEM *aParent)
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void ChangeTextBorder(DIM_TEXT_BORDER aBorder)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
void swapData(BOARD_ITEM *aImage) override
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
void CopyFrom(const BOARD_ITEM *aOther) override
void SetOrientation(DIR aOrientation)
Set the orientation of the dimension line (so, perpendicular to the feature lines).
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
DIR m_orientation
What axis to lock the dimension line to.
void Mirror(const VECTOR2I &axis_pos, FLIP_DIRECTION aFlipDirection) override
Mirror the dimension relative to a given horizontal axis.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
PCB_DIM_ORTHOGONAL(BOARD_ITEM *aParent)
A radial dimension indicates either the radius or diameter of an arc or circle.
int GetLeaderLength() const
PCB_DIM_RADIAL(BOARD_ITEM *aParent)
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
virtual void swapData(BOARD_ITEM *aImage) override
void SetLeaderLength(int aLength)
void CopyFrom(const BOARD_ITEM *aOther) override
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void ChangeLeaderLength(int aLength)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
VECTOR2I GetKnee() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
Definition pcb_text.cpp:355
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition pcb_text.cpp:226
EDA_ANGLE GetTextAngle() const override
Definition pcb_text.cpp:544
void Offset(const VECTOR2I &aOffset) override
Definition pcb_text.cpp:509
void SetLibTextAngle(const EDA_ANGLE &aAngle)
Definition pcb_text.h:121
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition pcb_text.cpp:162
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition pcb_text.cpp:241
VECTOR2I GetTextPos() const override
Definition pcb_text.cpp:445
PCB_TEXT(BOARD_ITEM *parent, KICAD_T idtype=PCB_TEXT_T)
Definition pcb_text.cpp:49
void OnFootprintRescaled(double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I &aAnchor, const EDA_ANGLE &aParentRotate) override
Apply a parent footprint scale to this item.
Definition pcb_text.cpp:598
std::vector< int > ViewGetLayers() const override
Definition pcb_text.cpp:232
bool TextHitTest(const VECTOR2I &aPoint, int aAccuracy=0) const override
Test if aPoint is within the bounds of this object.
Definition pcb_text.cpp:410
const EDA_ANGLE & GetLibTextAngle() const
Text angle in the parent footprint's lib frame, or absolute when not in a footprint.
Definition pcb_text.h:120
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_text.cpp:678
int GetTextThickness() const override
Definition pcb_text.cpp:481
void SetTextAngle(const EDA_ANGLE &aAngle) override
Definition pcb_text.cpp:553
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition property.h:287
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:349
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.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void OverrideAvailability(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName, std::function< bool(INSPECTABLE *)> aFunc)
Sets an override availability functor for a base class property of a given derived class.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
void AddShape(SHAPE *aShape)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
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.
SEGMENT_ITERATOR IterateSegments(int aFirst, int aLast, bool aIterateHoles=false)
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
CONST_SEGMENT_ITERATOR CIterateSegments(int aFirst, int aLast, bool aIterateHoles=false) const
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
SEGMENT_ITERATOR_TEMPLATE< SEG > SEGMENT_ITERATOR
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.
SEGMENT_ITERATOR_TEMPLATE< const SEG > CONST_SEGMENT_ITERATOR
const SEG & GetSeg() const
VECTOR2I InverseApply(const VECTOR2I &aPoint) const
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
void SetUserUnits(EDA_UNITS aUnits)
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition vector2d.h:534
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:381
A type-safe container of any type.
Definition ki_any.h:92
DIM_VALUE_MODE DimensionValueMode(BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
The value mode aDimension is in, derived from state: a self driving length means Driving,...
bool DimensionHasValueMode(const PCB_DIMENSION_BASE *aDimension)
True for dimension types with a measured value aligned orthogonal or radial offering the Driven Drivi...
PCB_CONSTRAINT * FindDimensionLengthConstraint(BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
Self FIXED_LENGTH constraint whose members are exactly aDimension START and END or nullptr the drivin...
bool DimensionCanDrive(BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
True when Driving mode may be offered for aDimension needs both endpoints bound via DimensionEndpoint...
DIM_VALUE_MODE
Mode a value bearing dimension value is in Driven mirrors measured geometry Driving forces geometry t...
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
@ DEGREES_T
Definition eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:412
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:416
static constexpr EDA_ANGLE FULL_CIRCLE
Definition eda_angle.h:409
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
static constexpr EDA_ANGLE ANGLE_135
Definition eda_angle.h:414
#define PCB_EDIT_FRAME_NAME
EDA_UNITS
Definition eda_units.h:44
a few functions useful in geometry calculations.
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:177
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:180
@ LAYER_CONSTRAINT_SHADOW
Shadow layer for items bound to a constraint.
Definition layer_ids.h:320
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Dwgs_User
Definition layer_ids.h:103
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:41
FLIP_DIRECTION
Definition mirror.h:23
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:25
KICOMMON_API wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Return the string from aValue according to aUnits (inch, mm ...) for display.
KICOMMON_API double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
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.
KICOMMON_API wxString GetText(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
bool ShapeHitTest(const SHAPE_LINE_CHAIN &aHitter, const SHAPE &aHittee, bool aHitteeContained)
Perform a shape-to-shape hit test.
KICOMMON_API wxString EllipsizeMenuText(const wxString &aString)
Ellipsize text (at the end) to be no more than 36 characters.
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, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
#define _HKI(x)
Definition page_info.cpp:40
static const int INWARD_ARROW_LENGTH_TO_HEAD_RATIO
static const EDA_ANGLE s_arrowAngle(27.5, DEGREES_T)
static struct DIMENSION_DESC _DIMENSION_DESC
static OPT_VECTOR2I segPolyIntersection(const SHAPE_POLY_SET &aPoly, const SEG &aSeg, bool aStart=true)
Find the intersection between a given segment and polygon outline.
static OPT_VECTOR2I segCircleIntersection(CIRCLE &aCircle, SEG &aSeg, bool aStart=true)
static void CollectKnockedOutSegments(const SHAPE_POLY_SET &aPoly, const SEG &aSeg, std::vector< std::shared_ptr< SHAPE > > &aSegmentsAfterKnockout)
Knockout a polygon from a segment.
DIM_TEXT_POSITION
Where to place the text on a dimension.
@ OUTSIDE
Text appears outside the dimension line (default)
@ INLINE
Text appears in line with the dimension line.
DIM_UNITS_FORMAT
How to display the units in a dimension's text.
DIM_UNITS_MODE
Used for storing the units selection in the file because EDA_UNITS alone doesn't cut it.
DIM_ARROW_DIRECTION
Used for dimension's arrow.
DIM_TEXT_BORDER
Frame to show around dimension text.
DIM_PRECISION
#define TYPE_HASH(x)
Definition property.h:74
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:828
@ PT_DEGREE
Angle expressed in degrees.
Definition property.h:66
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:35
VECTOR2I center
int radius
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:99
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:96
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:97
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:95
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:98
constexpr int sign(T val)
Definition util.h:141
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682